# HG changeset patch # User Mark Wielaard # Date 1212098400 -7200 # Node ID a6a6e9c3d502f8e77fbf41959a22067b1b367927 # Parent 66af07c1f52a02bc96f6df89c040bcb8bc56012f Import b10 diff -r 66af07c1f52a -r a6a6e9c3d502 README-builds.html --- a/README-builds.html Fri Apr 11 00:00:00 2008 +0200 +++ b/README-builds.html Fri May 30 00:00:00 2008 +0200 @@ -1,1490 +1,1658 @@ - -OpenJDK Build README - - -
- -
-

OpenJDK Build README

-
- - -
- -

Introduction

- -
-

- This README file contains build instructions for the - OpenJDK. - Building the source code for the - OpenJDK - requires - a certain degree of technical expertise. -

- - -
- -

Contents

- -
- -
- - -
- -

Minimum Build Environments

- -
-

- This file often describes specific requirements for what we call the - "minimum build environments" (MBE) for the JDK. - Building with the MBE will generate the most compatible - bits that install on, and run correctly on, the most variations - of the same base OS and hardware architecture. - These usually represent what is often called the - least common denominator platforms. - It is understood that most developers will NOT be using these - specific platforms, and in fact creating these specific platforms - may be difficult due to the age of some of this software. -

- -

- The minimum OS and C/C++ compiler versions needed for building the - OpenJDK: -

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + OpenJDK 6 Build README + + + +
Base OS and ArchitectureOSCompiler
Linux X86 (32bit)Red Hat Enterprise Linux 4 gcc 4
Linux X64 (64bit)Red Hat Enterprise Linux 4 gcc 4
Solaris SPARC (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris SPARCV9 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X86 (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X64 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Windows X86 (32bit)Windows XPMicrosoft Visual Studio .NET 2003 Professional
Windows X64 (64bit)Windows Server 2003 - Enterprise x64 EditionMicrosoft Platform SDK - April 2005
+ + + + + +
+ + OpenJDK + +
+ +

OpenJDK 6 Build README

+
-
-
- - -
- -

Specific Developer Build Environments

- -
-

- We won't be listing all the possible environments, but - we will try to provide what information we have available to us. -

- -

Fedora

- -
- TBD -
- -

Debian

- -
- TBD -
- -

Ubuntu

- -
-

- In addition to needing the Bootstrap JDK and the Binary Plugs, - when building on Ubuntu you will need to - make sure certain packages are installed. - In particular, certain X11 packages, make, m4, gawk, gcc 4, - binutils, cups, freetype - and alsa. - -

Ubuntu 6.06

- -

- The following list of packages for Ubuntu 6.06 is a working set that - does appear to work. - -

- Note that it's quite possible that some of these - packages are not required, so anyone discovering that some of the - packages listed below are NOT required, - please let the - OpenJDK - team know. -

- All the packages below can be installed with the - Synaptic Package manager provided with the base Ubuntu 6.06 release. - -

-
    -
  • binutils (2.16.1cvs20060117-1ubuntu2.1)
  • -
  • cpp (4:4.0.3-1)
  • -
  • cpp-4.0 (4.0.3-1ubuntu5)
  • -
  • libfreetype6-dev
  • -
  • g++ (4:4.0.3-1)
  • -
  • g++-4.0 (4.0.3-1ubuntu5)
  • -
  • gawk (1:3.1.5-2build1)
  • -
  • gcc (4:4.0.3-1)
  • -
  • gcc-4.0 (4.0.3-1ubuntu5)
  • -
  • libasound2-dev (1.0.10-2ubuntu4)
  • -
  • libc6 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libc6-dev (2.3.6-0ubuntu20.4)
  • -
  • libc6-i686 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libcupsys2-dev (1.2.2-0ubuntu0.6.06)
  • -
  • libgcrypt11-dev (1.2.2-1)
  • -
  • libgnutls-dev (1.2.9-2ubuntu1.1)
  • -
  • libgnutls12 (1.2.9-2ubuntu1) to 1.2.9-2ubuntu1.1
  • -
  • libgpg-error-dev (1.1-4)
  • -
  • libice-dev (2:1.0.0-0ubuntu2)
  • -
  • liblockfile1 (1.06.1)
  • -
  • libopencdk8-dev (0.5.7-2)
  • -
  • libpopt-dev (1.7-5)
  • -
  • libsm-dev (2:1.0.0-0ubuntu2)
  • -
  • libstdc++6-4.0-dev (4.0.3-1ubuntu5)
  • -
  • libtasn1-2-dev (0.2.17-1ubuntu1)
  • -
  • libx11-dev (2:1.0.0-0ubuntu9)
  • -
  • libxau-dev (1:1.0.0-0ubuntu4)
  • -
  • libxaw-headers (2:1.0.1-0ubuntu3)
  • -
  • libxaw7-dev (2:1.0.1-0ubuntu3)
  • -
  • libxdmcp-dev (1:1.0.0-0ubuntu2)
  • -
  • libxext-dev (2:1.0.0-0ubuntu4)
  • -
  • libxi-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-headers (2:1.0.0-0ubuntu3)
  • -
  • libxmuu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxp-dev (6.8.2-11ubuntu2)
  • -
  • libxpm-dev (1:3.5.4.2-0ubuntu3)
  • -
  • libxrandr-dev (1:1.1.0.2-0ubuntu4)
  • -
  • libxt-dev (1:1.0.0-0ubuntu3)
  • -
  • libxtrap-dev (2:1.0.0-0ubuntu2)
  • -
  • libxtst-dev (2:1.0.1-0ubuntu2)
  • -
  • libxv-dev (2:1.0.1-0ubuntu3)
  • -
  • linux-kernel-headers (2.6.11.2-0ubuntu18)
  • -
  • m4 (1.4.4-1)
  • -
  • make (3.80+3.81.b4-1)
  • -
  • ssl-cert (1.0.13)
  • -
  • x-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-core-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-input-dev (1.3.2-0ubuntu2)
  • -
  • x11proto-kb-dev (1.0.2-0ubuntu2)
  • -
  • x11proto-randr-dev (1.1.2-0ubuntu2)
  • -
  • x11proto-record-dev (1.13.2-0ubuntu2)
  • -
  • x11proto-trap-dev (3.4.3-0ubuntu2)
  • -
  • x11proto-video-dev (2.2.2-0ubuntu2)
  • -
  • x11proto-xext-dev (7.0.2-0ubuntu2)
  • -
  • xlibs-dev (7.0.0-0ubuntu45)
  • -
  • zlib1g-dev (1:1.2.3-6ubuntu4)
  • -
-
- -

Ubuntu 7.04

- -

- Using the Synaptic Package Manager, download the following - packages (double indented packages are automatically aquired - due to package dependencies): - -

- -
-
- - -
- -

Source Directory Structure

- -
-

- The source code for the OpenJDK is delivered in a set of - directories: - hotspot, - langtools, - corba, - jaxws, - jaxp, - and - jdk. - The hotspot directory contains the source code and make - files for building the OpenJDK Hotspot Virtual Machine. - The langtools directory contains the source code and make - files for building the OpenJDK javac and language tools. - The corba directory contains the source code and make - files for building the OpenJDK Corba files. - The jaxws directory contains the source code and make - files for building the OpenJDK JAXWS files. - The jaxp directory contains the source code and make - files for building the OpenJDK JAXP files. - The jdk directory contains the source code and make files for - building the OpenJDK runtime libraries and misc files. - The top level Makefile (or control/Makefile) - is used to build the entire OpenJDK. -

- - -
- -

Build Information

- -
-

- Building the - OpenJDK - is done with a gmake - command line and various - environment or make variable settings that direct the make rules - to where various components have been installed. - Where possible the makefiles will attempt to located the various - components in the default locations or any component specific - variable settings. - When the normal defaults fail or components cannot be found, - the various - ALT_* variables (alternates) - can be used to help the makefiles locate components. -

- Refer to the bash/sh/ksh setup file - jdk/make/jdk_generic_profile.sh - if you need help in setting up your environment variables. - A build could be as simple as: -

-

+        
+ +
+

Minimum Build Environments

+
+ This file often describes specific requirements for what we call the + "minimum build environments" (MBE) for the JDK. + Building with the MBE will generate the most compatible + bits that install on, and run correctly on, the most variations + of the same base OS and hardware architecture. + These usually represent what is often called the + least common denominator platforms. + It is understood that most developers will NOT be using these + specific platforms, and in fact creating these specific platforms + may be difficult due to the age of some of this software. +

+ The minimum OS and C/C++ compiler versions needed for building the + OpenJDK: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Base OS and ArchitectureOSCompiler
Linux X86 (32bit)Red Hat Enterprise Linux 4 gcc 4
Linux X64 (64bit)Red Hat Enterprise Linux 4 gcc 4
Solaris SPARC (32bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris SPARCV9 (64bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris X86 (32bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris X64 (64bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Windows X86 (32bit)Windows XPMicrosoft Visual Studio .NET 2003 Professional
Windows X64 (64bit)Windows Server 2003 - Enterprise x64 EditionMicrosoft Platform SDK - April 2005
+

+ +
+

Specific Developer Build Environments

+
+ We won't be listing all the possible environments, but + we will try to provide what information we have available to us. +
+ +

Fedora

+
+ TBD +
+ +

Debian

+
+ TBD +
+ +

Ubuntu

+
+ In addition to needing the Bootstrap JDK and the Binary Plugs, + when building on Ubuntu you will need to + make sure certain packages are installed. + In particular, certain X11 packages, make, m4, gawk, gcc 4, + binutils, cups, freetype + and alsa. + +

Ubuntu 6.06

+

+ The following list of packages for Ubuntu 6.06 is a working set that + does appear to work. +

+ Note that it's quite possible that some of these + packages are not required, so anyone discovering that some of the + packages listed below are NOT required, + please let the + OpenJDK + team know. +

+ All the packages below can be installed with the + Synaptic Package manager provided with the base Ubuntu 6.06 release. +

+
    +
  • binutils (2.16.1cvs20060117-1ubuntu2.1)
  • +
  • cpp (4:4.0.3-1)
  • +
  • cpp-4.0 (4.0.3-1ubuntu5)
  • +
  • libfreetype6-dev
  • +
  • g++ (4:4.0.3-1)
  • +
  • g++-4.0 (4.0.3-1ubuntu5)
  • +
  • gawk (1:3.1.5-2build1)
  • +
  • gcc (4:4.0.3-1)
  • +
  • gcc-4.0 (4.0.3-1ubuntu5)
  • +
  • libasound2-dev (1.0.10-2ubuntu4)
  • +
  • libc6 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • +
  • libc6-dev (2.3.6-0ubuntu20.4)
  • +
  • libc6-i686 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • +
  • libcupsys2-dev (1.2.2-0ubuntu0.6.06)
  • +
  • libgcrypt11-dev (1.2.2-1)
  • +
  • libgnutls-dev (1.2.9-2ubuntu1.1)
  • +
  • libgnutls12 (1.2.9-2ubuntu1) to 1.2.9-2ubuntu1.1
  • +
  • libgpg-error-dev (1.1-4)
  • +
  • libice-dev (2:1.0.0-0ubuntu2)
  • +
  • liblockfile1 (1.06.1)
  • +
  • libopencdk8-dev (0.5.7-2)
  • +
  • libpopt-dev (1.7-5)
  • +
  • libsm-dev (2:1.0.0-0ubuntu2)
  • +
  • libstdc++6-4.0-dev (4.0.3-1ubuntu5)
  • +
  • libtasn1-2-dev (0.2.17-1ubuntu1)
  • +
  • libx11-dev (2:1.0.0-0ubuntu9)
  • +
  • libxau-dev (1:1.0.0-0ubuntu4)
  • +
  • libxaw-headers (2:1.0.1-0ubuntu3)
  • +
  • libxaw7-dev (2:1.0.1-0ubuntu3)
  • +
  • libxdmcp-dev (1:1.0.0-0ubuntu2)
  • +
  • libxext-dev (2:1.0.0-0ubuntu4)
  • +
  • libxi-dev (2:1.0.0-0ubuntu3)
  • +
  • libxmu-dev (2:1.0.0-0ubuntu3)
  • +
  • libxmu-headers (2:1.0.0-0ubuntu3)
  • +
  • libxmuu-dev (2:1.0.0-0ubuntu3)
  • +
  • libxp-dev (6.8.2-11ubuntu2)
  • +
  • libxpm-dev (1:3.5.4.2-0ubuntu3)
  • +
  • libxrandr-dev (1:1.1.0.2-0ubuntu4)
  • +
  • libxt-dev (1:1.0.0-0ubuntu3)
  • +
  • libxtrap-dev (2:1.0.0-0ubuntu2)
  • +
  • libxtst-dev (2:1.0.1-0ubuntu2)
  • +
  • libxv-dev (2:1.0.1-0ubuntu3)
  • +
  • linux-kernel-headers (2.6.11.2-0ubuntu18)
  • +
  • m4 (1.4.4-1)
  • +
  • make (3.80+3.81.b4-1)
  • +
  • ssl-cert (1.0.13)
  • +
  • x-dev (7.0.4-0ubuntu2)
  • +
  • x11proto-core-dev (7.0.4-0ubuntu2)
  • +
  • x11proto-input-dev (1.3.2-0ubuntu2)
  • +
  • x11proto-kb-dev (1.0.2-0ubuntu2)
  • +
  • x11proto-randr-dev (1.1.2-0ubuntu2)
  • +
  • x11proto-record-dev (1.13.2-0ubuntu2)
  • +
  • x11proto-trap-dev (3.4.3-0ubuntu2)
  • +
  • x11proto-video-dev (2.2.2-0ubuntu2)
  • +
  • x11proto-xext-dev (7.0.2-0ubuntu2)
  • +
  • xlibs-dev (7.0.0-0ubuntu45)
  • +
  • zlib1g-dev (1:1.2.3-6ubuntu4)
  • +
+
+ +

Ubuntu 7.04

+

+ Using the Synaptic Package Manager, download the following + packages (double indented packages are automatically aquired + due to package dependencies): +

+
    +
  • build-essential
  • +
      +
    • dpkg-dev
    • +
    • g++
    • +
    • g++-4.1
    • +
    • libc6-dev
    • +
    • libstdc++6.4.1-dev
    • +
    • linux-libc-dev
    • +
    +
  • gawk
  • +
  • m4
  • +
  • libasound2-dev
  • + +
  • libmotif3-dev
  • +
      +
    • libmotif3
    • +
    +
  • libcupsys2-dev
  • +
      +
    • libgcrypt11-dev
    • +
    • lgnutls-dev
    • +
    • libgpg-error-dev
    • +
    • liblzo-dev
    • +
    • libopencdk8-dev
    • +
    • libpopt-dev
    • +
    • libtasn1-3-dev
    • +
    • zlib1g-dev
    • +
    +
  • sun-java6-jdk
  • +
      +
    • java-common
    • +
    • libltdl3
    • +
    • odbcinst1debian1
    • +
    • sun-java6-bin
    • +
    • sun-java6-jre
    • +
    • unixodbc
    • +
    +
  • xlibs-dev
  • +
      +
    • (many)
    • +
    +
  • x11proto-print-dev
  • +
  • libxaw7-dev
  • +
      +
    • libxaw-headers
    • +
    +
  • libxp-dev
  • +
  • libfreetype6-dev
  • +
+
+
+ +
+

Source Directory Structure

+
+

+ The source code for the OpenJDK is delivered in a set of + directories: + hotspot, + langtools, + corba, + jaxws, + jaxp, + and + jdk. + The hotspot directory contains the source code and make + files for building the OpenJDK Hotspot Virtual Machine. + The langtools directory contains the source code and make + files for building the OpenJDK javac and language tools. + The corba directory contains the source code and make + files for building the OpenJDK Corba files. + The jaxws directory contains the source code and make + files for building the OpenJDK JAXWS files. + The jaxp directory contains the source code and make + files for building the OpenJDK JAXP files. + The jdk directory contains the source code and make files for + building the OpenJDK runtime libraries and misc files. + The top level Makefile + is used to build the entire OpenJDK. +

+ +
+

Build Information

+
+ Building the OpenJDK + is done with a gmake + command line and various + environment or make variable settings that direct the make rules + to where various components have been installed. + Where possible the makefiles will attempt to located the various + components in the default locations or any component specific + variable settings. + When the normal defaults fail or components cannot be found, + the various + ALT_* variables (alternates) + can be used to help the makefiles locate components. +

+ Refer to the bash/sh/ksh setup file + jdk/make/jdk_generic_profile.sh + if you need help in setting up your environment variables. + A build could be as simple as: +

+

                 bash
                 . jdk/make/jdk_generic_profile.sh
                 gmake sanity && gmake
-        
-
-

- Of course ksh or sh would work too. - But some customization will probably be necessary. - The sanity rule will make some basic checks on build - dependencies and generate appropriate warning messages - regarding missing, out of date, or newer than expected components - found on your system. -

- - -
- -

GNU make (gmake)

- -
-

- The Makefiles in the - OpenJDK - are only valid when used with the - GNU version of the utility command make - (gmake). - A few notes about using GNU make: -

    -
  • - In general, you need GNU make version 3.78.1 or newer. -
  • -
  • - Place the location of the GNU make binary in the PATH. -
  • -
  • - Linux: - The /usr/bin/make command should work fine for you. -
  • -
  • - Solaris: - Do NOT use /usr/bin/make on Solaris. - If your Solaris system has the software - from the Solaris Companion CD installed, - you should use gmake - which will be located in either the /opt/sfw/bin or - /usr/sfw/bin directory. -
  • -
  • + +
+

+ Of course ksh or sh would work too. + But some customization will probably be necessary. + The sanity rule will make some basic checks on build + dependencies and generate appropriate warning messages + regarding missing, out of date, or newer than expected components + found on your system. +

+ +
+

GNU make (gmake)

+
+ The Makefiles in the OpenJDK are only valid when used with the + GNU version of the utility command make + (gmake). + A few notes about using GNU make: + +

+ Information on GNU make, and access to ftp download sites, are + available on the + + GNU make web site + . + The latest source to GNU make is available at + + ftp.gnu.org/pub/gnu/make/. +

+ +
+

Basic Linux System Setup

+
+ i586 only: + The minimum recommended hardware for building the Linux version + is a Pentium class processor or better, at least 256 MB of RAM, and + approximately 1.5 GB of free disk space. +

+ X64 only: + The minimum recommended hardware for building the Linux + version is an AMD Opteron class processor, at least 512 MB of RAM, and + approximately 4 GB of free disk space. +

+ The build will use the tools contained in + /bin and + /usr/bin + of a standard installation of the Linux operating environment. + You should ensure that these directories are in your + PATH. +

+ Note that some Linux systems have a habit of pre-populating + your environment variables for you, for example JAVA_HOME + might get pre-defined for you to refer to the JDK installed on + your Linux system. + You will need to unset JAVA_HOME. + It's a good idea to run env and verify the + environment variables you are getting from the default system + settings make sense for building the + OpenJDK. +

+ +

Basic Linux Check List

+
+
    +
  1. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  2. +
  3. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH. +
  4. +
  5. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  6. +
  7. + Install or upgrade the FreeType development + package. +
  8. +
  9. + + Install the + Motif header files, set + ALT_MOTIF_DIR. +
  10. +
+
+ +
+

Basic Solaris System Setup

+
+ The minimum recommended hardware for building the + Solaris SPARC version is an UltraSPARC with 512 MB of RAM. + For building + the Solaris x86 version, a Pentium class processor or better and at + least 512 MB of RAM are recommended. + Approximately 1.4 GB of free disk + space is needed for a 32-bit build. +

+ If you are building the 64bit version, you should + run the command "isainfo -v" to verify that you have a + 64-bit installation, it should say sparcv9 or + amd64. + An additional 7 GB of free disk space is needed + for a 64-bit build. +

+ The build uses the tools contained in /usr/ccs/bin + and /usr/bin of a standard developer or full installation of + the Solaris operating environment. +

+ Solaris patches specific to the JDK can be downloaded from the + + SunSolve JDK Solaris patches download page. + You should ensure that the latest patch cluster for + your version of the Solaris operating environment has also + been installed. +

+ +

Basic Solaris Check List

+
+
    +
  1. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  2. +
  3. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH. +
  4. +
  5. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  6. +
  7. + Install the + Sun Studio Compilers, set + ALT_COMPILER_PATH. +
  8. +
  9. + Install the + CUPS Include files, set + ALT_CUPS_HEADERS_PATH. +
  10. +
+
+ +
+

Basic Windows System Setup

+
+ i586 only: + The minimum recommended hardware for building the 32bit or X86 + Windows version is an Pentium class processor or better, at least + 512 MB of RAM, and approximately 600 MB of free disk space. + + NOTE: The Windows 2000 build machines need to use the + file system NTFS. + Build machines formatted to FAT32 will not work + because FAT32 doesn't support case-sensitivity in file names. + +

+ X64 only: + The minimum recommended hardware for building + the Windows X64 version is an AMD Opteron class processor, at least 1 + GB of RAM, and approximately 10 GB of free disk space. +

+ +

Windows Paths

+
Windows: - Make sure you start your build inside a bash/sh/ksh shell. -
- WARNING: Watch out for make version 3.81, it may - not work due to a lack of support for drive letter paths - like C:/. Use a 3.80 version, or find a newer - version that has this problem fixed. - - -

- Information on GNU make, and access to ftp download sites, are - available on the - - GNU make web site - . - The latest source to GNU make is available at - ftp.gnu.org/pub/gnu/make/. -

- - -
- -

Basic Linux System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the Linux version - is a Pentium class processor or better, at least 256 MB of RAM, and - approximately 1.5 GB of free disk space. -

- X64 only: - The minimum recommended hardware for building the Linux - version is an AMD Opteron class processor, at least 512 MB of RAM, and - approximately 4 GB of free disk space. -

- The build will use the tools contained in - /bin and - /usr/bin - of a standard installation of the Linux operating environment. - You should ensure that these directories are in your - PATH. -

- Note that some Linux systems have a habit of pre-populating - your environment variables for you, for example JAVA_HOME - might get pre-defined for you to refer to the JDK installed on - your Linux system. - You will need to unset JAVA_HOME. - It's a good idea to run env and verify the - environment variables you are getting from the default system - settings make sense for building the - OpenJDK. -

- - - -

Basic Linux Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install the - Motif header files, set - ALT_MOTIF_DIR.. -
  6. -
  7. - Install or upgrade the FreeType development - package. -
  8. -
-
- - -
- -

Basic Solaris System Setup

- -
-

- The minimum recommended hardware for building the - Solaris SPARC version is an UltraSPARC with 512 MB of RAM. - For building - the Solaris x86 version, a Pentium class processor or better and at - least 128 MB of RAM are recommended. - Approximately 1.4 GB of free disk - space is needed for a 32-bit build. -

- If you are building the 64bit version, you should - run the command "isainfo -v" to verify that you have a - 64-bit installation. - An additional 7 GB of free disk space is needed - for a 64-bit build. -

- The build uses the tools contained in /usr/ccs/bin - and /usr/bin of a standard developer or full installation of - the Solaris operating environment. -

- - - -

Basic Solaris Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install the - Sun Studio Compilers, set - ALT_COMPILER_PATH. -
  6. -
  7. - Install the - CUPS Include files, set - ALT_CUPS_HEADERS_PATH. -
  8. -
-
- - -
- -

Basic Windows System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the 32bit or X86 - Windows version is an Pentium class processor or better, at least - 512 MB of RAM, and approximately 600 MB of free disk space. - - NOTE: The Windows 2000 build machines need to use the - file system NTFS. - Build machines formatted to FAT32 will not work - because FAT32 doesn't support case-sensitivity in file names. - -

- X64 only: - The minimum recommended hardware for building - the Windows X64 version is an AMD Opteron class processor, at least 1 - GB of RAM, and approximately 10 GB of free disk space. -

- - - -

Windows Paths

- -
-

- Windows: - Note that GNU make is a historic utility and is based very - heavily on shell scripting, so it does not tolerate the Windows habit - of having spaces in pathnames or the use of the \characters in pathnames. - Luckily on most Windows systems, you can use /instead of \, and - there is always a 'short' pathname without spaces for any path that - contains spaces. - Unfortunately, this short pathname can be somewhat dynamic and the - formula is difficult to explain. - You can use cygpath utility to map pathnames with spaces - or the \character into the C:/ style of pathname - (called 'mixed'), e.g. - cygpath -s -m "path". -

- The makefiles will try to translate any pathnames supplied - to it into the C:/ style automatically. -

- Note that use of CYGWIN creates a unique problem with regards to - setting PATH. Normally on Windows - the PATH variable contains directories - separated with the ";" character (Solaris and Linux uses ":"). - With CYGWIN, it uses ":", but that means that paths like "C:/path" - cannot be placed in the CYGWIN version of PATH and - instead CYGWIN uses something like /cygdrive/c/path - which CYGWIN understands, but only CYGWIN understands. - So be careful with paths on Windows. -

- - - -

Basic Windows Check List

- -
-
    -
  1. - Install the - CYGWIN product. -
  2. -
  3. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  4. -
  5. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH.. -
  6. -
  7. - Install the - Microsoft Visual Studio .NET 2003 Professional or the - Microsoft Platform SDK. -
  8. -
  9. - Setup all environment variables for compilers - (see compilers). -
  10. -
  11. - Install - Microsoft DirectX SDK. -
  12. -
-
- - -
- -

Build Dependencies

- -
-

- Depending on the platform, the - OpenJDK - build process has some basic - dependencies on components not part of the - OpenJDK - sources. - Some of these are specific to a platform, some even specific to - an architecture. - Each dependency will have a set of ALT variables that can be set - to tell the makefiles where to locate the component. - In most cases setting these ALT variables may not be necessary - and the makefiles will find defaults on the system in standard - install locations or through component specific variables. - -

Bootstrap JDK

- -
-

- All - OpenJDK - builds require access to the previously released - JDK 6, this is often called a bootstrap JDK. - The JDK 6 binaries can be downloaded from Sun's - JDK 6 download site. - For build performance reasons - is very important that this bootstrap JDK be made available on the - local disk of the machine doing the build. - You should always set - ALT_BOOTDIR - to point to the location of - the bootstrap JDK installation, this is the directory pathname - that contains a bin, lib, and include - It's also a good idea to also place its bin directory - in the PATH environment variable, although it's - not required. -

- Solaris: - Some pre-installed JDK images may be available to you in the - directory /usr/jdk/instances. - If you don't set - ALT_BOOTDIR - the makefiles will look in that location for a JDK it can use. -

- -

Binary Plugs

- -
-

- Not all of the source code that makes up the JDK is available - under an open-source license. - In order to build an OpenJDK binary from source code, - you must first download and install the appropriate - binary plug bundles from the OpenJDK, go to the - OpenJDK site and select - the "Bundles(6)" link. - During the OpenJDK build process these "binary plugs" - for the encumbered components will be copied into your - resulting OpenJDK binary build image. - These binary plug files are only for the purpose of - building an OpenJDK binary. - Make sure you set - ALT_BINARY_PLUGS_PATH - to the root of this installation. -

- -

Certificate Authority File (cacert)

- -
-

- See - www.wikipedia.org/wiki/CAcert - for a better understanding of the Certificate Authority (CA). - A certificates file named "cacerts" - represents a system-wide keystore with CA certificates. - In JDK and JRE - binary bundles, the "cacerts" file contains root CA certificates from - several public CAs (e.g., VeriSign, Thawte, and Baltimore). - The source contain a cacerts file - without CA root certificates. - Formal JDK builders will need to secure - permission from each public CA and include the certificates into their - own custom cacerts file. - Failure to provide a populated cacerts file - will result in verification errors of a certificate chain during runtime. - The variable - ALT_CACERTS_FILE - can be used to override the default location of the - cacerts file that will get placed in your build. - By default an empty cacerts file is provided and that should be - fine for most JDK developers. -

- -

Compilers

- -
- - - Linux gcc/binutils - - + Note that GNU make is a historic utility and is based very + heavily on shell scripting, so it does not tolerate the Windows habit + of having spaces in pathnames or the use of the \characters in pathnames. + Luckily on most Windows systems, you can use /instead of \, and + there is always a 'short' pathname without spaces for any path that + contains spaces. + Unfortunately, this short pathname can be somewhat dynamic and the + formula is difficult to explain. + You can use cygpath utility to map pathnames with spaces + or the \character into the C:/ style of pathname + (called 'mixed'), e.g. + cygpath -s -m "path". +

+ The makefiles will try to translate any pathnames supplied + to it into the C:/ style automatically. +

+ Note that use of CYGWIN creates a unique problem with regards to + setting PATH. Normally on Windows + the PATH variable contains directories + separated with the ";" character (Solaris and Linux uses ":"). + With CYGWIN, it uses ":", but that means that paths like "C:/path" + cannot be placed in the CYGWIN version of PATH and + instead CYGWIN uses something like /cygdrive/c/path + which CYGWIN understands, but only CYGWIN understands. + So be careful with paths on Windows. +

+ +

Basic Windows Check List

+
+
    +
  1. + Install the + CYGWIN product. +
  2. +
  3. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  4. +
  5. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH.. +
  6. +
  7. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  8. +
  9. + Install the + Microsoft Visual Studio .NET 2003 Professional or the + Microsoft Platform SDK. +
  10. +
  11. + Setup all environment variables for compilers + (see compilers). +
  12. +
  13. + Install + Microsoft DirectX SDK. +
  14. +
+
+ +
+

Build Dependencies

-

- The GNU gcc compiler version should be 3.2.2 or newer. - The binutils package should be 2.11.93.0.2-11 or newer. - The compiler used should be the default compiler installed - in /usr/bin. -

- - Solaris: Sun Studio - -
-

- At a minimum, the - - Sun Studio 11 Compilers - (containing version 5.8 of the C and C++ compilers) is required, - with patches from the - - SunSolve web site. -

- Set - ALT_COMPILER_PATH - to point to the location of - the compiler binaries, and place this location in the PATH. -

- The Sun Studio Express compilers at: - - Sun Studio Express Download site - are also an option, although these compilers have not - been extensively used yet. -

- - - Windows i586: Microsoft Visual Studio .NET 2003 Professional - - -
-

- The 32-bit - OpenJDK - Windows build - requires Microsoft Visual Studio .NET 2003 (VS2003) Professional - Edition compiler. - The compiler and other tools are expected to reside - in the location defined by the variable VS71COMNTOOLS which - is set by the Microsoft Visual Studio .NET installer. -

- Once the compiler is installed, - it is recommended that you run VCVARS32.BAT - to set the compiler environment variables - MSVCDIR, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- The Microsoft Visual Studio .NET 2005 (VS2005) compiler - will not work at this time due to the new runtime dll - and the manifest requirements. -

- - - Windows X64: Microsoft Platform SDK April 2005 - - -
-

- On X64, - the Microsoft Platform Software - Development Kit (SDK), April 2005 Edition compiler, is required for - building the - OpenJDK - because it contains the C/C++ compiler. - You will need to minimally install the Core SDK and - the MDAC SDK features of this compiler. -

- Once the Platform SDK is installed, - it is recommended that you run SetEnv.Cmd /X64 - to set the compiler environment variables - MSSDK, - MSTOOLS, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- Note that this compiler may say it's version is a - Microsoft Visual Studio .NET 2005 (VS2005), but be careful, - it will not match the official VS2005 product. - This Platform SDK compiler is only used on X64 builds. + Depending on the platform, the OpenJDK build process has some basic + dependencies on components not part of the OpenJDK sources. + Some of these are specific to a platform, some even specific to + an architecture. + Each dependency will have a set of ALT variables that can be set + to tell the makefiles where to locate the component. + In most cases setting these ALT variables may not be necessary + and the makefiles will find defaults on the system in standard + install locations or through component specific variables. + +

Bootstrap JDK

+
+ All OpenJDK builds require access to the previously released + JDK 6, this is often called a bootstrap JDK. +
+ + Normally the "boot" JDK is the previously released version + of the JDK, so it's unusual for a JDK 6 build like this to + require a JDK 6 "boot". + Unfortunately, it is currently required due to some JDK 6 + dependencies in some of the sources. +
+ The JDK 6 binaries can be downloaded from Sun's + JDK 6 download site. + For build performance reasons + is very important that this bootstrap JDK be made available on the + local disk of the machine doing the build. + You should always set + ALT_BOOTDIR + to point to the location of + the bootstrap JDK installation, this is the directory pathname + that contains a bin, lib, and include + It's also a good idea to also place its bin directory + in the PATH environment variable, although it's + not required. +

+ Solaris: + Some pre-installed JDK images may be available to you in the + directory /usr/jdk/instances. + If you don't set + ALT_BOOTDIR + the makefiles will look in that location for a JDK it can use. +

+ +

Binary Plugs

+
+ Not all of the source code that makes up the JDK is available + under an open-source license. + This is a temporary situation and these binary plugs will be + replaced with fully open source replacements as soon as possible. + So currently, in order to build a complete OpenJDK image, + you must first download and install the appropriate + binary plug bundles for the OpenJDK, go to the + OpenJDK site and select + the + + + "Bundles(6)" + + link and download the binaryplugs for + your particular platform. + The file downloaded is a jar file that must be extracted by running + the jar file with: +
+ +
+            java -jar jdk-6-ea-plug-bnn-os-arch-dd_month_year.jar
+                    
+
+ A prompt will be issued for acceptance of these binary plug files. + During the OpenJDK build process these "binary plugs" + for the encumbered components will be copied into your + resulting OpenJDK binary build image. + These binary plug files are only for the purpose of + building an OpenJDK binary. + Make sure you set + ALT_BINARY_PLUGS_PATH + to the root of this installation. +
+ +

Optional Import JDK

+
+ The ALT_JDK_IMPORT_PATH + setting is only needed if you are not building the entire + JDK. For example, if you have built the entire JDK once, and + wanted to avoid repeatedly building the Hotspot VM, you could + set this to the location of the previous JDK install image + and the build will copy the needed files from this import area. +
+ +

Certificate Authority File (cacert)

+
+ See + http://en.wikipedia.org/wiki/Certificate_Authority + for a better understanding of the Certificate Authority (CA). + A certificates file named "cacerts" + represents a system-wide keystore with CA certificates. + In JDK and JRE + binary bundles, the "cacerts" file contains root CA certificates from + several public CAs (e.g., VeriSign, Thawte, and Baltimore). + The source contain a cacerts file + without CA root certificates. + Formal JDK builders will need to secure + permission from each public CA and include the certificates into their + own custom cacerts file. + Failure to provide a populated cacerts file + will result in verification errors of a certificate chain during runtime. + The variable + ALT_CACERTS_FILE + can be used to override the default location of the + cacerts file that will get placed in your build. + By default an empty cacerts file is provided and that should be + fine for most JDK developers. +
+ +

Compilers

+
+ Linux gcc/binutils +
+ The GNU gcc compiler version should be 3.2.2 or newer. + The binutils package should be 2.11.93.0.2-11 or newer. + The compiler used should be the default compiler installed + in /usr/bin. +

+ Older Linux systems may require a gcc and bunutils update. + The Redhat Enterprise Advanced Server 2.1 update 2 system + is one of these systems. + RedHat Linux users can obtain this binutils package from + Redhat web site. + You will need to remove the default compiler and binutils + packages and install the required packages + into the default location on the system. + However if you have a new video card driver, like + Geforce 4 it is best to use + the same compiler as the kernel was built with to + build the new video card driver module. + So you should build the modules before making this change. +

+ Solaris: Sun Studio +
+ At a minimum, the + + Sun Studio 11 Compilers + (containing version 5.8 of the C and C++ compilers) is required, + with patches from the + + SunSolve web site. +

+ Set + ALT_COMPILER_PATH + to point to the location of + the compiler binaries, and place this location in the PATH. +

+ The Sun Studio Express compilers at: + + Sun Studio Express Download site + are also an option, although these compilers have not + been extensively used yet. +

+ Windows i586: Microsoft Visual Studio .NET 2003 Professional +
+ The 32-bit OpenJDK Windows build + requires Microsoft Visual Studio .NET 2003 (VS2003) Professional + Edition compiler. + The compiler and other tools are expected to reside + in the location defined by the variable VS71COMNTOOLS which + is set by the Microsoft Visual Studio .NET installer. +

+ Once the compiler is installed, + it is recommended that you run VCVARS32.BAT + to set the compiler environment variables + MSVCDIR, + INCLUDE, + LIB, and + PATH + prior to building the + OpenJDK. + The above environment variables MUST be set. +

+ The Microsoft Visual Studio .NET 2005 (VS2005) compiler + will not work at this time due to the new runtime dll + and the manifest requirements. +

+ Windows X64: Microsoft Platform SDK April 2005 +
+ On X64, the Microsoft Platform Software + Development Kit (SDK), April 2005 Edition compiler, + is required for building the OpenJDK + because it contains the C/C++ compiler. + You will need to minimally install the Core SDK and + the MDAC SDK features of this compiler. +

+ Once the Platform SDK is installed, + it is recommended that you run SetEnv.Cmd /X64 + to set the compiler environment variables + MSSDK, + MSTOOLS, + INCLUDE, + LIB, and + PATH + prior to building the + OpenJDK. + The above environment variables MUST be set. +

+ Note that this compiler may say it's version is a + Microsoft Visual Studio .NET 2005 (VS2005), but be careful, + it will not match the official VS2005 product. + This Platform SDK compiler is only used on X64 builds. +

+
+ +

Zip and Unzip

+
+ Version 2.2 (November 3rd 1997) or newer of the zip utility + and version 5.12 or newer of the unzip utility is needed + to build the JDK. + With Solaris, Linux, and Windows CYGWIN, the zip and unzip + utilities installed on the system should be fine. + Information and the source code for + ZIP.EXE and UNZIP.EXE is available on the + info-zip web site. +
+ +

Common UNIX Printing System (CUPS) Headers (Solaris & Linux)

+
+ Solaris: + CUPS header files are required for building the + OpenJDK on Solaris. + The Solaris header files can be obtained by installing + the package SFWcups from the Solaris Software + Companion CD/DVD, these often will be installed into + /opt/sfw/cups. +

+ Linux: + CUPS header files are required for building the + OpenJDK on Linux. + The Linux header files are usually available from a "cups" + development package, it's recommended that you try and use + the package provided by the particular version of Linux that + you are using. +

+ The CUPS header files can always be downloaded from + www.cups.org. + The variable + ALT_CUPS_HEADERS_PATH + can be used to override the default location of the + CUPS Header files. +

+ +

Motif Headers (Solaris & Linux)

+
+ + Motif headers (not libraries) are required for building the + OpenJDK 6. +

+ Solaris: + Normally these files can be found on Solaris systems + at /usr/include/Xm, so on Solaris systems no further downloads + should be needed. +

+ Linux: + On Linux, your particular Linux distribution may provide a + "motif" development package you can install. If this package + installs the files into /usr/include/Xm, no further action should + be needed. + An acceptable version of these Motif header files are + available in the source bundle + + openmotif-2.1.30.5p1.tgz + from + www.openbsd.org. + You would need to install the package and set the environment variable + ALT_MOTIF_DIR + to refer to the top of this installation. +

+ +

FreeType 2

+
+ Version 2.3 or newer of FreeType is required for building the OpenJDK. + On Unix systems required files can be available as part of your + distribution (while you still may need to upgrade them). + Note that you need development version of package that + includes both FreeType library and header files. +

+ You can always download latest FreeType version from the + FreeType website. +

+ Makefiles will try to pick FreeType from /usr/lib and /usr/include. + In case it is installed elsewhere you will need to set environment + variables + ALT_FREETYPE_LIB_PATH + and + ALT_FREETYPE_HEADERS_PATH + to refer to place where library and header files are installed. +

+ +

Advanced Linux Sound Architecture (ALSA) (Linux only)

+
+ Linux only: + Version 0.9.1 or newer of the ALSA files are + required for building the OpenJDK on Linux. + These Linux files are usually available from an "alsa" + of "libasound" + development package, it's highly recommended that you try and use + the package provided by the particular version of Linux that + you are using. + The makefiles will check this emit a sanity error if it is + missing or the wrong version. +

+ In particular, older Linux systems will likely not have the + right version of ALSA installed, for example + Redhat AS 2.1 U2 and SuSE 8.1 do not include a sufficiently + recent ALSA distribution. + On rpm-based systems, you can see if ALSA is installed by + running this command: +

+                    rpm -qa | grep alsa
+                
+ Both alsa and alsa-devel packages are needed. +

+ If your distribution does not come with ALSA, and you can't + find ALSA packages built for your particular system, + you can try to install the pre-built ALSA rpm packages from + + www.freshrpms.net. + Note that installing a newer ALSA could + break sound output if an older version of ALSA was previously + installed on the system, but it will enable JDK compilation. +

+ Installation: execute as root
+ [i586]: rpm -Uv --force alsa-lib-devel-0.9.1-rh61.i386.rpm
+ [x64]: rpm -Uv --force alsa-lib-devel-0.9.8-amd64.x86_64.rpm
+ Uninstallation:
+ [i586]: rpm -ev alsa-lib-devel-0.9.1-rh61
+ [x64]:rpm -ev alsa-lib-devel-0.9.8-amd64
+ Make sure that you do not link to the static library + (libasound.a), + by verifying that the dynamic library (libasound.so) is + correctly installed in /usr/lib. +
+ As a last resort you can go to the + + Advanced Linux Sound Architecture Site and build it from + source. +
+ Download driver and library + source tarballs from + ALSA's homepage. + As root, execute the following + commands (you may need to adapt the version number): +
+                        
+                            $ tar xjf alsa-driver-0.9.1.tar.bz2
+                            $ cd alsa-driver-0.9.1
+                            $ ./configure
+                            $ make install
+                            $ cd ..
+                            $ tar xjf alsa-lib-0.9.1.tar.bz2
+                            $ cd alsa-lib-0.9.1
+                            $ ./configure
+                            $ make install
+                        
+                    
+ Should one of the above steps fail, refer to the documentation on + ALSA's home page. +
+ Note that this is a minimum install that enables + building the JDK platform. To actually use ALSA sound drivers, more + steps are necessary as outlined in the documentation on ALSA's homepage. +

+ ALSA can be uninstalled by executing make uninstall first in + the alsa-lib-0.9.1 directory and then in + alsa-driver-0.9.1. +

+ There are no ALT* variables to change the assumed locations of ALSA, + the makefiles will expect to find the ALSA include files and library at: + /usr/include/alsa and /usr/lib/libasound.so.
- -
- -

Common UNIX Printing System (CUPS) Headers (Solaris & Linux)

- -
-

- Solaris: - CUPS header files are required for building the - OpenJDK on Solaris. - The Solaris header files can be obtained by installing - the package SFWcups from the Solaris Software - Companion CD/DVD, these often will be installed into - /opt/sfw/cups. -

- Linux: - CUPS header files are required for building the - OpenJDK on Linux. - The Linux header files are usually available from a "cups" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. -

- The CUPS header files can always be downloaded from - www.cups.org. - The variable - ALT_CUPS_HEADERS_PATH - can be used to override the default location of the - CUPS Header files. -

-

Motif Headers (Solaris & Linux)

- -
-

- Motif headers (not libraries) are required for building the - OpenJDK. -

- Solaris: - Normally these files can be found on Solaris systems - at /usr/include/Xm, so on Solaris systems no further downloads - should be needed. -

- Linux: - On Linux, your particular Linux distribution may provide a - "motif" development package you can install. If this package - installs the files into /usr/include/Xm, no further action should - be needed. - An acceptable version of these Motif header files are - available in the source bundle - - openmotif-2.1.30.5p1.tgz - from - www.openbsd.org. - You would need to install the package and set the environment variable - ALT_MOTIF_DIR - to refer to the top of this installation. -

- -

FreeType 2

- -
-

- Version 2.3 or newer of FreeType is required for building the OpenJDK. - On Unix systems required files can be available as part of your - distribution (while you still may need to upgrade them). - Note that you need development version of package that - includes both FreeType library and header files. -

-

- You can always download latest FreeType version from the - FreeType website. -

-

- Makefiles will try to pick FreeType from /usr/lib and /usr/include. - In case it is installed elsewhere you will need to set environment - variables - ALT_FREETYPE_LIB_PATH - and - ALT_FREETYPE_HEADERS_PATH - to refer to place where library and header files are installed. -

-
- -

Advanced Linux Sound Architecture (ALSA) (Linux only)

- -
-

- Linux only: - Version 0.9.1 or newer of the ALSA files are - required for building the - OpenJDK on Linux. - These Linux files are usually available from an "alsa" - of "libasound" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. - The makefiles will check this emit a sanity error if it is - missing or the wrong version. - As a last resort you can go to the - - Advanced Linux Sound Architecture Site. -

- -

Windows Specific Dependencies

- -
- - Unix Command Tools (CYGWIN) - -
-

- The - OpenJDK - requires access to a set of unix command tools - on Windows which can be supplied by - CYGWIN. -

- The - OpenJDK - build - requires CYGWIN version 1.5.12 or newer. - Information about CYGWIN can - be obtained from the CYGWIN website at - www.cygwin.com. -

- By default CYGWIN doesn't install all the tools required for building - the OpenJDK. - Along with the default installation, you need to install - the following tools. + +

Windows Specific Dependencies

+
+ Unix Command Tools (CYGWIN) +
+ The OpenJDK requires access to a set of unix command tools + on Windows which can be supplied by + CYGWIN. +

+ The OpenJDK build requires CYGWIN version 1.5.12 or newer. + Information about CYGWIN can + be obtained from the CYGWIN website at + www.cygwin.com. +

+ By default CYGWIN doesn't install all the tools required for building + the OpenJDK. + Along with the default installation, you need to install + the following tools. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Binary NamePackageDescription
ar.exeDevelbinutils: The GNU assembler, linker and binary + utilities
make.exeDevelmake: The GNU version of the 'make' utility
m4.exeInterpretersm4: GNU implementation of the traditional Unix macro + processor
cpio.exeUtilscpio: A program to manage archives of files
awk.exeUtilsawk: Pattern-directed scanning and processing language
file.exeUtilsfile: Determines file type using 'magic' numbers
zip.exeUtilszip: Package and compress (archive) files
unzip.exeUtilsunzip: Extract compressed files in a ZIP archive
free.exeUtilsfree: Display amount of free and used memory in the system
+
+

+ Note that the CYGWIN software can conflict with other non-CYGWIN + software on your Windows system. + CYGWIN provides a + FAQ for + known issues and problems, of particular interest is the + section on + + BLODA (applications that interfere with CYGWIN). +

+ Microsoft DirectX 9.0 SDK header files and libraries
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Binary NamePackageDescription
ar.exeDevelbinutils: The GNU assembler, linker and binary - utilities
make.exeDevelmake: The GNU version of the 'make' utility
m4.exeInterpretersm4: GNU implementation of the traditional Unix macro - processor
cpio.exeUtilscpio: A program to manage archives of files
file.exeUtilsfile: Determines file type using 'magic' numbers
+ Microsoft DirectX 9.0 SDK (Summer 2004) + headers are required for building + OpenJDK. + This SDK can be downloaded from + + Microsoft DirectX 9.0 SDK (Summer 2004). + If the link above becomes obsolete, the SDK can be found from + the Microsoft Download Site + (search with "DirectX 9.0 SDK Update Summer 2004"). + The location of this SDK can be set with + ALT_DXSDK_PATH + but it's normally found via the DirectX environment variable + DXSDK_DIR. +
+ MSVCRT.DLL +
+ i586 only: + The OpenJDK 32bit build requires access to + MSVCRT.DLL version 6.00.8337.0 or newer. + If the MSVCRT.DLL is not installed in + the system32 directory set the + ALT_MSVCRT_DLL_PATH + variable to the location. +

+ X64 only: + The OpenJDK 64bit build requires access to + MSVCRT.DLL version 7.0.3790.0 or newer, which is + usually supplied by the + Platform SDK. + If it is not available from the Platform SDK, + set the + ALT_MSVCRT_DLL_PATH + variable to the location. +

+ MSVCR71.DLL +
+ i586 only: + The + OpenJDK + build requires access to + MSVCR71.DLL version 7.10.3052.4 or newer which should be + supplied by the + Visual Studio product + If the MSVCR71.DLL is not available from the + Visual Studio product + set the + ALT_MSVCR71_DLL_PATH + variable to the location.
- - - Microsoft DirectX 9.0 SDK header files and libraries - - + +
+

Creating the Build

-

- Microsoft DirectX 9.0 SDK (Summer 2004) - headers are required for building - OpenJDK. - This SDK can be downloaded from - - Microsoft DirectX 9.0 SDK (Summer 2004). - If the link above becomes obsolete, the SDK can be found from - the Microsoft Download Site - (search with "DirectX 9.0 SDK Update Summer 2004"). - The location of this SDK can be set with - ALT_DXSDK_PATH - but it's normally found via the DirectX environment variable - DXSDK_DIR. -

- - - MSVCRT.DLL - - -
+ Once a machine is setup to build the OpenJDK, + the steps to create the build are fairly simple. + The various ALT settings can either be made into variables + or can be supplied on the + gmake + command. +
    +
  1. Use the sanity rule to double check all the ALT settings: +
    + + gmake + sanity + [ARCH_DATA_MODEL=32 or 64] + [other "ALT_" overrides] + +
    +
  2. +
  3. Start the build with the command: +
    + + gmake + [ARCH_DATA_MODEL=32 or 64] + [ALT_OUTPUTDIR=output_directory] + [other "ALT_" overrides] + +
    +
  4. +

- i586 only: - The - OpenJDK - 32bit build requires - access to MSVCRT.DLL - version 6.00.8337.0 or newer. - If the MSVCRT.DLL is not installed in - the system32 directory set the - ALT_MSVCRT_DLL_PATH - variable to the location. -

- X64 only: - The OpenJDK 64bit build requires access to - MSVCRT.DLL version 7.0.3790.0 or newer, which is - usually supplied by the - Platform SDK. - If it is not available from the Platform SDK, - set the - ALT_MSVCRT_DLL_PATH - variable to the location. + Solaris: + Note that ARCH_DATA_MODEL is really only needed on Solaris to + indicate you want to built the 64-bit version. + And before the Solaris 64-bit binaries can be used, they + must be merged with the binaries from a separate 32-bit build. + The merged binaries may then be used in either 32-bit or 64-bit mode, with + the selection occurring at runtime + with the -d32 or -d64 options.

- - - MSVCR71.DLL - - + +
+

Testing the Build

+ When the build is completed, you should see the generated + binaries and associated files in the j2sdk-image + directory in the output directory. + The default output directory is + build/platform, + where platform is one of +
    +
  • solaris-sparc
  • +
  • solaris-sparcv9
  • +
  • solaris-i586
  • +
  • solaris-amd64
  • +
  • linux-i586
  • +
  • linux-amd64
  • +
  • windows-i586
  • +
  • windows-amd64
  • +
+ In particular, the + build/platform/j2sdk-image/bin + directory should contain executables for the + OpenJDK tools and utilities.

- i586 only: - The - OpenJDK - build requires access to - MSVCR71.DLL version 7.10.3052.4 or newer which should be - supplied by the - Visual Studio product - If the MSVCR71.DLL is not available from the - Visual Studio product - set the - ALT_MSVCR71_DLL_PATH - variable to the location. + You can test that the build completed properly by using the build + to run the various demos that you will find in the + build/platform/j2sdk-image/demo + directory. +

+ The provided regression tests can be run with the jtreg + utility from + the jtreg site.

- -
- - -
- - -
- -

Creating the Build

- -
-

- Once a machine is setup to build the - OpenJDK, - the steps to create the - build are fairly simple. - The various ALT settings can either be made into variables - or can be supplied on the - gmake - command. -

-

    -
  1. Use the sanity rule to double check all the ALT settings: -
    - - gmake - sanity - [ARCH_DATA_MODEL=32 or 64] - [other "ALT_" overrides] - -
    -
  2. -
  3. Start the build with the command: -
    - - gmake - [ARCH_DATA_MODEL=32 or 64] - [ALT_OUTPUTDIR=output_directory] - [other "ALT_" overrides] - -
    -
  4. -
-

- Solaris: - Note that ARCH_DATA_MODEL is really only needed on Solaris to - indicate you want to built the 64-bit version. - And before the Solaris 64-bit binaries can be used, they - must be merged with the binaries from a separate 32-bit build. - The merged binaries may then be used in either 32-bit or 64-bit mode, with - the selection occurring at runtime - with the -d32 or -d64 options. -

- - -
- -

Testing the Build

- -
-

- When the build is completed, you should see the generated - binaries and associated files in the j2sdk-image - directory in the output directory. - The default output directory is - build/platform, - where platform is one of -

- In particular, the - build/platform/j2sdk-image/bin - directory should contain executables for the - OpenJDK - tools and utilities. -

- You can test that the build completed properly by using the build - to run the various demos that you will find in the - build/platform/j2sdk-image/demo - directory. -

- The provided regression tests can be run with the jtreg - utility from - the jtreg site. -

- - -
- -

Environment/Make Variables

- -

-Some of the -environment or make variables (just called variables in this -document) that can impact the build are: - -

- -
- -
PATH
-
Typically you want to set the PATH to include: -
    -
  • The location of the GNU make binary
  • -
  • The location of the JDK 6 java - (see Bootstrap JDK)
  • -
  • The location of the C/C++ compilers - (see compilers)
  • -
  • The location or locations for the Unix command utilities - (e.g. /usr/bin)
  • -
-
- -
ARCH_DATA_MODEL
-
The ARCH_DATA_MODEL variable - is used to specify whether the build is to generate 32-bit or 64-bit - binaries. - The Solaris build supports either 32-bit or 64-bit builds, but - Windows and Linux will support only one, depending on the specific - OS being used. - Normally, setting this variable is only necessary on Solaris. - Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, - or to 64 for generating 64-bit binaries. -
- -
ALT_BOOTDIR
-
- The location of the bootstrap JDK installation. - See Bootstrap JDK for more information. - You should always install your own local Bootstrap JDK and - always set ALT_BOOTDIR explicitly. -
- -
ALT_OUTPUTDIR
-
- An override for specifying the (absolute) path of where the - build output is to go. - The default output directory will be build/platform. -
- -
ALT_COMPILER_PATH
-
- The location of the C/C++ compiler. - The default varies depending on the platform. -
- -
ALT_CACERTS_FILE
-
- The location of the cacerts file. - The default will refer to - jdk/src/share/lib/security/cacerts. -
- -
ALT_BINARY_PLUGS_PATH
-
- The location of the binary plugs installation. - See Binary Plugs for more information. - You should always have a local copy of a - recent Binary Plugs install image - and set this variable to that location. -
- -
ALT_CUPS_HEADERS_PATH
-
- The location of the CUPS header files. - See CUPS information for more information. - If this path does not exist the fallback path is - /usr/include. -
- - -
ALT_MOTIF_DIR
-
- The location of the Motif 2.1 headers and libraries. - See Motif for details. -
- -
ALT_FREETYPE_LIB_PATH
-
- The location of the FreeType shared library. - See FreeType information for details. -
- -
ALT_FREETYPE_HEADERS_PATH
-
- The location of the FreeType header files. - See FreeType information for details. -
- -
Windows specific:
-
+ +
+

Environment/Make Variables

+

+ Some of the + environment or make variables (just called variables in this + document) that can impact the build are: +

-
ALT_MSDEVTOOLS_PATH
+
PATH
+
Typically you want to set the PATH to include: +
    +
  • The location of the GNU make binary
  • +
  • The location of the Bootstrap JDK java + (see Bootstrap JDK)
  • +
  • The location of the C/C++ compilers + (see compilers)
  • +
  • The location or locations for the Unix command utilities + (e.g. /usr/bin)
  • +
+
+
MILESTONE
+
+ The milestone name for the build (e.g."beta"). + The default value is "internal". +
+
BUILD_NUMBER
+
+ The build number for the build (e.g. "b27"). + The default value is "b00". +
+
ARCH_DATA_MODEL
+
The ARCH_DATA_MODEL variable + is used to specify whether the build is to generate 32-bit or 64-bit + binaries. + The Solaris build supports either 32-bit or 64-bit builds, but + Windows and Linux will support only one, depending on the specific + OS being used. + Normally, setting this variable is only necessary on Solaris. + Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, + or to 64 for generating 64-bit binaries. +
+
ALT_BOOTDIR
+
+ The location of the bootstrap JDK installation. + See Bootstrap JDK for more information. + You should always install your own local Bootstrap JDK and + always set ALT_BOOTDIR explicitly. +
+
ALT_BINARY_PLUGS_PATH
+
+ The location of the binary plugs installation. + See Binary Plugs for more information. + You should always have a local copy of a + recent Binary Plugs install image + and set this variable to that location. +
+
ALT_JDK_IMPORT_PATH
- The location of the Microsoft Visual Studio .NET 2003 - tools 'bin' directory. - The default is usually derived from - ALT_COMPILER_PATH. + The location of a previously built JDK installation. + See Optional Import JDK for more information. +
+
ALT_OUTPUTDIR
+
+ An override for specifying the (absolute) path of where the + build output is to go. + The default output directory will be build/platform. +
+
ALT_COMPILER_PATH
+
+ The location of the C/C++ compiler. + The default varies depending on the platform. +
+
ALT_CACERTS_FILE
+
+ The location of the cacerts file. + The default will refer to + jdk/src/share/lib/security/cacerts.
- -
ALT_DXSDK_PATH
+
ALT_CUPS_HEADERS_PATH
+
+ The location of the CUPS header files. + See CUPS information for more information. + If this path does not exist the fallback path is + /usr/include. +
+ +
ALT_MOTIF_DIR
+
+ The location of the Motif 2.1 headers and libraries. + See Motif for details. +
+
ALT_FREETYPE_LIB_PATH
+
+ The location of the FreeType shared library. + See FreeType information for details. +
+
ALT_FREETYPE_HEADERS_PATH
+
+ The location of the FreeType header files. + See FreeType information for details. +
+
ALT_JDK_DEVTOOLS_PATH
+
+ The default root location of the devtools. + The default value is + $(ALT_SLASH_JAVA)/devtools. +
+
ALT_DEVTOOLS_PATH
- The location of the - Microsoft DirectX 9 SDK. - The default will be to try and use the DirectX environment - variable DXSDK_DIR, - failing that, look in C:/DXSDK. + The location of tools like the + zip and unzip + binaries, but might also contain the GNU make utility + (gmake). + So this area is a bit of a grab bag, especially on Windows. + The default value depends on the platform and + Unix Commands being used. + On Linux the default will be + $(ALT_JDK_DEVTOOLS_PATH)/linux/bin, + on Solaris + $(ALT_JDK_DEVTOOLS_PATH)/{sparc,i386}/bin, + on Windows with MKS + %SYSTEMDRIVE%/UTILS, + and on Windows with CYGWIN + /usr/bin.
- -
ALT_MSVCRT_DLL_PATH
+
ALT_UNIXCOMMAND_PATH
+
+ An override for specifying where the + Unix command set are located. + The default location varies depending on the platform, + "%SYSTEMDRIVE%/MKSNT" or + $(ROOTDIR) on Windows with MKS, otherwise it's + "/bin" or /usr/bin. +
+
ALT_UNIXCCS_PATH
+
+ Solaris only: + An override for specifying where the Unix CCS + command set are located. + The default location is /usr/ccs/bin +
+
ALT_USRBIN_PATH
+
+ An override for specifying where the + Unix /usr/bin commands are located. You usually do not need + to set this variable: the default location is /usr/bin) +
+
ALT_SLASHJAVA
+
+ The default root location for many of the ALT path locations + of the following ALT variables. + The default value is + "/java" on Solaris and Linux, + "J:" on Windows. +
+
ALT_BUILD_JDK_IMPORT_PATH
- The location of the - MSVCRT.DLL. + These are useful in managing builds on multiple platforms. + The default network location for all of the import JDK images + for all platforms. + If ALT_JDK_IMPORT_PATH + is not set, this directory will be used and should contain + the following directories: + solaris-sparc, + solaris-i586, + solaris-sparcv9, + solaris-amd64, + linux-i586, + linux-amd64, + windows-i586, + and + windows-amd64. + Where each of these directories contain the import JDK image + for that platform.
- -
ALT_MSVCR71_DLL_PATH
+
ALT_BUILD_BINARY_PLUGS_PATH
+
+ These are useful in managing builds on multiple platforms. + The default network location for all of the binary plug images + for all platforms. + If ALT_BINARY_PLUGS_PATH + is not set, this directory will be used and should contain + the following directories: + solaris-sparc, + solaris-i586, + solaris-sparcv9, + solaris-amd64, + linux-i586, + linux-amd64, + windows-i586, + and + windows-amd64. + Where each of these directories contain the binary plugs image + for that platform. +
+
Windows specific:
- i586 only: - The location of the - MSVCR71.DLL. +
+
ALT_MSDEVTOOLS_PATH
+
+ The location of the Microsoft Visual Studio .NET 2003 + tools 'bin' directory. + The default is usually derived from + ALT_COMPILER_PATH. +
+
ALT_DXSDK_PATH
+
+ The location of the + Microsoft DirectX 9 SDK. + The default will be to try and use the DirectX environment + variable DXSDK_DIR, + failing that, look in C:/DXSDK. +
+
ALT_MSVCRT_DLL_PATH
+
+ The location of the + MSVCRT.DLL. +
+
ALT_MSVCR71_DLL_PATH
+
+ i586 only: + The location of the + MSVCR71.DLL. +
+
-
- -
-
- - -
- -

Troubleshooting

- -
-

- A build can fail for any number of reasons. - Most failures - are a result of trying to build in an environment in which all the - pre-build requirements have not been met. - The first step in - troubleshooting a build failure is to recheck that you have satisfied - all the pre-build requirements for your platform. - Look for the check list of the platform you are building on in the - Table of Contents. - -

- You can validate your build environment by using the sanity - target. - Any errors listed - will stop the build from starting, and any warnings may result in - a flawed product build. - We strongly encourage you to evaluate every - sanity check warning and fix it if required, before you proceed - further with your build. - -

- Some of the more common problems with builds are briefly described - below, with suggestions for remedies. - -

-
- -
+ + +
+

Troubleshooting

+
+ A build can fail for any number of reasons. + Most failures + are a result of trying to build in an environment in which all the + pre-build requirements have not been met. + The first step in + troubleshooting a build failure is to recheck that you have satisfied + all the pre-build requirements for your platform. + Look for the check list of the platform you are building on in the + Table of Contents. +

+ You can validate your build environment by using the sanity + target. + Any errors listed + will stop the build from starting, and any warnings may result in + a flawed product build. + We strongly encourage you to evaluate every + sanity check warning and fix it if required, before you proceed + further with your build. +

+ Some of the more common problems with builds are briefly described + below, with suggestions for remedies. +

+
+
+ + diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/doc-files/binding_chart.png Binary file jaxws/src/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/doc-files/binding_chart.png has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/doc-files/binding_chart.sxd Binary file jaxws/src/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/doc-files/binding_chart.sxd has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/j2s_architecture.gif Binary file jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/j2s_architecture.gif has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/j2s_architecture.sxd Binary file jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/j2s_architecture.sxd has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/packages.png Binary file jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/packages.png has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/packages.vsd Binary file jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/packages.vsd has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/readme.txt --- a/jaxws/src/share/classes/com/sun/xml/internal/bind/v2/doc-files/readme.txt Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -The sxd/vsd files are the master, and the gif file should be created from it. diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/README-builds.html --- a/jdk/make/README-builds.html Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/README-builds.html Fri May 30 00:00:00 2008 +0200 @@ -1,1490 +1,1658 @@ - -OpenJDK Build README - - -
- -
-

OpenJDK Build README

-
- - -
- -

Introduction

- -
-

- This README file contains build instructions for the - OpenJDK. - Building the source code for the - OpenJDK - requires - a certain degree of technical expertise. -

- - -
- -

Contents

- -
- -
- - -
- -

Minimum Build Environments

- -
-

- This file often describes specific requirements for what we call the - "minimum build environments" (MBE) for the JDK. - Building with the MBE will generate the most compatible - bits that install on, and run correctly on, the most variations - of the same base OS and hardware architecture. - These usually represent what is often called the - least common denominator platforms. - It is understood that most developers will NOT be using these - specific platforms, and in fact creating these specific platforms - may be difficult due to the age of some of this software. -

- -

- The minimum OS and C/C++ compiler versions needed for building the - OpenJDK: -

-

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + OpenJDK 6 Build README + + + +
Base OS and ArchitectureOSCompiler
Linux X86 (32bit)Red Hat Enterprise Linux 4 gcc 4
Linux X64 (64bit)Red Hat Enterprise Linux 4 gcc 4
Solaris SPARC (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris SPARCV9 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X86 (32bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Solaris X64 (64bit)Solaris 10 + patches -
- See SunSolve for patch downloads. -
Sun Studio 11
Windows X86 (32bit)Windows XPMicrosoft Visual Studio .NET 2003 Professional
Windows X64 (64bit)Windows Server 2003 - Enterprise x64 EditionMicrosoft Platform SDK - April 2005
+ + + + + +
+ + OpenJDK + +
+ +

OpenJDK 6 Build README

+
-
-
- - -
- -

Specific Developer Build Environments

- -
-

- We won't be listing all the possible environments, but - we will try to provide what information we have available to us. -

- -

Fedora

- -
- TBD -
- -

Debian

- -
- TBD -
- -

Ubuntu

- -
-

- In addition to needing the Bootstrap JDK and the Binary Plugs, - when building on Ubuntu you will need to - make sure certain packages are installed. - In particular, certain X11 packages, make, m4, gawk, gcc 4, - binutils, cups, freetype - and alsa. - -

Ubuntu 6.06

- -

- The following list of packages for Ubuntu 6.06 is a working set that - does appear to work. - -

- Note that it's quite possible that some of these - packages are not required, so anyone discovering that some of the - packages listed below are NOT required, - please let the - OpenJDK - team know. -

- All the packages below can be installed with the - Synaptic Package manager provided with the base Ubuntu 6.06 release. - -

-
    -
  • binutils (2.16.1cvs20060117-1ubuntu2.1)
  • -
  • cpp (4:4.0.3-1)
  • -
  • cpp-4.0 (4.0.3-1ubuntu5)
  • -
  • libfreetype6-dev
  • -
  • g++ (4:4.0.3-1)
  • -
  • g++-4.0 (4.0.3-1ubuntu5)
  • -
  • gawk (1:3.1.5-2build1)
  • -
  • gcc (4:4.0.3-1)
  • -
  • gcc-4.0 (4.0.3-1ubuntu5)
  • -
  • libasound2-dev (1.0.10-2ubuntu4)
  • -
  • libc6 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libc6-dev (2.3.6-0ubuntu20.4)
  • -
  • libc6-i686 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • -
  • libcupsys2-dev (1.2.2-0ubuntu0.6.06)
  • -
  • libgcrypt11-dev (1.2.2-1)
  • -
  • libgnutls-dev (1.2.9-2ubuntu1.1)
  • -
  • libgnutls12 (1.2.9-2ubuntu1) to 1.2.9-2ubuntu1.1
  • -
  • libgpg-error-dev (1.1-4)
  • -
  • libice-dev (2:1.0.0-0ubuntu2)
  • -
  • liblockfile1 (1.06.1)
  • -
  • libopencdk8-dev (0.5.7-2)
  • -
  • libpopt-dev (1.7-5)
  • -
  • libsm-dev (2:1.0.0-0ubuntu2)
  • -
  • libstdc++6-4.0-dev (4.0.3-1ubuntu5)
  • -
  • libtasn1-2-dev (0.2.17-1ubuntu1)
  • -
  • libx11-dev (2:1.0.0-0ubuntu9)
  • -
  • libxau-dev (1:1.0.0-0ubuntu4)
  • -
  • libxaw-headers (2:1.0.1-0ubuntu3)
  • -
  • libxaw7-dev (2:1.0.1-0ubuntu3)
  • -
  • libxdmcp-dev (1:1.0.0-0ubuntu2)
  • -
  • libxext-dev (2:1.0.0-0ubuntu4)
  • -
  • libxi-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxmu-headers (2:1.0.0-0ubuntu3)
  • -
  • libxmuu-dev (2:1.0.0-0ubuntu3)
  • -
  • libxp-dev (6.8.2-11ubuntu2)
  • -
  • libxpm-dev (1:3.5.4.2-0ubuntu3)
  • -
  • libxrandr-dev (1:1.1.0.2-0ubuntu4)
  • -
  • libxt-dev (1:1.0.0-0ubuntu3)
  • -
  • libxtrap-dev (2:1.0.0-0ubuntu2)
  • -
  • libxtst-dev (2:1.0.1-0ubuntu2)
  • -
  • libxv-dev (2:1.0.1-0ubuntu3)
  • -
  • linux-kernel-headers (2.6.11.2-0ubuntu18)
  • -
  • m4 (1.4.4-1)
  • -
  • make (3.80+3.81.b4-1)
  • -
  • ssl-cert (1.0.13)
  • -
  • x-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-core-dev (7.0.4-0ubuntu2)
  • -
  • x11proto-input-dev (1.3.2-0ubuntu2)
  • -
  • x11proto-kb-dev (1.0.2-0ubuntu2)
  • -
  • x11proto-randr-dev (1.1.2-0ubuntu2)
  • -
  • x11proto-record-dev (1.13.2-0ubuntu2)
  • -
  • x11proto-trap-dev (3.4.3-0ubuntu2)
  • -
  • x11proto-video-dev (2.2.2-0ubuntu2)
  • -
  • x11proto-xext-dev (7.0.2-0ubuntu2)
  • -
  • xlibs-dev (7.0.0-0ubuntu45)
  • -
  • zlib1g-dev (1:1.2.3-6ubuntu4)
  • -
-
- -

Ubuntu 7.04

- -

- Using the Synaptic Package Manager, download the following - packages (double indented packages are automatically aquired - due to package dependencies): - -

- -
-
- - -
- -

Source Directory Structure

- -
-

- The source code for the OpenJDK is delivered in a set of - directories: - hotspot, - langtools, - corba, - jaxws, - jaxp, - and - jdk. - The hotspot directory contains the source code and make - files for building the OpenJDK Hotspot Virtual Machine. - The langtools directory contains the source code and make - files for building the OpenJDK javac and language tools. - The corba directory contains the source code and make - files for building the OpenJDK Corba files. - The jaxws directory contains the source code and make - files for building the OpenJDK JAXWS files. - The jaxp directory contains the source code and make - files for building the OpenJDK JAXP files. - The jdk directory contains the source code and make files for - building the OpenJDK runtime libraries and misc files. - The top level Makefile (or control/Makefile) - is used to build the entire OpenJDK. -

- - -
- -

Build Information

- -
-

- Building the - OpenJDK - is done with a gmake - command line and various - environment or make variable settings that direct the make rules - to where various components have been installed. - Where possible the makefiles will attempt to located the various - components in the default locations or any component specific - variable settings. - When the normal defaults fail or components cannot be found, - the various - ALT_* variables (alternates) - can be used to help the makefiles locate components. -

- Refer to the bash/sh/ksh setup file - jdk/make/jdk_generic_profile.sh - if you need help in setting up your environment variables. - A build could be as simple as: -

-

+        
+ +
+

Minimum Build Environments

+
+ This file often describes specific requirements for what we call the + "minimum build environments" (MBE) for the JDK. + Building with the MBE will generate the most compatible + bits that install on, and run correctly on, the most variations + of the same base OS and hardware architecture. + These usually represent what is often called the + least common denominator platforms. + It is understood that most developers will NOT be using these + specific platforms, and in fact creating these specific platforms + may be difficult due to the age of some of this software. +

+ The minimum OS and C/C++ compiler versions needed for building the + OpenJDK: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Base OS and ArchitectureOSCompiler
Linux X86 (32bit)Red Hat Enterprise Linux 4 gcc 4
Linux X64 (64bit)Red Hat Enterprise Linux 4 gcc 4
Solaris SPARC (32bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris SPARCV9 (64bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris X86 (32bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Solaris X64 (64bit)Solaris 10 + patches +
+ See + SunSolve for patch downloads. +
Sun Studio 11
Windows X86 (32bit)Windows XPMicrosoft Visual Studio .NET 2003 Professional
Windows X64 (64bit)Windows Server 2003 - Enterprise x64 EditionMicrosoft Platform SDK - April 2005
+

+ +
+

Specific Developer Build Environments

+
+ We won't be listing all the possible environments, but + we will try to provide what information we have available to us. +
+ +

Fedora

+
+ TBD +
+ +

Debian

+
+ TBD +
+ +

Ubuntu

+
+ In addition to needing the Bootstrap JDK and the Binary Plugs, + when building on Ubuntu you will need to + make sure certain packages are installed. + In particular, certain X11 packages, make, m4, gawk, gcc 4, + binutils, cups, freetype + and alsa. + +

Ubuntu 6.06

+

+ The following list of packages for Ubuntu 6.06 is a working set that + does appear to work. +

+ Note that it's quite possible that some of these + packages are not required, so anyone discovering that some of the + packages listed below are NOT required, + please let the + OpenJDK + team know. +

+ All the packages below can be installed with the + Synaptic Package manager provided with the base Ubuntu 6.06 release. +

+
    +
  • binutils (2.16.1cvs20060117-1ubuntu2.1)
  • +
  • cpp (4:4.0.3-1)
  • +
  • cpp-4.0 (4.0.3-1ubuntu5)
  • +
  • libfreetype6-dev
  • +
  • g++ (4:4.0.3-1)
  • +
  • g++-4.0 (4.0.3-1ubuntu5)
  • +
  • gawk (1:3.1.5-2build1)
  • +
  • gcc (4:4.0.3-1)
  • +
  • gcc-4.0 (4.0.3-1ubuntu5)
  • +
  • libasound2-dev (1.0.10-2ubuntu4)
  • +
  • libc6 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • +
  • libc6-dev (2.3.6-0ubuntu20.4)
  • +
  • libc6-i686 (2.3.6-0ubuntu20) to 2.3.6-0ubuntu20.4
  • +
  • libcupsys2-dev (1.2.2-0ubuntu0.6.06)
  • +
  • libgcrypt11-dev (1.2.2-1)
  • +
  • libgnutls-dev (1.2.9-2ubuntu1.1)
  • +
  • libgnutls12 (1.2.9-2ubuntu1) to 1.2.9-2ubuntu1.1
  • +
  • libgpg-error-dev (1.1-4)
  • +
  • libice-dev (2:1.0.0-0ubuntu2)
  • +
  • liblockfile1 (1.06.1)
  • +
  • libopencdk8-dev (0.5.7-2)
  • +
  • libpopt-dev (1.7-5)
  • +
  • libsm-dev (2:1.0.0-0ubuntu2)
  • +
  • libstdc++6-4.0-dev (4.0.3-1ubuntu5)
  • +
  • libtasn1-2-dev (0.2.17-1ubuntu1)
  • +
  • libx11-dev (2:1.0.0-0ubuntu9)
  • +
  • libxau-dev (1:1.0.0-0ubuntu4)
  • +
  • libxaw-headers (2:1.0.1-0ubuntu3)
  • +
  • libxaw7-dev (2:1.0.1-0ubuntu3)
  • +
  • libxdmcp-dev (1:1.0.0-0ubuntu2)
  • +
  • libxext-dev (2:1.0.0-0ubuntu4)
  • +
  • libxi-dev (2:1.0.0-0ubuntu3)
  • +
  • libxmu-dev (2:1.0.0-0ubuntu3)
  • +
  • libxmu-headers (2:1.0.0-0ubuntu3)
  • +
  • libxmuu-dev (2:1.0.0-0ubuntu3)
  • +
  • libxp-dev (6.8.2-11ubuntu2)
  • +
  • libxpm-dev (1:3.5.4.2-0ubuntu3)
  • +
  • libxrandr-dev (1:1.1.0.2-0ubuntu4)
  • +
  • libxt-dev (1:1.0.0-0ubuntu3)
  • +
  • libxtrap-dev (2:1.0.0-0ubuntu2)
  • +
  • libxtst-dev (2:1.0.1-0ubuntu2)
  • +
  • libxv-dev (2:1.0.1-0ubuntu3)
  • +
  • linux-kernel-headers (2.6.11.2-0ubuntu18)
  • +
  • m4 (1.4.4-1)
  • +
  • make (3.80+3.81.b4-1)
  • +
  • ssl-cert (1.0.13)
  • +
  • x-dev (7.0.4-0ubuntu2)
  • +
  • x11proto-core-dev (7.0.4-0ubuntu2)
  • +
  • x11proto-input-dev (1.3.2-0ubuntu2)
  • +
  • x11proto-kb-dev (1.0.2-0ubuntu2)
  • +
  • x11proto-randr-dev (1.1.2-0ubuntu2)
  • +
  • x11proto-record-dev (1.13.2-0ubuntu2)
  • +
  • x11proto-trap-dev (3.4.3-0ubuntu2)
  • +
  • x11proto-video-dev (2.2.2-0ubuntu2)
  • +
  • x11proto-xext-dev (7.0.2-0ubuntu2)
  • +
  • xlibs-dev (7.0.0-0ubuntu45)
  • +
  • zlib1g-dev (1:1.2.3-6ubuntu4)
  • +
+
+ +

Ubuntu 7.04

+

+ Using the Synaptic Package Manager, download the following + packages (double indented packages are automatically aquired + due to package dependencies): +

+
    +
  • build-essential
  • +
      +
    • dpkg-dev
    • +
    • g++
    • +
    • g++-4.1
    • +
    • libc6-dev
    • +
    • libstdc++6.4.1-dev
    • +
    • linux-libc-dev
    • +
    +
  • gawk
  • +
  • m4
  • +
  • libasound2-dev
  • + +
  • libmotif3-dev
  • +
      +
    • libmotif3
    • +
    +
  • libcupsys2-dev
  • +
      +
    • libgcrypt11-dev
    • +
    • lgnutls-dev
    • +
    • libgpg-error-dev
    • +
    • liblzo-dev
    • +
    • libopencdk8-dev
    • +
    • libpopt-dev
    • +
    • libtasn1-3-dev
    • +
    • zlib1g-dev
    • +
    +
  • sun-java6-jdk
  • +
      +
    • java-common
    • +
    • libltdl3
    • +
    • odbcinst1debian1
    • +
    • sun-java6-bin
    • +
    • sun-java6-jre
    • +
    • unixodbc
    • +
    +
  • xlibs-dev
  • +
      +
    • (many)
    • +
    +
  • x11proto-print-dev
  • +
  • libxaw7-dev
  • +
      +
    • libxaw-headers
    • +
    +
  • libxp-dev
  • +
  • libfreetype6-dev
  • +
+
+
+ +
+

Source Directory Structure

+
+

+ The source code for the OpenJDK is delivered in a set of + directories: + hotspot, + langtools, + corba, + jaxws, + jaxp, + and + jdk. + The hotspot directory contains the source code and make + files for building the OpenJDK Hotspot Virtual Machine. + The langtools directory contains the source code and make + files for building the OpenJDK javac and language tools. + The corba directory contains the source code and make + files for building the OpenJDK Corba files. + The jaxws directory contains the source code and make + files for building the OpenJDK JAXWS files. + The jaxp directory contains the source code and make + files for building the OpenJDK JAXP files. + The jdk directory contains the source code and make files for + building the OpenJDK runtime libraries and misc files. + The top level Makefile + is used to build the entire OpenJDK. +

+ +
+

Build Information

+
+ Building the OpenJDK + is done with a gmake + command line and various + environment or make variable settings that direct the make rules + to where various components have been installed. + Where possible the makefiles will attempt to located the various + components in the default locations or any component specific + variable settings. + When the normal defaults fail or components cannot be found, + the various + ALT_* variables (alternates) + can be used to help the makefiles locate components. +

+ Refer to the bash/sh/ksh setup file + jdk/make/jdk_generic_profile.sh + if you need help in setting up your environment variables. + A build could be as simple as: +

+

                 bash
                 . jdk/make/jdk_generic_profile.sh
                 gmake sanity && gmake
-        
-
-

- Of course ksh or sh would work too. - But some customization will probably be necessary. - The sanity rule will make some basic checks on build - dependencies and generate appropriate warning messages - regarding missing, out of date, or newer than expected components - found on your system. -

- - -
- -

GNU make (gmake)

- -
-

- The Makefiles in the - OpenJDK - are only valid when used with the - GNU version of the utility command make - (gmake). - A few notes about using GNU make: -

    -
  • - In general, you need GNU make version 3.78.1 or newer. -
  • -
  • - Place the location of the GNU make binary in the PATH. -
  • -
  • - Linux: - The /usr/bin/make command should work fine for you. -
  • -
  • - Solaris: - Do NOT use /usr/bin/make on Solaris. - If your Solaris system has the software - from the Solaris Companion CD installed, - you should use gmake - which will be located in either the /opt/sfw/bin or - /usr/sfw/bin directory. -
  • -
  • + +
+

+ Of course ksh or sh would work too. + But some customization will probably be necessary. + The sanity rule will make some basic checks on build + dependencies and generate appropriate warning messages + regarding missing, out of date, or newer than expected components + found on your system. +

+ +
+

GNU make (gmake)

+
+ The Makefiles in the OpenJDK are only valid when used with the + GNU version of the utility command make + (gmake). + A few notes about using GNU make: + +

+ Information on GNU make, and access to ftp download sites, are + available on the + + GNU make web site + . + The latest source to GNU make is available at + + ftp.gnu.org/pub/gnu/make/. +

+ +
+

Basic Linux System Setup

+
+ i586 only: + The minimum recommended hardware for building the Linux version + is a Pentium class processor or better, at least 256 MB of RAM, and + approximately 1.5 GB of free disk space. +

+ X64 only: + The minimum recommended hardware for building the Linux + version is an AMD Opteron class processor, at least 512 MB of RAM, and + approximately 4 GB of free disk space. +

+ The build will use the tools contained in + /bin and + /usr/bin + of a standard installation of the Linux operating environment. + You should ensure that these directories are in your + PATH. +

+ Note that some Linux systems have a habit of pre-populating + your environment variables for you, for example JAVA_HOME + might get pre-defined for you to refer to the JDK installed on + your Linux system. + You will need to unset JAVA_HOME. + It's a good idea to run env and verify the + environment variables you are getting from the default system + settings make sense for building the + OpenJDK. +

+ +

Basic Linux Check List

+
+
    +
  1. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  2. +
  3. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH. +
  4. +
  5. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  6. +
  7. + Install or upgrade the FreeType development + package. +
  8. +
  9. + + Install the + Motif header files, set + ALT_MOTIF_DIR. +
  10. +
+
+ +
+

Basic Solaris System Setup

+
+ The minimum recommended hardware for building the + Solaris SPARC version is an UltraSPARC with 512 MB of RAM. + For building + the Solaris x86 version, a Pentium class processor or better and at + least 512 MB of RAM are recommended. + Approximately 1.4 GB of free disk + space is needed for a 32-bit build. +

+ If you are building the 64bit version, you should + run the command "isainfo -v" to verify that you have a + 64-bit installation, it should say sparcv9 or + amd64. + An additional 7 GB of free disk space is needed + for a 64-bit build. +

+ The build uses the tools contained in /usr/ccs/bin + and /usr/bin of a standard developer or full installation of + the Solaris operating environment. +

+ Solaris patches specific to the JDK can be downloaded from the + + SunSolve JDK Solaris patches download page. + You should ensure that the latest patch cluster for + your version of the Solaris operating environment has also + been installed. +

+ +

Basic Solaris Check List

+
+
    +
  1. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  2. +
  3. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH. +
  4. +
  5. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  6. +
  7. + Install the + Sun Studio Compilers, set + ALT_COMPILER_PATH. +
  8. +
  9. + Install the + CUPS Include files, set + ALT_CUPS_HEADERS_PATH. +
  10. +
+
+ +
+

Basic Windows System Setup

+
+ i586 only: + The minimum recommended hardware for building the 32bit or X86 + Windows version is an Pentium class processor or better, at least + 512 MB of RAM, and approximately 600 MB of free disk space. + + NOTE: The Windows 2000 build machines need to use the + file system NTFS. + Build machines formatted to FAT32 will not work + because FAT32 doesn't support case-sensitivity in file names. + +

+ X64 only: + The minimum recommended hardware for building + the Windows X64 version is an AMD Opteron class processor, at least 1 + GB of RAM, and approximately 10 GB of free disk space. +

+ +

Windows Paths

+
Windows: - Make sure you start your build inside a bash/sh/ksh shell. -
- WARNING: Watch out for make version 3.81, it may - not work due to a lack of support for drive letter paths - like C:/. Use a 3.80 version, or find a newer - version that has this problem fixed. - - -

- Information on GNU make, and access to ftp download sites, are - available on the - - GNU make web site - . - The latest source to GNU make is available at - ftp.gnu.org/pub/gnu/make/. -

- - -
- -

Basic Linux System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the Linux version - is a Pentium class processor or better, at least 256 MB of RAM, and - approximately 1.5 GB of free disk space. -

- X64 only: - The minimum recommended hardware for building the Linux - version is an AMD Opteron class processor, at least 512 MB of RAM, and - approximately 4 GB of free disk space. -

- The build will use the tools contained in - /bin and - /usr/bin - of a standard installation of the Linux operating environment. - You should ensure that these directories are in your - PATH. -

- Note that some Linux systems have a habit of pre-populating - your environment variables for you, for example JAVA_HOME - might get pre-defined for you to refer to the JDK installed on - your Linux system. - You will need to unset JAVA_HOME. - It's a good idea to run env and verify the - environment variables you are getting from the default system - settings make sense for building the - OpenJDK. -

- - - -

Basic Linux Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install the - Motif header files, set - ALT_MOTIF_DIR.. -
  6. -
  7. - Install or upgrade the FreeType development - package. -
  8. -
-
- - -
- -

Basic Solaris System Setup

- -
-

- The minimum recommended hardware for building the - Solaris SPARC version is an UltraSPARC with 512 MB of RAM. - For building - the Solaris x86 version, a Pentium class processor or better and at - least 128 MB of RAM are recommended. - Approximately 1.4 GB of free disk - space is needed for a 32-bit build. -

- If you are building the 64bit version, you should - run the command "isainfo -v" to verify that you have a - 64-bit installation. - An additional 7 GB of free disk space is needed - for a 64-bit build. -

- The build uses the tools contained in /usr/ccs/bin - and /usr/bin of a standard developer or full installation of - the Solaris operating environment. -

- - - -

Basic Solaris Check List

- -
-
    -
  1. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  2. -
  3. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH. -
  4. -
  5. - Install the - Sun Studio Compilers, set - ALT_COMPILER_PATH. -
  6. -
  7. - Install the - CUPS Include files, set - ALT_CUPS_HEADERS_PATH. -
  8. -
-
- - -
- -

Basic Windows System Setup

- -
-

- i586 only: - The minimum recommended hardware for building the 32bit or X86 - Windows version is an Pentium class processor or better, at least - 512 MB of RAM, and approximately 600 MB of free disk space. - - NOTE: The Windows 2000 build machines need to use the - file system NTFS. - Build machines formatted to FAT32 will not work - because FAT32 doesn't support case-sensitivity in file names. - -

- X64 only: - The minimum recommended hardware for building - the Windows X64 version is an AMD Opteron class processor, at least 1 - GB of RAM, and approximately 10 GB of free disk space. -

- - - -

Windows Paths

- -
-

- Windows: - Note that GNU make is a historic utility and is based very - heavily on shell scripting, so it does not tolerate the Windows habit - of having spaces in pathnames or the use of the \characters in pathnames. - Luckily on most Windows systems, you can use /instead of \, and - there is always a 'short' pathname without spaces for any path that - contains spaces. - Unfortunately, this short pathname can be somewhat dynamic and the - formula is difficult to explain. - You can use cygpath utility to map pathnames with spaces - or the \character into the C:/ style of pathname - (called 'mixed'), e.g. - cygpath -s -m "path". -

- The makefiles will try to translate any pathnames supplied - to it into the C:/ style automatically. -

- Note that use of CYGWIN creates a unique problem with regards to - setting PATH. Normally on Windows - the PATH variable contains directories - separated with the ";" character (Solaris and Linux uses ":"). - With CYGWIN, it uses ":", but that means that paths like "C:/path" - cannot be placed in the CYGWIN version of PATH and - instead CYGWIN uses something like /cygdrive/c/path - which CYGWIN understands, but only CYGWIN understands. - So be careful with paths on Windows. -

- - - -

Basic Windows Check List

- -
-
    -
  1. - Install the - CYGWIN product. -
  2. -
  3. - Install the - Bootstrap JDK, set - ALT_BOOTDIR. -
  4. -
  5. - Install the - Binary Plugs, set - ALT_BINARY_PLUGS_PATH.. -
  6. -
  7. - Install the - Microsoft Visual Studio .NET 2003 Professional or the - Microsoft Platform SDK. -
  8. -
  9. - Setup all environment variables for compilers - (see compilers). -
  10. -
  11. - Install - Microsoft DirectX SDK. -
  12. -
-
- - -
- -

Build Dependencies

- -
-

- Depending on the platform, the - OpenJDK - build process has some basic - dependencies on components not part of the - OpenJDK - sources. - Some of these are specific to a platform, some even specific to - an architecture. - Each dependency will have a set of ALT variables that can be set - to tell the makefiles where to locate the component. - In most cases setting these ALT variables may not be necessary - and the makefiles will find defaults on the system in standard - install locations or through component specific variables. - -

Bootstrap JDK

- -
-

- All - OpenJDK - builds require access to the previously released - JDK 6, this is often called a bootstrap JDK. - The JDK 6 binaries can be downloaded from Sun's - JDK 6 download site. - For build performance reasons - is very important that this bootstrap JDK be made available on the - local disk of the machine doing the build. - You should always set - ALT_BOOTDIR - to point to the location of - the bootstrap JDK installation, this is the directory pathname - that contains a bin, lib, and include - It's also a good idea to also place its bin directory - in the PATH environment variable, although it's - not required. -

- Solaris: - Some pre-installed JDK images may be available to you in the - directory /usr/jdk/instances. - If you don't set - ALT_BOOTDIR - the makefiles will look in that location for a JDK it can use. -

- -

Binary Plugs

- -
-

- Not all of the source code that makes up the JDK is available - under an open-source license. - In order to build an OpenJDK binary from source code, - you must first download and install the appropriate - binary plug bundles from the OpenJDK, go to the - OpenJDK site and select - the "Bundles(6)" link. - During the OpenJDK build process these "binary plugs" - for the encumbered components will be copied into your - resulting OpenJDK binary build image. - These binary plug files are only for the purpose of - building an OpenJDK binary. - Make sure you set - ALT_BINARY_PLUGS_PATH - to the root of this installation. -

- -

Certificate Authority File (cacert)

- -
-

- See - www.wikipedia.org/wiki/CAcert - for a better understanding of the Certificate Authority (CA). - A certificates file named "cacerts" - represents a system-wide keystore with CA certificates. - In JDK and JRE - binary bundles, the "cacerts" file contains root CA certificates from - several public CAs (e.g., VeriSign, Thawte, and Baltimore). - The source contain a cacerts file - without CA root certificates. - Formal JDK builders will need to secure - permission from each public CA and include the certificates into their - own custom cacerts file. - Failure to provide a populated cacerts file - will result in verification errors of a certificate chain during runtime. - The variable - ALT_CACERTS_FILE - can be used to override the default location of the - cacerts file that will get placed in your build. - By default an empty cacerts file is provided and that should be - fine for most JDK developers. -

- -

Compilers

- -
- - - Linux gcc/binutils - - + Note that GNU make is a historic utility and is based very + heavily on shell scripting, so it does not tolerate the Windows habit + of having spaces in pathnames or the use of the \characters in pathnames. + Luckily on most Windows systems, you can use /instead of \, and + there is always a 'short' pathname without spaces for any path that + contains spaces. + Unfortunately, this short pathname can be somewhat dynamic and the + formula is difficult to explain. + You can use cygpath utility to map pathnames with spaces + or the \character into the C:/ style of pathname + (called 'mixed'), e.g. + cygpath -s -m "path". +

+ The makefiles will try to translate any pathnames supplied + to it into the C:/ style automatically. +

+ Note that use of CYGWIN creates a unique problem with regards to + setting PATH. Normally on Windows + the PATH variable contains directories + separated with the ";" character (Solaris and Linux uses ":"). + With CYGWIN, it uses ":", but that means that paths like "C:/path" + cannot be placed in the CYGWIN version of PATH and + instead CYGWIN uses something like /cygdrive/c/path + which CYGWIN understands, but only CYGWIN understands. + So be careful with paths on Windows. +

+ +

Basic Windows Check List

+
+
    +
  1. + Install the + CYGWIN product. +
  2. +
  3. + Install the + Bootstrap JDK, set + ALT_BOOTDIR. +
  4. +
  5. + Install the + Binary Plugs, set + ALT_BINARY_PLUGS_PATH.. +
  6. +
  7. + Optional Import JDK, set + ALT_JDK_IMPORT_PATH. +
  8. +
  9. + Install the + Microsoft Visual Studio .NET 2003 Professional or the + Microsoft Platform SDK. +
  10. +
  11. + Setup all environment variables for compilers + (see compilers). +
  12. +
  13. + Install + Microsoft DirectX SDK. +
  14. +
+
+ +
+

Build Dependencies

-

- The GNU gcc compiler version should be 3.2.2 or newer. - The binutils package should be 2.11.93.0.2-11 or newer. - The compiler used should be the default compiler installed - in /usr/bin. -

- - Solaris: Sun Studio - -
-

- At a minimum, the - - Sun Studio 11 Compilers - (containing version 5.8 of the C and C++ compilers) is required, - with patches from the - - SunSolve web site. -

- Set - ALT_COMPILER_PATH - to point to the location of - the compiler binaries, and place this location in the PATH. -

- The Sun Studio Express compilers at: - - Sun Studio Express Download site - are also an option, although these compilers have not - been extensively used yet. -

- - - Windows i586: Microsoft Visual Studio .NET 2003 Professional - - -
-

- The 32-bit - OpenJDK - Windows build - requires Microsoft Visual Studio .NET 2003 (VS2003) Professional - Edition compiler. - The compiler and other tools are expected to reside - in the location defined by the variable VS71COMNTOOLS which - is set by the Microsoft Visual Studio .NET installer. -

- Once the compiler is installed, - it is recommended that you run VCVARS32.BAT - to set the compiler environment variables - MSVCDIR, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- The Microsoft Visual Studio .NET 2005 (VS2005) compiler - will not work at this time due to the new runtime dll - and the manifest requirements. -

- - - Windows X64: Microsoft Platform SDK April 2005 - - -
-

- On X64, - the Microsoft Platform Software - Development Kit (SDK), April 2005 Edition compiler, is required for - building the - OpenJDK - because it contains the C/C++ compiler. - You will need to minimally install the Core SDK and - the MDAC SDK features of this compiler. -

- Once the Platform SDK is installed, - it is recommended that you run SetEnv.Cmd /X64 - to set the compiler environment variables - MSSDK, - MSTOOLS, - INCLUDE, - LIB, and - PATH - prior to building the - OpenJDK. - The above environment variables MUST be set. -

- Note that this compiler may say it's version is a - Microsoft Visual Studio .NET 2005 (VS2005), but be careful, - it will not match the official VS2005 product. - This Platform SDK compiler is only used on X64 builds. + Depending on the platform, the OpenJDK build process has some basic + dependencies on components not part of the OpenJDK sources. + Some of these are specific to a platform, some even specific to + an architecture. + Each dependency will have a set of ALT variables that can be set + to tell the makefiles where to locate the component. + In most cases setting these ALT variables may not be necessary + and the makefiles will find defaults on the system in standard + install locations or through component specific variables. + +

Bootstrap JDK

+
+ All OpenJDK builds require access to the previously released + JDK 6, this is often called a bootstrap JDK. +
+ + Normally the "boot" JDK is the previously released version + of the JDK, so it's unusual for a JDK 6 build like this to + require a JDK 6 "boot". + Unfortunately, it is currently required due to some JDK 6 + dependencies in some of the sources. +
+ The JDK 6 binaries can be downloaded from Sun's + JDK 6 download site. + For build performance reasons + is very important that this bootstrap JDK be made available on the + local disk of the machine doing the build. + You should always set + ALT_BOOTDIR + to point to the location of + the bootstrap JDK installation, this is the directory pathname + that contains a bin, lib, and include + It's also a good idea to also place its bin directory + in the PATH environment variable, although it's + not required. +

+ Solaris: + Some pre-installed JDK images may be available to you in the + directory /usr/jdk/instances. + If you don't set + ALT_BOOTDIR + the makefiles will look in that location for a JDK it can use. +

+ +

Binary Plugs

+
+ Not all of the source code that makes up the JDK is available + under an open-source license. + This is a temporary situation and these binary plugs will be + replaced with fully open source replacements as soon as possible. + So currently, in order to build a complete OpenJDK image, + you must first download and install the appropriate + binary plug bundles for the OpenJDK, go to the + OpenJDK site and select + the + + + "Bundles(6)" + + link and download the binaryplugs for + your particular platform. + The file downloaded is a jar file that must be extracted by running + the jar file with: +
+ +
+            java -jar jdk-6-ea-plug-bnn-os-arch-dd_month_year.jar
+                    
+
+ A prompt will be issued for acceptance of these binary plug files. + During the OpenJDK build process these "binary plugs" + for the encumbered components will be copied into your + resulting OpenJDK binary build image. + These binary plug files are only for the purpose of + building an OpenJDK binary. + Make sure you set + ALT_BINARY_PLUGS_PATH + to the root of this installation. +
+ +

Optional Import JDK

+
+ The ALT_JDK_IMPORT_PATH + setting is only needed if you are not building the entire + JDK. For example, if you have built the entire JDK once, and + wanted to avoid repeatedly building the Hotspot VM, you could + set this to the location of the previous JDK install image + and the build will copy the needed files from this import area. +
+ +

Certificate Authority File (cacert)

+
+ See + http://en.wikipedia.org/wiki/Certificate_Authority + for a better understanding of the Certificate Authority (CA). + A certificates file named "cacerts" + represents a system-wide keystore with CA certificates. + In JDK and JRE + binary bundles, the "cacerts" file contains root CA certificates from + several public CAs (e.g., VeriSign, Thawte, and Baltimore). + The source contain a cacerts file + without CA root certificates. + Formal JDK builders will need to secure + permission from each public CA and include the certificates into their + own custom cacerts file. + Failure to provide a populated cacerts file + will result in verification errors of a certificate chain during runtime. + The variable + ALT_CACERTS_FILE + can be used to override the default location of the + cacerts file that will get placed in your build. + By default an empty cacerts file is provided and that should be + fine for most JDK developers. +
+ +

Compilers

+
+ Linux gcc/binutils +
+ The GNU gcc compiler version should be 3.2.2 or newer. + The binutils package should be 2.11.93.0.2-11 or newer. + The compiler used should be the default compiler installed + in /usr/bin. +

+ Older Linux systems may require a gcc and bunutils update. + The Redhat Enterprise Advanced Server 2.1 update 2 system + is one of these systems. + RedHat Linux users can obtain this binutils package from + Redhat web site. + You will need to remove the default compiler and binutils + packages and install the required packages + into the default location on the system. + However if you have a new video card driver, like + Geforce 4 it is best to use + the same compiler as the kernel was built with to + build the new video card driver module. + So you should build the modules before making this change. +

+ Solaris: Sun Studio +
+ At a minimum, the + + Sun Studio 11 Compilers + (containing version 5.8 of the C and C++ compilers) is required, + with patches from the + + SunSolve web site. +

+ Set + ALT_COMPILER_PATH + to point to the location of + the compiler binaries, and place this location in the PATH. +

+ The Sun Studio Express compilers at: + + Sun Studio Express Download site + are also an option, although these compilers have not + been extensively used yet. +

+ Windows i586: Microsoft Visual Studio .NET 2003 Professional +
+ The 32-bit OpenJDK Windows build + requires Microsoft Visual Studio .NET 2003 (VS2003) Professional + Edition compiler. + The compiler and other tools are expected to reside + in the location defined by the variable VS71COMNTOOLS which + is set by the Microsoft Visual Studio .NET installer. +

+ Once the compiler is installed, + it is recommended that you run VCVARS32.BAT + to set the compiler environment variables + MSVCDIR, + INCLUDE, + LIB, and + PATH + prior to building the + OpenJDK. + The above environment variables MUST be set. +

+ The Microsoft Visual Studio .NET 2005 (VS2005) compiler + will not work at this time due to the new runtime dll + and the manifest requirements. +

+ Windows X64: Microsoft Platform SDK April 2005 +
+ On X64, the Microsoft Platform Software + Development Kit (SDK), April 2005 Edition compiler, + is required for building the OpenJDK + because it contains the C/C++ compiler. + You will need to minimally install the Core SDK and + the MDAC SDK features of this compiler. +

+ Once the Platform SDK is installed, + it is recommended that you run SetEnv.Cmd /X64 + to set the compiler environment variables + MSSDK, + MSTOOLS, + INCLUDE, + LIB, and + PATH + prior to building the + OpenJDK. + The above environment variables MUST be set. +

+ Note that this compiler may say it's version is a + Microsoft Visual Studio .NET 2005 (VS2005), but be careful, + it will not match the official VS2005 product. + This Platform SDK compiler is only used on X64 builds. +

+
+ +

Zip and Unzip

+
+ Version 2.2 (November 3rd 1997) or newer of the zip utility + and version 5.12 or newer of the unzip utility is needed + to build the JDK. + With Solaris, Linux, and Windows CYGWIN, the zip and unzip + utilities installed on the system should be fine. + Information and the source code for + ZIP.EXE and UNZIP.EXE is available on the + info-zip web site. +
+ +

Common UNIX Printing System (CUPS) Headers (Solaris & Linux)

+
+ Solaris: + CUPS header files are required for building the + OpenJDK on Solaris. + The Solaris header files can be obtained by installing + the package SFWcups from the Solaris Software + Companion CD/DVD, these often will be installed into + /opt/sfw/cups. +

+ Linux: + CUPS header files are required for building the + OpenJDK on Linux. + The Linux header files are usually available from a "cups" + development package, it's recommended that you try and use + the package provided by the particular version of Linux that + you are using. +

+ The CUPS header files can always be downloaded from + www.cups.org. + The variable + ALT_CUPS_HEADERS_PATH + can be used to override the default location of the + CUPS Header files. +

+ +

Motif Headers (Solaris & Linux)

+
+ + Motif headers (not libraries) are required for building the + OpenJDK 6. +

+ Solaris: + Normally these files can be found on Solaris systems + at /usr/include/Xm, so on Solaris systems no further downloads + should be needed. +

+ Linux: + On Linux, your particular Linux distribution may provide a + "motif" development package you can install. If this package + installs the files into /usr/include/Xm, no further action should + be needed. + An acceptable version of these Motif header files are + available in the source bundle + + openmotif-2.1.30.5p1.tgz + from + www.openbsd.org. + You would need to install the package and set the environment variable + ALT_MOTIF_DIR + to refer to the top of this installation. +

+ +

FreeType 2

+
+ Version 2.3 or newer of FreeType is required for building the OpenJDK. + On Unix systems required files can be available as part of your + distribution (while you still may need to upgrade them). + Note that you need development version of package that + includes both FreeType library and header files. +

+ You can always download latest FreeType version from the + FreeType website. +

+ Makefiles will try to pick FreeType from /usr/lib and /usr/include. + In case it is installed elsewhere you will need to set environment + variables + ALT_FREETYPE_LIB_PATH + and + ALT_FREETYPE_HEADERS_PATH + to refer to place where library and header files are installed. +

+ +

Advanced Linux Sound Architecture (ALSA) (Linux only)

+
+ Linux only: + Version 0.9.1 or newer of the ALSA files are + required for building the OpenJDK on Linux. + These Linux files are usually available from an "alsa" + of "libasound" + development package, it's highly recommended that you try and use + the package provided by the particular version of Linux that + you are using. + The makefiles will check this emit a sanity error if it is + missing or the wrong version. +

+ In particular, older Linux systems will likely not have the + right version of ALSA installed, for example + Redhat AS 2.1 U2 and SuSE 8.1 do not include a sufficiently + recent ALSA distribution. + On rpm-based systems, you can see if ALSA is installed by + running this command: +

+                    rpm -qa | grep alsa
+                
+ Both alsa and alsa-devel packages are needed. +

+ If your distribution does not come with ALSA, and you can't + find ALSA packages built for your particular system, + you can try to install the pre-built ALSA rpm packages from + + www.freshrpms.net. + Note that installing a newer ALSA could + break sound output if an older version of ALSA was previously + installed on the system, but it will enable JDK compilation. +

+ Installation: execute as root
+ [i586]: rpm -Uv --force alsa-lib-devel-0.9.1-rh61.i386.rpm
+ [x64]: rpm -Uv --force alsa-lib-devel-0.9.8-amd64.x86_64.rpm
+ Uninstallation:
+ [i586]: rpm -ev alsa-lib-devel-0.9.1-rh61
+ [x64]:rpm -ev alsa-lib-devel-0.9.8-amd64
+ Make sure that you do not link to the static library + (libasound.a), + by verifying that the dynamic library (libasound.so) is + correctly installed in /usr/lib. +
+ As a last resort you can go to the + + Advanced Linux Sound Architecture Site and build it from + source. +
+ Download driver and library + source tarballs from + ALSA's homepage. + As root, execute the following + commands (you may need to adapt the version number): +
+                        
+                            $ tar xjf alsa-driver-0.9.1.tar.bz2
+                            $ cd alsa-driver-0.9.1
+                            $ ./configure
+                            $ make install
+                            $ cd ..
+                            $ tar xjf alsa-lib-0.9.1.tar.bz2
+                            $ cd alsa-lib-0.9.1
+                            $ ./configure
+                            $ make install
+                        
+                    
+ Should one of the above steps fail, refer to the documentation on + ALSA's home page. +
+ Note that this is a minimum install that enables + building the JDK platform. To actually use ALSA sound drivers, more + steps are necessary as outlined in the documentation on ALSA's homepage. +

+ ALSA can be uninstalled by executing make uninstall first in + the alsa-lib-0.9.1 directory and then in + alsa-driver-0.9.1. +

+ There are no ALT* variables to change the assumed locations of ALSA, + the makefiles will expect to find the ALSA include files and library at: + /usr/include/alsa and /usr/lib/libasound.so.
- -
- -

Common UNIX Printing System (CUPS) Headers (Solaris & Linux)

- -
-

- Solaris: - CUPS header files are required for building the - OpenJDK on Solaris. - The Solaris header files can be obtained by installing - the package SFWcups from the Solaris Software - Companion CD/DVD, these often will be installed into - /opt/sfw/cups. -

- Linux: - CUPS header files are required for building the - OpenJDK on Linux. - The Linux header files are usually available from a "cups" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. -

- The CUPS header files can always be downloaded from - www.cups.org. - The variable - ALT_CUPS_HEADERS_PATH - can be used to override the default location of the - CUPS Header files. -

-

Motif Headers (Solaris & Linux)

- -
-

- Motif headers (not libraries) are required for building the - OpenJDK. -

- Solaris: - Normally these files can be found on Solaris systems - at /usr/include/Xm, so on Solaris systems no further downloads - should be needed. -

- Linux: - On Linux, your particular Linux distribution may provide a - "motif" development package you can install. If this package - installs the files into /usr/include/Xm, no further action should - be needed. - An acceptable version of these Motif header files are - available in the source bundle - - openmotif-2.1.30.5p1.tgz - from - www.openbsd.org. - You would need to install the package and set the environment variable - ALT_MOTIF_DIR - to refer to the top of this installation. -

- -

FreeType 2

- -
-

- Version 2.3 or newer of FreeType is required for building the OpenJDK. - On Unix systems required files can be available as part of your - distribution (while you still may need to upgrade them). - Note that you need development version of package that - includes both FreeType library and header files. -

-

- You can always download latest FreeType version from the - FreeType website. -

-

- Makefiles will try to pick FreeType from /usr/lib and /usr/include. - In case it is installed elsewhere you will need to set environment - variables - ALT_FREETYPE_LIB_PATH - and - ALT_FREETYPE_HEADERS_PATH - to refer to place where library and header files are installed. -

-
- -

Advanced Linux Sound Architecture (ALSA) (Linux only)

- -
-

- Linux only: - Version 0.9.1 or newer of the ALSA files are - required for building the - OpenJDK on Linux. - These Linux files are usually available from an "alsa" - of "libasound" - development package, it's recommended that you try and use - the package provided by the particular version of Linux that - you are using. - The makefiles will check this emit a sanity error if it is - missing or the wrong version. - As a last resort you can go to the - - Advanced Linux Sound Architecture Site. -

- -

Windows Specific Dependencies

- -
- - Unix Command Tools (CYGWIN) - -
-

- The - OpenJDK - requires access to a set of unix command tools - on Windows which can be supplied by - CYGWIN. -

- The - OpenJDK - build - requires CYGWIN version 1.5.12 or newer. - Information about CYGWIN can - be obtained from the CYGWIN website at - www.cygwin.com. -

- By default CYGWIN doesn't install all the tools required for building - the OpenJDK. - Along with the default installation, you need to install - the following tools. + +

Windows Specific Dependencies

+
+ Unix Command Tools (CYGWIN) +
+ The OpenJDK requires access to a set of unix command tools + on Windows which can be supplied by + CYGWIN. +

+ The OpenJDK build requires CYGWIN version 1.5.12 or newer. + Information about CYGWIN can + be obtained from the CYGWIN website at + www.cygwin.com. +

+ By default CYGWIN doesn't install all the tools required for building + the OpenJDK. + Along with the default installation, you need to install + the following tools. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Binary NamePackageDescription
ar.exeDevelbinutils: The GNU assembler, linker and binary + utilities
make.exeDevelmake: The GNU version of the 'make' utility
m4.exeInterpretersm4: GNU implementation of the traditional Unix macro + processor
cpio.exeUtilscpio: A program to manage archives of files
awk.exeUtilsawk: Pattern-directed scanning and processing language
file.exeUtilsfile: Determines file type using 'magic' numbers
zip.exeUtilszip: Package and compress (archive) files
unzip.exeUtilsunzip: Extract compressed files in a ZIP archive
free.exeUtilsfree: Display amount of free and used memory in the system
+
+

+ Note that the CYGWIN software can conflict with other non-CYGWIN + software on your Windows system. + CYGWIN provides a + FAQ for + known issues and problems, of particular interest is the + section on + + BLODA (applications that interfere with CYGWIN). +

+ Microsoft DirectX 9.0 SDK header files and libraries
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Binary NamePackageDescription
ar.exeDevelbinutils: The GNU assembler, linker and binary - utilities
make.exeDevelmake: The GNU version of the 'make' utility
m4.exeInterpretersm4: GNU implementation of the traditional Unix macro - processor
cpio.exeUtilscpio: A program to manage archives of files
file.exeUtilsfile: Determines file type using 'magic' numbers
+ Microsoft DirectX 9.0 SDK (Summer 2004) + headers are required for building + OpenJDK. + This SDK can be downloaded from + + Microsoft DirectX 9.0 SDK (Summer 2004). + If the link above becomes obsolete, the SDK can be found from + the Microsoft Download Site + (search with "DirectX 9.0 SDK Update Summer 2004"). + The location of this SDK can be set with + ALT_DXSDK_PATH + but it's normally found via the DirectX environment variable + DXSDK_DIR. +
+ MSVCRT.DLL +
+ i586 only: + The OpenJDK 32bit build requires access to + MSVCRT.DLL version 6.00.8337.0 or newer. + If the MSVCRT.DLL is not installed in + the system32 directory set the + ALT_MSVCRT_DLL_PATH + variable to the location. +

+ X64 only: + The OpenJDK 64bit build requires access to + MSVCRT.DLL version 7.0.3790.0 or newer, which is + usually supplied by the + Platform SDK. + If it is not available from the Platform SDK, + set the + ALT_MSVCRT_DLL_PATH + variable to the location. +

+ MSVCR71.DLL +
+ i586 only: + The + OpenJDK + build requires access to + MSVCR71.DLL version 7.10.3052.4 or newer which should be + supplied by the + Visual Studio product + If the MSVCR71.DLL is not available from the + Visual Studio product + set the + ALT_MSVCR71_DLL_PATH + variable to the location.
- - - Microsoft DirectX 9.0 SDK header files and libraries - - + +
+

Creating the Build

-

- Microsoft DirectX 9.0 SDK (Summer 2004) - headers are required for building - OpenJDK. - This SDK can be downloaded from - - Microsoft DirectX 9.0 SDK (Summer 2004). - If the link above becomes obsolete, the SDK can be found from - the Microsoft Download Site - (search with "DirectX 9.0 SDK Update Summer 2004"). - The location of this SDK can be set with - ALT_DXSDK_PATH - but it's normally found via the DirectX environment variable - DXSDK_DIR. -

- - - MSVCRT.DLL - - -
+ Once a machine is setup to build the OpenJDK, + the steps to create the build are fairly simple. + The various ALT settings can either be made into variables + or can be supplied on the + gmake + command. +
    +
  1. Use the sanity rule to double check all the ALT settings: +
    + + gmake + sanity + [ARCH_DATA_MODEL=32 or 64] + [other "ALT_" overrides] + +
    +
  2. +
  3. Start the build with the command: +
    + + gmake + [ARCH_DATA_MODEL=32 or 64] + [ALT_OUTPUTDIR=output_directory] + [other "ALT_" overrides] + +
    +
  4. +

- i586 only: - The - OpenJDK - 32bit build requires - access to MSVCRT.DLL - version 6.00.8337.0 or newer. - If the MSVCRT.DLL is not installed in - the system32 directory set the - ALT_MSVCRT_DLL_PATH - variable to the location. -

- X64 only: - The OpenJDK 64bit build requires access to - MSVCRT.DLL version 7.0.3790.0 or newer, which is - usually supplied by the - Platform SDK. - If it is not available from the Platform SDK, - set the - ALT_MSVCRT_DLL_PATH - variable to the location. + Solaris: + Note that ARCH_DATA_MODEL is really only needed on Solaris to + indicate you want to built the 64-bit version. + And before the Solaris 64-bit binaries can be used, they + must be merged with the binaries from a separate 32-bit build. + The merged binaries may then be used in either 32-bit or 64-bit mode, with + the selection occurring at runtime + with the -d32 or -d64 options.

- - - MSVCR71.DLL - - + +
+

Testing the Build

+ When the build is completed, you should see the generated + binaries and associated files in the j2sdk-image + directory in the output directory. + The default output directory is + build/platform, + where platform is one of +
    +
  • solaris-sparc
  • +
  • solaris-sparcv9
  • +
  • solaris-i586
  • +
  • solaris-amd64
  • +
  • linux-i586
  • +
  • linux-amd64
  • +
  • windows-i586
  • +
  • windows-amd64
  • +
+ In particular, the + build/platform/j2sdk-image/bin + directory should contain executables for the + OpenJDK tools and utilities.

- i586 only: - The - OpenJDK - build requires access to - MSVCR71.DLL version 7.10.3052.4 or newer which should be - supplied by the - Visual Studio product - If the MSVCR71.DLL is not available from the - Visual Studio product - set the - ALT_MSVCR71_DLL_PATH - variable to the location. + You can test that the build completed properly by using the build + to run the various demos that you will find in the + build/platform/j2sdk-image/demo + directory. +

+ The provided regression tests can be run with the jtreg + utility from + the jtreg site.

- -
- - -
- - -
- -

Creating the Build

- -
-

- Once a machine is setup to build the - OpenJDK, - the steps to create the - build are fairly simple. - The various ALT settings can either be made into variables - or can be supplied on the - gmake - command. -

-

    -
  1. Use the sanity rule to double check all the ALT settings: -
    - - gmake - sanity - [ARCH_DATA_MODEL=32 or 64] - [other "ALT_" overrides] - -
    -
  2. -
  3. Start the build with the command: -
    - - gmake - [ARCH_DATA_MODEL=32 or 64] - [ALT_OUTPUTDIR=output_directory] - [other "ALT_" overrides] - -
    -
  4. -
-

- Solaris: - Note that ARCH_DATA_MODEL is really only needed on Solaris to - indicate you want to built the 64-bit version. - And before the Solaris 64-bit binaries can be used, they - must be merged with the binaries from a separate 32-bit build. - The merged binaries may then be used in either 32-bit or 64-bit mode, with - the selection occurring at runtime - with the -d32 or -d64 options. -

- - -
- -

Testing the Build

- -
-

- When the build is completed, you should see the generated - binaries and associated files in the j2sdk-image - directory in the output directory. - The default output directory is - build/platform, - where platform is one of -

- In particular, the - build/platform/j2sdk-image/bin - directory should contain executables for the - OpenJDK - tools and utilities. -

- You can test that the build completed properly by using the build - to run the various demos that you will find in the - build/platform/j2sdk-image/demo - directory. -

- The provided regression tests can be run with the jtreg - utility from - the jtreg site. -

- - -
- -

Environment/Make Variables

- -

-Some of the -environment or make variables (just called variables in this -document) that can impact the build are: - -

- -
- -
PATH
-
Typically you want to set the PATH to include: -
    -
  • The location of the GNU make binary
  • -
  • The location of the JDK 6 java - (see Bootstrap JDK)
  • -
  • The location of the C/C++ compilers - (see compilers)
  • -
  • The location or locations for the Unix command utilities - (e.g. /usr/bin)
  • -
-
- -
ARCH_DATA_MODEL
-
The ARCH_DATA_MODEL variable - is used to specify whether the build is to generate 32-bit or 64-bit - binaries. - The Solaris build supports either 32-bit or 64-bit builds, but - Windows and Linux will support only one, depending on the specific - OS being used. - Normally, setting this variable is only necessary on Solaris. - Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, - or to 64 for generating 64-bit binaries. -
- -
ALT_BOOTDIR
-
- The location of the bootstrap JDK installation. - See Bootstrap JDK for more information. - You should always install your own local Bootstrap JDK and - always set ALT_BOOTDIR explicitly. -
- -
ALT_OUTPUTDIR
-
- An override for specifying the (absolute) path of where the - build output is to go. - The default output directory will be build/platform. -
- -
ALT_COMPILER_PATH
-
- The location of the C/C++ compiler. - The default varies depending on the platform. -
- -
ALT_CACERTS_FILE
-
- The location of the cacerts file. - The default will refer to - jdk/src/share/lib/security/cacerts. -
- -
ALT_BINARY_PLUGS_PATH
-
- The location of the binary plugs installation. - See Binary Plugs for more information. - You should always have a local copy of a - recent Binary Plugs install image - and set this variable to that location. -
- -
ALT_CUPS_HEADERS_PATH
-
- The location of the CUPS header files. - See CUPS information for more information. - If this path does not exist the fallback path is - /usr/include. -
- - -
ALT_MOTIF_DIR
-
- The location of the Motif 2.1 headers and libraries. - See Motif for details. -
- -
ALT_FREETYPE_LIB_PATH
-
- The location of the FreeType shared library. - See FreeType information for details. -
- -
ALT_FREETYPE_HEADERS_PATH
-
- The location of the FreeType header files. - See FreeType information for details. -
- -
Windows specific:
-
+ +
+

Environment/Make Variables

+

+ Some of the + environment or make variables (just called variables in this + document) that can impact the build are: +

-
ALT_MSDEVTOOLS_PATH
+
PATH
+
Typically you want to set the PATH to include: +
    +
  • The location of the GNU make binary
  • +
  • The location of the Bootstrap JDK java + (see Bootstrap JDK)
  • +
  • The location of the C/C++ compilers + (see compilers)
  • +
  • The location or locations for the Unix command utilities + (e.g. /usr/bin)
  • +
+
+
MILESTONE
+
+ The milestone name for the build (e.g."beta"). + The default value is "internal". +
+
BUILD_NUMBER
+
+ The build number for the build (e.g. "b27"). + The default value is "b00". +
+
ARCH_DATA_MODEL
+
The ARCH_DATA_MODEL variable + is used to specify whether the build is to generate 32-bit or 64-bit + binaries. + The Solaris build supports either 32-bit or 64-bit builds, but + Windows and Linux will support only one, depending on the specific + OS being used. + Normally, setting this variable is only necessary on Solaris. + Set ARCH_DATA_MODEL to 32 for generating 32-bit binaries, + or to 64 for generating 64-bit binaries. +
+
ALT_BOOTDIR
+
+ The location of the bootstrap JDK installation. + See Bootstrap JDK for more information. + You should always install your own local Bootstrap JDK and + always set ALT_BOOTDIR explicitly. +
+
ALT_BINARY_PLUGS_PATH
+
+ The location of the binary plugs installation. + See Binary Plugs for more information. + You should always have a local copy of a + recent Binary Plugs install image + and set this variable to that location. +
+
ALT_JDK_IMPORT_PATH
- The location of the Microsoft Visual Studio .NET 2003 - tools 'bin' directory. - The default is usually derived from - ALT_COMPILER_PATH. + The location of a previously built JDK installation. + See Optional Import JDK for more information. +
+
ALT_OUTPUTDIR
+
+ An override for specifying the (absolute) path of where the + build output is to go. + The default output directory will be build/platform. +
+
ALT_COMPILER_PATH
+
+ The location of the C/C++ compiler. + The default varies depending on the platform. +
+
ALT_CACERTS_FILE
+
+ The location of the cacerts file. + The default will refer to + jdk/src/share/lib/security/cacerts.
- -
ALT_DXSDK_PATH
+
ALT_CUPS_HEADERS_PATH
+
+ The location of the CUPS header files. + See CUPS information for more information. + If this path does not exist the fallback path is + /usr/include. +
+ +
ALT_MOTIF_DIR
+
+ The location of the Motif 2.1 headers and libraries. + See Motif for details. +
+
ALT_FREETYPE_LIB_PATH
+
+ The location of the FreeType shared library. + See FreeType information for details. +
+
ALT_FREETYPE_HEADERS_PATH
+
+ The location of the FreeType header files. + See FreeType information for details. +
+
ALT_JDK_DEVTOOLS_PATH
+
+ The default root location of the devtools. + The default value is + $(ALT_SLASH_JAVA)/devtools. +
+
ALT_DEVTOOLS_PATH
- The location of the - Microsoft DirectX 9 SDK. - The default will be to try and use the DirectX environment - variable DXSDK_DIR, - failing that, look in C:/DXSDK. + The location of tools like the + zip and unzip + binaries, but might also contain the GNU make utility + (gmake). + So this area is a bit of a grab bag, especially on Windows. + The default value depends on the platform and + Unix Commands being used. + On Linux the default will be + $(ALT_JDK_DEVTOOLS_PATH)/linux/bin, + on Solaris + $(ALT_JDK_DEVTOOLS_PATH)/{sparc,i386}/bin, + on Windows with MKS + %SYSTEMDRIVE%/UTILS, + and on Windows with CYGWIN + /usr/bin.
- -
ALT_MSVCRT_DLL_PATH
+
ALT_UNIXCOMMAND_PATH
+
+ An override for specifying where the + Unix command set are located. + The default location varies depending on the platform, + "%SYSTEMDRIVE%/MKSNT" or + $(ROOTDIR) on Windows with MKS, otherwise it's + "/bin" or /usr/bin. +
+
ALT_UNIXCCS_PATH
+
+ Solaris only: + An override for specifying where the Unix CCS + command set are located. + The default location is /usr/ccs/bin +
+
ALT_USRBIN_PATH
+
+ An override for specifying where the + Unix /usr/bin commands are located. You usually do not need + to set this variable: the default location is /usr/bin) +
+
ALT_SLASHJAVA
+
+ The default root location for many of the ALT path locations + of the following ALT variables. + The default value is + "/java" on Solaris and Linux, + "J:" on Windows. +
+
ALT_BUILD_JDK_IMPORT_PATH
- The location of the - MSVCRT.DLL. + These are useful in managing builds on multiple platforms. + The default network location for all of the import JDK images + for all platforms. + If ALT_JDK_IMPORT_PATH + is not set, this directory will be used and should contain + the following directories: + solaris-sparc, + solaris-i586, + solaris-sparcv9, + solaris-amd64, + linux-i586, + linux-amd64, + windows-i586, + and + windows-amd64. + Where each of these directories contain the import JDK image + for that platform.
- -
ALT_MSVCR71_DLL_PATH
+
ALT_BUILD_BINARY_PLUGS_PATH
+
+ These are useful in managing builds on multiple platforms. + The default network location for all of the binary plug images + for all platforms. + If ALT_BINARY_PLUGS_PATH + is not set, this directory will be used and should contain + the following directories: + solaris-sparc, + solaris-i586, + solaris-sparcv9, + solaris-amd64, + linux-i586, + linux-amd64, + windows-i586, + and + windows-amd64. + Where each of these directories contain the binary plugs image + for that platform. +
+
Windows specific:
- i586 only: - The location of the - MSVCR71.DLL. +
+
ALT_MSDEVTOOLS_PATH
+
+ The location of the Microsoft Visual Studio .NET 2003 + tools 'bin' directory. + The default is usually derived from + ALT_COMPILER_PATH. +
+
ALT_DXSDK_PATH
+
+ The location of the + Microsoft DirectX 9 SDK. + The default will be to try and use the DirectX environment + variable DXSDK_DIR, + failing that, look in C:/DXSDK. +
+
ALT_MSVCRT_DLL_PATH
+
+ The location of the + MSVCRT.DLL. +
+
ALT_MSVCR71_DLL_PATH
+
+ i586 only: + The location of the + MSVCR71.DLL. +
+
-
- -
-
- - -
- -

Troubleshooting

- -
-

- A build can fail for any number of reasons. - Most failures - are a result of trying to build in an environment in which all the - pre-build requirements have not been met. - The first step in - troubleshooting a build failure is to recheck that you have satisfied - all the pre-build requirements for your platform. - Look for the check list of the platform you are building on in the - Table of Contents. - -

- You can validate your build environment by using the sanity - target. - Any errors listed - will stop the build from starting, and any warnings may result in - a flawed product build. - We strongly encourage you to evaluate every - sanity check warning and fix it if required, before you proceed - further with your build. - -

- Some of the more common problems with builds are briefly described - below, with suggestions for remedies. - -

-
- -
+ + +
+

Troubleshooting

+
+ A build can fail for any number of reasons. + Most failures + are a result of trying to build in an environment in which all the + pre-build requirements have not been met. + The first step in + troubleshooting a build failure is to recheck that you have satisfied + all the pre-build requirements for your platform. + Look for the check list of the platform you are building on in the + Table of Contents. +

+ You can validate your build environment by using the sanity + target. + Any errors listed + will stop the build from starting, and any warnings may result in + a flawed product build. + We strongly encourage you to evaluate every + sanity check warning and fix it if required, before you proceed + further with your build. +

+ Some of the more common problems with builds are briefly described + below, with suggestions for remedies. +

+
+
+ + diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/com/sun/crypto/provider/Makefile --- a/jdk/make/com/sun/crypto/provider/Makefile Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/com/sun/crypto/provider/Makefile Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,8 +87,7 @@ # sign Alias for sign-jar # sign-jar Builds/signs sunjce_provider.jar (no install) # -# obfus Builds/obfuscates/signs/installs -# sunjce_provider.jar +# obfus Builds/obfuscates/signs sunjce_provider.jar # # release Builds all targets in preparation # for workspace integration. @@ -101,8 +100,25 @@ BUILDDIR = ../../../.. PACKAGE = com.sun.crypto.provider PRODUCT = sun + +# +# The following is for when we need to do postprocessing +# (signing/obfuscation) against a read-only build. If the OUTPUTDIR +# isn't writable, the build currently crashes out. +# +ifndef OPENJDK + ifdef ALT_JCE_BUILD_DIR + # ===================================================== + # Where to place the output, in case we're building from a read-only + # build area. (e.g. a release engineering build.) + JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR} + IGNORE_WRITABLE_OUTPUTDIR_TEST=true + else + JCE_BUILD_DIR=${TEMPDIR} + endif +endif + include $(BUILDDIR)/common/Defs.gmk -include $(BUILDDIR)/javax/crypto/Defs-jce.gmk # # Location for the newly built classfiles. @@ -147,6 +163,8 @@ # UNSIGNED_DIR = $(TEMPDIR)/unsigned +include $(BUILDDIR)/javax/crypto/Defs-jce.gmk + # ===================================================== # Build the unsigned sunjce_provider.jar file. @@ -184,44 +202,66 @@ # Sign the provider jar file. Not needed for OpenJDK. # -SIGNED_DIR = $(TEMPDIR)/signed +SIGNED_DIR = $(JCE_BUILD_DIR)/signed sign: sign-jar sign-jar: $(SIGNED_DIR)/sunjce_provider.jar +ifndef ALT_JCE_BUILD_DIR $(SIGNED_DIR)/sunjce_provider.jar: $(UNSIGNED_DIR)/sunjce_provider.jar - $(sign-file) +else +# +# We have to remove the build dependency, otherwise, we'll try to rebuild it +# which we can't do on a read-only filesystem. +# +$(SIGNED_DIR)/sunjce_provider.jar: + @if [ ! -r $(UNSIGNED_DIR)/sunjce_provider.jar ] ; then \ + $(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunjce_provider.jar"; \ + exit 1; \ + fi +endif + $(call sign-file, $(UNSIGNED_DIR)/sunjce_provider.jar) # ===================================================== # Obfuscate/sign/install the JDK build. Not needed for OpenJDK. # -OBFUS_DIR = $(TEMPDIR)/obfus +OBFUS_DIR = $(JCE_BUILD_DIR)/obfus/sunjce CLOSED_DIR = $(BUILDDIR)/closed/com/sun/crypto/provider obfus: $(OBFUS_DIR)/sunjce_provider.jar $(release-warning) -$(OBFUS_DIR)/sunjce_provider.jar: build-jar $(JCE_MANIFEST_FILE) +ifndef ALT_JCE_BUILD_DIR +$(OBFUS_DIR)/sunjce_provider.jar: build-jar $(JCE_MANIFEST_FILE) \ + $(OBFUS_DIR)/sunjce.dox +else +$(OBFUS_DIR)/sunjce_provider.jar: $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/sunjce.dox + @if [ ! -d $(CLASSDESTDIR) ] ; then \ + $(ECHO) "Couldn't find $(CLASSDESTDIR)"; \ + exit 1; \ + fi +endif + @$(ECHO) ">>>Obfuscating SunJCE Provider..." $(presign) $(preobfus) - @$(ECHO) ">>>Obfuscating Sun JCE Provider..." $(prep-target) $(CD) $(OBFUS_DIR); \ - $(OBFUSCATOR) -fv \ - $(CURRENT_DIRECTORY)/$(CLOSED_DIR)/obfus/sunjce.dox + $(OBFUSCATOR) -fv sunjce.dox @$(CD) $(OBFUS_DIR); $(java-vm-cleanup) $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ -C $(OBFUS_DIR)/build com \ $(JAR_JFLAGS) $(sign-target) - $(MKDIR) -p $(dir $(JAR_DESTFILE)) - $(RM) $(JAR_DESTFILE) - $(CP) $@ $(JAR_DESTFILE) @$(java-vm-cleanup) +$(OBFUS_DIR)/sunjce.dox: $(CLOSED_DIR)/obfus/sunjce.dox + @$(ECHO) ">>>Creating sunjce.dox" + $(prep-target) + $(SED) "s:@@TEMPDIR@@:$(ABS_TEMPDIR):" $< > $@ + # # The current obfuscator has a limitation in that it currently only # supports up to v49 class file format. Force v49 classfiles in our @@ -235,9 +275,9 @@ # release: $(OBFUS_DIR)/sunjce_provider.jar - $(RM) $(RELEASE_DIR)/sunjce_provider.jar - $(MKDIR) -p $(RELEASE_DIR) - $(CP) $(OBFUS_DIR)/sunjce_provider.jar $(RELEASE_DIR) + $(RM) $(JCE_BUILD_DIR)/release/sunjce_provider.jar + $(MKDIR) -p $(JCE_BUILD_DIR)/release + $(CP) $(OBFUS_DIR)/sunjce_provider.jar $(JCE_BUILD_DIR)/release $(release-warning) endif # OPENJDK @@ -275,7 +315,7 @@ # clobber clean:: - $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) + $(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR) .PHONY: build-jar jar install-jar ifndef OPENJDK diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/common/Release.gmk --- a/jdk/make/common/Release.gmk Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/common/Release.gmk Fri May 30 00:00:00 2008 +0200 @@ -910,14 +910,6 @@ done ifeq ($(PLATFORM), windows) @# - @# Audio soundbank - Bug# 4236400 - @# Windows only: adding audio files to JDK's jre/lib directory. - @# - ($(CD) $(LIBDIR) && $(TAR) cf - \ - `$(FIND) audio -depth -print`) | \ - ($(CD) $(JDK_IMAGE_DIR)/jre/lib && $(TAR) xf -) - @# - @# @# lib/ @# $(CP) $(LIBDIR)/$(LIB_PREFIX)jvm.$(LIB_SUFFIX) $(JDK_IMAGE_DIR)/lib diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/common/internal/BinaryPlugs.gmk --- a/jdk/make/common/internal/BinaryPlugs.gmk Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/common/internal/BinaryPlugs.gmk Fri May 30 00:00:00 2008 +0200 @@ -29,9 +29,7 @@ # Names of native shared libraries -PLUG_JSOUND_LIBRARY=$(LIB_PREFIX)jsoundhs.$(LIBRARY_SUFFIX) -PLUG_LIBRARY_NAMES = \ - $(PLUG_JSOUND_LIBRARY) +PLUG_LIBRARY_NAMES= # Sub-directory where native shared libraries are located (e.g. jre/bin or...) @@ -74,62 +72,10 @@ com/sun/jmx/snmp/daemon/SnmpTimerServer.class \ com/sun/jmx/snmp/daemon/WaitQ.class -PLUG_SOUND_CLASS_NAMES = \ -com/sun/media/sound/AbstractPlayer.class \ -com/sun/media/sound/CircularBuffer.class \ -com/sun/media/sound/HeadspaceInstrument.class \ -com/sun/media/sound/HeadspaceMixer\$$1.class \ -com/sun/media/sound/HeadspaceMixer\$$MidiLine.class \ -com/sun/media/sound/HeadspaceMixer\$$MidiLineInfo.class \ -com/sun/media/sound/HeadspaceMixer\$$MixerInfo.class \ -com/sun/media/sound/HeadspaceMixer\$$MixerReverbControl\$$MixerReverbType.class \ -com/sun/media/sound/HeadspaceMixer\$$MixerReverbControl.class \ -com/sun/media/sound/HeadspaceMixer.class \ -com/sun/media/sound/HeadspaceMixerProvider.class \ -com/sun/media/sound/HeadspaceSample.class \ -com/sun/media/sound/HeadspaceSoundbank.class \ -com/sun/media/sound/HsbParser.class \ -com/sun/media/sound/MixerClip\$$1.class \ -com/sun/media/sound/MixerClip\$$MixerClipApplyReverbControl.class \ -com/sun/media/sound/MixerClip\$$MixerClipGainControl.class \ -com/sun/media/sound/MixerClip\$$MixerClipMuteControl.class \ -com/sun/media/sound/MixerClip\$$MixerClipPanControl.class \ -com/sun/media/sound/MixerClip\$$MixerClipSampleRateControl.class \ -com/sun/media/sound/MixerClip.class \ -com/sun/media/sound/MixerMidiChannel.class \ -com/sun/media/sound/MixerSequencer\$$1.class \ -com/sun/media/sound/MixerSequencer\$$ControllerVectorElement.class \ -com/sun/media/sound/MixerSequencer\$$MixerSequencerInfo.class \ -com/sun/media/sound/MixerSequencer\$$RecordingTrack.class \ -com/sun/media/sound/MixerSequencer.class \ -com/sun/media/sound/MixerSequencerProvider.class \ -com/sun/media/sound/MixerSourceLine\$$1.class \ -com/sun/media/sound/MixerSourceLine\$$MixerSourceLineApplyReverbControl.class \ -com/sun/media/sound/MixerSourceLine\$$MixerSourceLineGainControl.class \ -com/sun/media/sound/MixerSourceLine\$$MixerSourceLineMuteControl.class \ -com/sun/media/sound/MixerSourceLine\$$MixerSourceLinePanControl.class \ -com/sun/media/sound/MixerSourceLine\$$MixerSourceLineSampleRateControl.class \ -com/sun/media/sound/MixerSourceLine.class \ -com/sun/media/sound/MixerSynth\$$1.class \ -com/sun/media/sound/MixerSynth\$$MixerSynthInfo.class \ -com/sun/media/sound/MixerSynth\$$SynthReceiver.class \ -com/sun/media/sound/MixerSynth.class \ -com/sun/media/sound/MixerSynthProvider.class \ -com/sun/media/sound/MixerThread.class \ -com/sun/media/sound/RmfFileReader.class \ -com/sun/media/sound/SimpleInputDevice\$$1.class \ -com/sun/media/sound/SimpleInputDevice\$$InputDeviceDataLine.class \ -com/sun/media/sound/SimpleInputDevice\$$InputDevicePort.class \ -com/sun/media/sound/SimpleInputDevice\$$InputDevicePortInfo.class \ -com/sun/media/sound/SimpleInputDevice.class \ -com/sun/media/sound/SimpleInputDeviceProvider\$$1.class \ -com/sun/media/sound/SimpleInputDeviceProvider\$$InputDeviceInfo.class \ -com/sun/media/sound/SimpleInputDeviceProvider.class - # Class list temp files (used by both import and export of plugs) PLUG_TEMPDIR=$(ABS_TEMPDIR)/plugs -PLUG_CLASS_AREAS = jmf sound +PLUG_CLASS_AREAS = jmf PLUG_CLISTS = $(PLUG_CLASS_AREAS:%=$(PLUG_TEMPDIR)/%.clist) # Create jargs file command @@ -147,18 +93,11 @@ @for i in $(PLUG_JMF_CLASS_NAMES) ; do \ $(ECHO) "$$i" >> $@; \ done -$(PLUG_TEMPDIR)/sound.clist: - @$(prep-target) - @for i in $(PLUG_SOUND_CLASS_NAMES) ; do \ - $(ECHO) "$$i" >> $@ ; \ - done $(PLUG_TEMPDIR)/all.clist: $(PLUG_CLISTS) @$(prep-target) $(CAT) $(PLUG_CLISTS) > $@ $(PLUG_TEMPDIR)/jmf.jargs: $(PLUG_TEMPDIR)/jmf.clist $(plug-create-jargs) -$(PLUG_TEMPDIR)/sound.jargs: $(PLUG_TEMPDIR)/sound.clist - $(plug-create-jargs) $(PLUG_TEMPDIR)/all.jargs: $(PLUG_TEMPDIR)/all.clist $(plug-create-jargs) @@ -172,8 +111,6 @@ PLUG_IMPORT_DIR=$(BINARY_PLUGS_PATH) PLUG_IMPORT_JARFILE=$(BINARY_PLUGS_JARFILE) -PLUG_IMPORT_JSOUND_LIBRARY=\ - $(PLUG_IMPORT_DIR)/$(PLUG_LOCATION_SUBDIR)/$(PLUG_JSOUND_LIBRARY) # Whether the import does anything: ifeq ($(IMPORT_BINARY_PLUGS),true) @@ -196,8 +133,6 @@ else # IMPORT_BINARY_PLUGS PLUG_IMPORT_JARFILE= -PLUG_IMPORT_JSOUND_LIBRARY= -PLUG_JSOUND_LIBRARY= PLUG_LIBRARY_NAMES= # Import file command @@ -218,24 +153,11 @@ import-binary-plug-jmf-classes: $(PLUG_IMPORT_JARFILE) $(PLUG_TEMPDIR)/jmf.clist $(call import-binary-plug-classes,$(PLUG_TEMPDIR)/jmf.clist) -import-binary-plug-sound-classes: $(PLUG_IMPORT_JARFILE) $(PLUG_TEMPDIR)/sound.clist - $(call import-binary-plug-classes,$(PLUG_TEMPDIR)/sound.clist) # Import all classes from the jar file import-binary-plug-jar: \ - import-binary-plug-jmf-classes \ - import-binary-plug-sound-classes - -# Import native libraries - -$(LIB_LOCATION)/$(PLUG_JSOUND_LIBRARY): $(PLUG_IMPORT_JSOUND_LIBRARY) - $(import-binary-plug-file) - -# Rules only used by lower level makefiles - -import-binary-plug-jsound-library: \ - $(LIB_LOCATION)/$(PLUG_JSOUND_LIBRARY) + import-binary-plug-jmf-classes # Binary plug start/complete messages @@ -265,9 +187,7 @@ import-binary-plugs-libs \ import-binary-plugs \ import-binary-plug-jar \ - import-binary-plug-jmf-classes \ - import-binary-plug-sound-classes \ - import-binary-plug-jsound-library + import-binary-plug-jmf-classes else # !OPENJDK @@ -303,12 +223,6 @@ $(BOOT_JAR_CMD) cf $@ @$(PLUG_TEMPDIR)/all.jargs export-binary-plugs-jar: $(PLUG_EXPORT_JARFILE) -# Export native libraries - -$(PLUG_EXPORT_DIR)/$(PLUG_LOCATION_SUBDIR)/$(PLUG_JSOUND_LIBRARY): \ - $(LIB_LOCATION)/$(PLUG_JSOUND_LIBRARY) - $(export-binary-plug-file) - # Export binary plug start/complete messages export-binary-plugs-started: diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/common/shared/Defs.gmk --- a/jdk/make/common/shared/Defs.gmk Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/common/shared/Defs.gmk Fri May 30 00:00:00 2008 +0200 @@ -439,12 +439,23 @@ endif _POSSIBLE_OUTPUTDIR =$(_OUTPUTDIR) endif + +# +# When signing the JCE framework and provider, we could be using built +# bits on a read-only filesystem. If so, this test will fail and crash +# the build. +# +ifndef IGNORE_WRITABLE_OUTPUTDIR_TEST _create_outputdir1:=$(shell mkdir -p $(_POSSIBLE_OUTPUTDIR) > $(DEV_NULL) 2>&1) OUTPUTDIR:=$(call WriteDirExists,$(_POSSIBLE_OUTPUTDIR),$(_BACKUP_OUTPUTDIR)) _create_outputdir2:=$(shell mkdir -p $(OUTPUTDIR) > $(DEV_NULL) 2>&1) ifeq "$(OUTPUTDIR)" "$(_BACKUP_OUTPUTDIR)" _outputdir_warning:=$(warning "WARNING: OUTPUTDIR '$(_POSSIBLE_OUTPUTDIR)' not writable, will use '$(_BACKUP_OUTPUTDIR)'") endif +else +OUTPUTDIR:=$(_POSSIBLE_OUTPUTDIR) +endif + OUTPUTDIR:=$(call AltCheckSpaces,OUTPUTDIR) OUTPUTDIR:=$(call AltCheckValue,OUTPUTDIR) diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/crypto/Defs-jce.gmk --- a/jdk/make/javax/crypto/Defs-jce.gmk Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/javax/crypto/Defs-jce.gmk Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ JCE_MANIFEST_FILE = $(TEMPDIR)/manifest.mf $(JCE_MANIFEST_FILE): $(MAINMANIFEST) $(prep-target) - ( $(SED) "s/@@RELEASE@@/$(RELEASE)/" $(MAINMANIFEST); \ + ( $(SED) "s/@@RELEASE@@/$(RELEASE)/" $<; \ $(ECHO) "Extension-Name: javax.crypto"; \ $(ECHO) "Implementation-Vendor-Id: com.sun"; ) > $@ @@ -75,6 +75,7 @@ define sign-target $(BOOT_JARSIGNER_CMD) -keystore $(SIGNING_KEYSTORE) \ $@ $(SIGNING_ALIAS) < $(SIGNING_PASSPHRASE) + @$(java-vm-cleanup) @$(ECHO) "\nJar codesigning finished." endef @@ -88,13 +89,15 @@ endef # -# Convenience macro for steps needed to sign a jar file. +# Convenience macros for signing a jar file. +# +# Call through $(call sign-file, target file) # define sign-file $(presign) - $(install-file) + $(prep-target) + $(CP) $1 $@ $(sign-target) - @$(java-vm-cleanup) endef # diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/crypto/Makefile --- a/jdk/make/javax/crypto/Makefile Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/javax/crypto/Makefile Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -96,7 +96,7 @@ # sign-jar Builds/signs jce.jar file (no install) # sign-policy Builds/signs policy files (no install) # -# obfus Builds/obfuscates/signs/installs jce.jar +# obfus Builds/obfuscates/signs jce.jar # # release Builds all targets in preparation # for workspace integration. @@ -110,8 +110,24 @@ PACKAGE = javax.crypto PRODUCT = sun +# +# The following is for when we need to do postprocessing +# (signing/obfuscation) against a read-only build. If the OUTPUTDIR +# isn't writable, the build currently crashes out. +# +ifndef OPENJDK + ifdef ALT_JCE_BUILD_DIR + # ===================================================== + # Where to place the output, in case we're building from a read-only + # build area. (e.g. a release engineering build.) + JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR} + IGNORE_WRITABLE_OUTPUTDIR_TEST=true + else + JCE_BUILD_DIR=${TEMPDIR} + endif +endif + include $(BUILDDIR)/common/Defs.gmk -include Defs-jce.gmk # # Location for the newly built classfiles. @@ -158,6 +174,8 @@ # UNSIGNED_DIR = $(TEMPDIR)/unsigned +include Defs-jce.gmk + # ===================================================== # Build the unsigned jce.jar file. Signing/obfuscation comes later. @@ -299,7 +317,7 @@ # Sign the various jar files. Not needed for OpenJDK. # -SIGNED_DIR = $(TEMPDIR)/signed +SIGNED_DIR = $(JCE_BUILD_DIR)/signed SIGNED_POLICY_BUILDDIR = $(SIGNED_DIR)/policy SIGNED_POLICY_FILES = \ @@ -312,61 +330,87 @@ sign-policy: $(SIGNED_POLICY_FILES) +ifndef ALT_JCE_BUILD_DIR $(SIGNED_DIR)/jce.jar: $(UNSIGNED_DIR)/jce.jar - $(sign-file) +else +# +# We have to remove the build dependency, otherwise, we'll try to rebuild it +# which we can't do on a read-only filesystem. +# +$(SIGNED_DIR)/jce.jar: + @if [ ! -r $(UNSIGNED_DIR)/jce.jar ] ; then \ + $(ECHO) "Couldn't find $(UNSIGNED_DIR)/jce.jar"; \ + exit 1; \ + fi +endif + $(call sign-file, $(UNSIGNED_DIR)/jce.jar) $(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar: \ -$(UNSIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar - $(sign-file) + $(UNSIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar + $(call sign-file, $<) $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar: \ -$(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar - $(sign-file) + $(UNSIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar + $(call sign-file, $<) $(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar: \ -$(UNSIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar - $(sign-file) + $(UNSIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar + $(call sign-file, $<) $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar: \ -$(UNSIGNED_POLICY_BUILDDIR)/limited/local_policy.jar - $(sign-file) + $(UNSIGNED_POLICY_BUILDDIR)/limited/local_policy.jar + $(call sign-file, $<) # ===================================================== # Obfuscate/sign/install the JDK build. Not needed for OpenJDK. # -OBFUS_DIR = $(TEMPDIR)/obfus +OBFUS_DIR = $(JCE_BUILD_DIR)/obfus/jce CLOSED_DIR = $(BUILDDIR)/closed/javax/crypto obfus: $(OBFUS_DIR)/jce.jar $(release-warning) -$(OBFUS_DIR)/jce.jar: build-jar $(JCE_MANIFEST_FILE) +ifndef ALT_JCE_BUILD_DIR +$(OBFUS_DIR)/jce.jar: build-jar $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/framework.dox +else +# +# We have to remove the build dependency, otherwise, we'll try to rebuild it +# which we can't do on a read-only filesystem. +# +$(OBFUS_DIR)/jce.jar: $(JCE_MANIFEST_FILE) $(OBFUS_DIR)/framework.dox + @if [ ! -d $(CLASSDESTDIR) ] ; then \ + $(ECHO) "Couldn't find $(CLASSDESTDIR)"; \ + exit 1; \ + fi +endif + @$(ECHO) ">>>Obfuscating JCE framework..." $(presign) $(preobfus) - @$(ECHO) ">>>Obfuscating JCE framework..." $(prep-target) $(CD) $(OBFUS_DIR); \ - $(OBFUSCATOR) -fv \ - $(CURRENT_DIRECTORY)/$(CLOSED_DIR)/obfus/framework.dox + $(OBFUSCATOR) -fv framework.dox @$(CD) $(OBFUS_DIR); $(java-vm-cleanup) + @# @# The sun.security.internal classes are currently not obfuscated @# due to an obfus problem. Manually copy them to the build directory @# so that they are included in the jce.jar file. + @# $(CP) -r $(CLASSDESTDIR)/sun $(OBFUS_DIR)/build - $(RM) $(UNSIGNED_DIR)/jce.jar $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ \ -C $(OBFUS_DIR)/build javax \ -C $(OBFUS_DIR)/build sun \ $(JAR_JFLAGS) $(sign-target) - $(MKDIR) -p $(dir $(JAR_DESTFILE)) - $(RM) $(JAR_DESTFILE) - $(CP) $@ $(JAR_DESTFILE) @$(java-vm-cleanup) +$(OBFUS_DIR)/framework.dox: $(CLOSED_DIR)/obfus/framework.dox + @$(ECHO) ">>>Creating framework.dox" + $(prep-target) + $(SED) "s:@@TEMPDIR@@:$(ABS_TEMPDIR):" $< > $@ + # # The current obfuscator has a limitation in that it currently only # supports up to v49 class file format. Force v49 classfiles in our @@ -380,26 +424,27 @@ # unlimited policy file distribution, etc. # -release: $(OBFUS_DIR)/jce.jar sign-policy +release: $(OBFUS_DIR)/jce.jar sign-policy $(CLOSED_DIR)/doc/COPYRIGHT.html \ + $(CLOSED_DIR)/doc/README.txt $(RM) -r \ - $(RELEASE_DIR)/UnlimitedJCEPolicy \ - $(RELEASE_DIR)/jce.jar \ - $(RELEASE_DIR)/US_export_policy.jar \ - $(RELEASE_DIR)/local_policy.jar \ - $(RELEASE_DIR)/UnlimitedJCEPolicy.zip - $(MKDIR) -p $(RELEASE_DIR)/UnlimitedJCEPolicy - $(CP) $(OBFUS_DIR)/jce.jar $(RELEASE_DIR) - $(CP) -r \ - $(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar \ - $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar \ - $(RELEASE_DIR) + $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy \ + $(JCE_BUILD_DIR)/release/jce.jar \ + $(JCE_BUILD_DIR)/release/US_export_policy.jar \ + $(JCE_BUILD_DIR)/release/local_policy.jar \ + $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy.zip + $(MKDIR) -p $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy + $(CP) $(OBFUS_DIR)/jce.jar $(JCE_BUILD_DIR)/release + $(CP) \ + $(SIGNED_POLICY_BUILDDIR)/limited/US_export_policy.jar \ + $(SIGNED_POLICY_BUILDDIR)/limited/local_policy.jar \ + $(JCE_BUILD_DIR)/release $(CP) \ $(SIGNED_POLICY_BUILDDIR)/unlimited/US_export_policy.jar \ - $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \ - $(RELEASE_DIR)/UnlimitedJCEPolicy - $(CP) $(CLOSED_DIR)/doc/COPYRIGHT.html \ - $(CLOSED_DIR)/doc/README.txt $(RELEASE_DIR)/UnlimitedJCEPolicy - cd $(RELEASE_DIR) ; \ + $(SIGNED_POLICY_BUILDDIR)/unlimited/local_policy.jar \ + $(CLOSED_DIR)/doc/COPYRIGHT.html \ + $(CLOSED_DIR)/doc/README.txt \ + $(JCE_BUILD_DIR)/release/UnlimitedJCEPolicy + cd $(JCE_BUILD_DIR)/release ; \ $(ZIPEXE) -qr UnlimitedJCEPolicy.zip UnlimitedJCEPolicy $(release-warning) @@ -478,7 +523,8 @@ clobber clean:: $(RM) -r $(JAR_DESTFILE) $(POLICY_DESTDIR)/US_export_policy.jar \ - $(POLICY_DESTDIR)/local_policy.jar $(DELETE_DIRS) $(TEMPDIR) + $(POLICY_DESTDIR)/local_policy.jar $(DELETE_DIRS) $(TEMPDIR) \ + $(JCE_BUILD_DIR) .PHONY: build-jar jar build-policy unlimited limited install-jar \ install-limited install-unlimited diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/sound/Makefile --- a/jdk/make/javax/sound/Makefile Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/javax/sound/Makefile Fri May 30 00:00:00 2008 +0200 @@ -54,23 +54,6 @@ AUTO_FILES_JAVA_DIRS = javax/sound com/sun/media/sound # -# Specific to OpenJDK building -# -ifdef OPENJDK - - # skip closed lib if the flag is set - ifeq ($(IMPORT_BINARY_PLUGS),true) - -# copy closed .class files -build: import-binary-plug-sound-classes - -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk - - endif # IMPORT_BINARY_PLUGS - -endif # OPENJDK - -# # Files that just need cp. # SERVICEDIR = $(CLASSBINDIR)/META-INF/services @@ -84,13 +67,11 @@ $(SERVICEDIR)/javax.sound.sampled.spi.AudioFileReader \ $(SERVICEDIR)/javax.sound.sampled.spi.FormatConversionProvider \ $(SERVICEDIR)/javax.sound.sampled.spi.MixerProvider \ - $(LIBDIR)/audio/soundbank.gm \ $(LIBDIR)/sound.properties FILES_mkdirs = \ $(CLASSBINDIR)/META-INF \ - $(CLASSBINDIR)/META-INF/services \ - $(LIBDIR)/audio + $(CLASSBINDIR)/META-INF/services FILES_copydirs = \ $(CLASSBINDIR) \ @@ -101,17 +82,6 @@ # -# add "closed" library -# -ifdef OPENJDK - ifeq ($(IMPORT_BINARY_PLUGS),true) - SUBDIRS += jsoundhs - endif # IMPORT_BINARY_PLUGS -else - SUBDIRS += jsoundhs -endif # OPENJDK - -# # system dependent flags # ifeq ($(PLATFORM), windows) diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/sound/jsoundhs/FILES.gmk --- a/jdk/make/javax/sound/jsoundhs/FILES.gmk Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -# -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -FILES_c = \ - Utilities.c \ - MixerThread.c \ - HeadspaceMixer.c \ - MixerClip.c \ - MixerSourceLine.c \ - SimpleInputDevice.c \ - SimpleInputDeviceProvider.c \ - HeadspaceSoundbank.c \ - MixerMidiChannel.c \ - AbstractPlayer.c \ - MixerSequencer.c \ - MixerSynth.c - -FILES_engine = \ - DriverTools.c \ - GenAudioCaptureStreams.c \ - GenAudioStreams.c \ - GenOutput.c \ - GenPatch.c \ - GenReverb.c \ - GenSample.c \ - GenSeq.c \ - GenSetup.c \ - GenSong.c \ - GenSynth.c \ - GenSynthFilters.c \ - GenSynthInterp2.c \ - GenSynthResample.c \ - NewNewLZSS.c \ - SampleTools.c \ - SMOD_Volume_Scaler.c \ - X_API.c \ - X_Decompress.c \ - X_IMA.c \ - GenFiltersReverb.c \ - GenInterp2Reverb.c \ - GenSoundFiles.c \ - SincResample.c - -FILES_solaris = \ - HAE_API_SolarisOS.c \ - HAE_API_SolarisOS_Capture.c - -FILES_linux = \ - HAE_API_LinuxOS.c \ - HAE_API_LinuxOS_Capture.c - -FILES_windows = \ - HAE_API_WinOS.c \ - HAE_API_WinOS_Capture.c \ - HAE_API_WinOS_Synth.c - -FILES_export = \ - com/sun/media/sound/AbstractPlayer.java \ - com/sun/media/sound/HeadspaceMixer.java \ - com/sun/media/sound/HeadspaceSoundbank.java \ - com/sun/media/sound/MixerClip.java \ - com/sun/media/sound/MixerMidiChannel.java \ - com/sun/media/sound/MixerSequencer.java \ - com/sun/media/sound/MixerSourceLine.java \ - com/sun/media/sound/MixerSynth.java \ - com/sun/media/sound/MixerThread.java \ - com/sun/media/sound/SimpleInputDevice.java \ - com/sun/media/sound/SimpleInputDeviceProvider.java - diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/sound/jsoundhs/Makefile --- a/jdk/make/javax/sound/jsoundhs/Makefile Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -# -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -BUILDDIR = ../../.. -PACKAGE = javax.sound -LIBRARY = jsoundhs -PRODUCT = sun -CPLUSPLUSLIBRARY = true -include $(BUILDDIR)/common/Defs.gmk - -# this Makefile compiles "closed" JavaSound library - -ifdef OPENJDK - -# precompiled lib will be copied by the rules in Library.gmk instead of compiling. -USE_BINARY_PLUG_LIBRARY=true - -build: import-binary-plug-jsound-library - -include $(BUILDDIR)/common/internal/BinaryPlugs.gmk - -else # OPENJDK - -# include defines for sound -include ../SoundDefs.gmk - -# -# Add use of mapfile -# -FILES_m = mapfile-vers -include $(BUILDDIR)/common/Mapfile-vers.gmk - -# -# Files -# -include FILES.gmk - -FILES_c += $(FILES_engine) $(FILES_$(PLATFORM)) - -# -# Extra cc/linker flags. -# -# flags needed for all platforms -CPPFLAGS += \ - -DJAVA_SOUND -DJAVA_THREAD \ - -I$(CLOSED_SHARE_SRC)/native/com/sun/media/sound \ - -I$(CLOSED_SHARE_SRC)/native/com/sun/media/sound/engine - -# system dependent flags -ifeq ($(PLATFORM), windows) - CPPFLAGS += -DUSE_DIRECTSOUND=0 \ - -DUSE_EXTERNAL_SYNTH=TRUE - LDLIBS += winmm.lib -endif # PLATFORM windows - -ifeq ($(PLATFORM), linux) -endif # PLATFORM linux - -ifeq ($(PLATFORM), solaris) -endif # PLATFORM solaris - - -# -# Add to the ambient VPATH. -# -vpath %.c $(CLOSED_SHARE_SRC)/native/com/sun/media/sound -vpath %.c $(CLOSED_SHARE_SRC)/native/com/sun/media/sound/engine -vpath %.c $(CLOSED_PLATFORM_SRC)/native/com/sun/media/sound/engine - - -endif # OPENJDK - - -# -# Include rules -# -include $(BUILDDIR)/common/Library.gmk - diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/javax/sound/jsoundhs/mapfile-vers --- a/jdk/make/javax/sound/jsoundhs/mapfile-vers Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -# -# Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Sun designates this -# particular file as subject to the "Classpath" exception as provided -# by Sun in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -# CA 95054 USA or visit www.sun.com if you need additional information or -# have any questions. -# - -# Define library interface. - -SUNWprivate_1.1 { - global: - Java_com_sun_media_sound_AbstractPlayer_nAddReceiver; - Java_com_sun_media_sound_AbstractPlayer_nClose; - Java_com_sun_media_sound_AbstractPlayer_nLoadInstrument; - Java_com_sun_media_sound_AbstractPlayer_nRemapInstrument; - Java_com_sun_media_sound_AbstractPlayer_nRemoveReceiver; - Java_com_sun_media_sound_AbstractPlayer_nUnloadInstrument; - Java_com_sun_media_sound_HeadspaceMixer_nAllocateVoices; - Java_com_sun_media_sound_HeadspaceMixer_nCloseMixer; - Java_com_sun_media_sound_HeadspaceMixer_nCreateLinkedStreams; - Java_com_sun_media_sound_HeadspaceMixer_nDrain; - Java_com_sun_media_sound_HeadspaceMixer_nFlush; - Java_com_sun_media_sound_HeadspaceMixer_nGetCpuLoad; - Java_com_sun_media_sound_HeadspaceMixer_nGetDefaultBufferSize; - Java_com_sun_media_sound_HeadspaceMixer_nGetLevel; - Java_com_sun_media_sound_HeadspaceMixer_nGetPosition; - Java_com_sun_media_sound_HeadspaceMixer_nGetTotalVoices; - Java_com_sun_media_sound_HeadspaceMixer_nOpenMixer; - Java_com_sun_media_sound_HeadspaceMixer_nPause; - Java_com_sun_media_sound_HeadspaceMixer_nResume; - Java_com_sun_media_sound_HeadspaceMixer_nSetInterpolation; - Java_com_sun_media_sound_HeadspaceMixer_nSetMixerFormat; - Java_com_sun_media_sound_HeadspaceMixer_nSetMixLevel; - Java_com_sun_media_sound_HeadspaceMixer_nSetReverb; - Java_com_sun_media_sound_HeadspaceMixer_nStartLinkedStreams; - Java_com_sun_media_sound_HeadspaceMixer_nStopLinkedStreams; - Java_com_sun_media_sound_HeadspaceSoundbank_nCloseResource; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetInstruments; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetName; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetSamples; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetVersionMajor; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetVersionMinor; - Java_com_sun_media_sound_HeadspaceSoundbank_nGetVersionSubMinor; - Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResource; - Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResourceFromByteArray; - Java_com_sun_media_sound_MixerClip_nClose; - Java_com_sun_media_sound_MixerClip_nDrain; - Java_com_sun_media_sound_MixerClip_nFlush; - Java_com_sun_media_sound_MixerClip_nGetPosition; - Java_com_sun_media_sound_MixerClip_nOpen; - Java_com_sun_media_sound_MixerClip_nSetLinearGain; - Java_com_sun_media_sound_MixerClip_nSetPan; - Java_com_sun_media_sound_MixerClip_nSetSampleRate; - Java_com_sun_media_sound_MixerClip_nSetup; - Java_com_sun_media_sound_MixerClip_nStart; - Java_com_sun_media_sound_MixerClip_nStop; - Java_com_sun_media_sound_MixerMidiChannel_nAllNotesOff; - Java_com_sun_media_sound_MixerMidiChannel_nControlChange; - Java_com_sun_media_sound_MixerMidiChannel_nGetController; - Java_com_sun_media_sound_MixerMidiChannel_nGetPitchBend; - Java_com_sun_media_sound_MixerMidiChannel_nGetSolo; - Java_com_sun_media_sound_MixerMidiChannel_nNoteOff; - Java_com_sun_media_sound_MixerMidiChannel_nNoteOn; - Java_com_sun_media_sound_MixerMidiChannel_nProgramChange__JIIIJ; - Java_com_sun_media_sound_MixerMidiChannel_nProgramChange__JIIJ; - Java_com_sun_media_sound_MixerMidiChannel_nResetAllControllers; - Java_com_sun_media_sound_MixerMidiChannel_nSetMute; - Java_com_sun_media_sound_MixerMidiChannel_nSetPitchBend; - Java_com_sun_media_sound_MixerMidiChannel_nSetSolo; - Java_com_sun_media_sound_MixerSequencer_nAddControllerEventCallback; - Java_com_sun_media_sound_MixerSequencer_nGetMasterTempo; - Java_com_sun_media_sound_MixerSequencer_nGetSequenceMicrosecondLength; - Java_com_sun_media_sound_MixerSequencer_nGetSequencerMicrosecondPosition; - Java_com_sun_media_sound_MixerSequencer_nGetSequencerTickPosition; - Java_com_sun_media_sound_MixerSequencer_nGetSequenceTickLength; - Java_com_sun_media_sound_MixerSequencer_nGetTempoInBPM; - Java_com_sun_media_sound_MixerSequencer_nGetTempoInMPQ; - Java_com_sun_media_sound_MixerSequencer_nGetTrackMute; - Java_com_sun_media_sound_MixerSequencer_nGetTrackSolo; - Java_com_sun_media_sound_MixerSequencer_nOpenMidiSequencer; - Java_com_sun_media_sound_MixerSequencer_nOpenRmfSequencer; - Java_com_sun_media_sound_MixerSequencer_nPauseSequencer; - Java_com_sun_media_sound_MixerSequencer_nResumeSequencer; - Java_com_sun_media_sound_MixerSequencer_nSetMasterTempo; - Java_com_sun_media_sound_MixerSequencer_nSetSequencerMicrosecondPosition; - Java_com_sun_media_sound_MixerSequencer_nSetSequencerTickPosition; - Java_com_sun_media_sound_MixerSequencer_nSetTempoInBPM; - Java_com_sun_media_sound_MixerSequencer_nSetTempoInMPQ; - Java_com_sun_media_sound_MixerSequencer_nSetTrackMute; - Java_com_sun_media_sound_MixerSequencer_nSetTrackSolo; - Java_com_sun_media_sound_MixerSequencer_nStartSequencer; - Java_com_sun_media_sound_MixerSourceLine_nClose; - Java_com_sun_media_sound_MixerSourceLine_nDrain; - Java_com_sun_media_sound_MixerSourceLine_nFlush; - Java_com_sun_media_sound_MixerSourceLine_nGetLevel; - Java_com_sun_media_sound_MixerSourceLine_nGetPosition; - Java_com_sun_media_sound_MixerSourceLine_nOpen; - Java_com_sun_media_sound_MixerSourceLine_nPause; - Java_com_sun_media_sound_MixerSourceLine_nResume; - Java_com_sun_media_sound_MixerSourceLine_nSetLinearGain; - Java_com_sun_media_sound_MixerSourceLine_nSetPan; - Java_com_sun_media_sound_MixerSourceLine_nSetSampleRate; - Java_com_sun_media_sound_MixerSourceLine_nStart; - Java_com_sun_media_sound_MixerSynth_nCreateSynthesizer; - Java_com_sun_media_sound_MixerSynth_nDestroySynthesizer; - Java_com_sun_media_sound_MixerSynth_nGetLatency; - Java_com_sun_media_sound_MixerSynth_nLoadInstrument; - Java_com_sun_media_sound_MixerSynth_nRemapInstrument; - Java_com_sun_media_sound_MixerSynth_nStartSynthesizer; - Java_com_sun_media_sound_MixerSynth_nUnloadInstrument; - Java_com_sun_media_sound_MixerThread_runNative; - Java_com_sun_media_sound_SimpleInputDevice_nClose; - Java_com_sun_media_sound_SimpleInputDevice_nDrain; - Java_com_sun_media_sound_SimpleInputDevice_nFlush; - Java_com_sun_media_sound_SimpleInputDevice_nGetBufferSizeInFrames; - Java_com_sun_media_sound_SimpleInputDevice_nGetFormats; - Java_com_sun_media_sound_SimpleInputDevice_nGetNumPorts; - Java_com_sun_media_sound_SimpleInputDevice_nGetPortName; - Java_com_sun_media_sound_SimpleInputDevice_nGetPosition; - Java_com_sun_media_sound_SimpleInputDevice_nOpen; - Java_com_sun_media_sound_SimpleInputDevice_nPause; - Java_com_sun_media_sound_SimpleInputDevice_nResume; - Java_com_sun_media_sound_SimpleInputDevice_nStart; - Java_com_sun_media_sound_SimpleInputDevice_nStop; - Java_com_sun_media_sound_SimpleInputDevice_nSupportsChannels; - Java_com_sun_media_sound_SimpleInputDevice_nSupportsSampleRate; - Java_com_sun_media_sound_SimpleInputDevice_nSupportsSampleSizeInBits; - Java_com_sun_media_sound_SimpleInputDeviceProvider_nGetDescription; - Java_com_sun_media_sound_SimpleInputDeviceProvider_nGetName; - Java_com_sun_media_sound_SimpleInputDeviceProvider_nGetNumDevices; - Java_com_sun_media_sound_SimpleInputDeviceProvider_nGetVendor; - Java_com_sun_media_sound_SimpleInputDeviceProvider_nGetVersion; - local: - *; -}; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/cmm/Makefile --- a/jdk/make/sun/cmm/Makefile Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/sun/cmm/Makefile Fri May 30 00:00:00 2008 +0200 @@ -41,12 +41,8 @@ ICCPROFILE_DEST_DIR = $(LIBDIR)/cmm iccprofiles: $(ICCPROFILE_DEST_DIR)/sRGB.pf $(ICCPROFILE_DEST_DIR)/GRAY.pf \ - $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf - -ifndef OPENJDK -iccprofiles: $(ICCPROFILE_DEST_DIR)/PYCC.pf \ - $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf -endif + $(ICCPROFILE_DEST_DIR)/CIEXYZ.pf $(ICCPROFILE_DEST_DIR)/PYCC.pf \ + $(ICCPROFILE_DEST_DIR)/LINEAR_RGB.pf $(ICCPROFILE_DEST_DIR)/sRGB.pf: $(ICCPROFILE_SRC_DIR)/sRGB.pf $(RM) $(ICCPROFILE_DEST_DIR)/sRGB.pf diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/javazic/tzdata/VERSION --- a/jdk/make/sun/javazic/tzdata/VERSION Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/sun/javazic/tzdata/VERSION Fri May 30 00:00:00 2008 +0200 @@ -21,4 +21,4 @@ # CA 95054 USA or visit www.sun.com if you need additional information or # have any questions. # -tzdata2008b +tzdata2008c diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/javazic/tzdata/africa --- a/jdk/make/sun/javazic/tzdata/africa Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/make/sun/javazic/tzdata/africa Fri May 30 00:00:00 2008 +0200 @@ -22,7 +22,7 @@ # have any questions. # -# @(#)africa 8.10 +# @(#)africa 8.11 #
 
 # This data is by no means authoritative; if you think you know better,
@@ -424,6 +424,77 @@
 
 # Morocco
 # See the `europe' file for Spanish Morocco (Africa/Ceuta).
+
+# From Alex Krivenyshev (2008-05-09):
+# Here is an article that Morocco plan to introduce Daylight Saving Time between
+# 1 June, 2008 and 27 September, 2008.
+#
+# "... Morocco is to save energy by adjusting its clock during summer so it will
+# be one hour ahead of GMT between 1 June and 27 September, according to
+# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
+#
+# 
+# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
+# 
+# OR
+# 
+# http://en.afrik.com/news11892.html
+# 
+
+# From Alex Krivenyshev (2008-05-09):
+# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
+# 
+# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
+# 
+#
+# Morocco shifts to daylight time on June 1st through September 27, Govt.
+# spokesman.
+
+# From Patrice Scattolin (2008-05-09):
+# According to this article:
+# 
+# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
+# 
+# (and republished here:
+# 
+# http://www.actu.ma/heure-dete-comment_i127896_0.html
+# 
+# )
+# the changes occurs at midnight:
+#
+# saturday night may 31st at midnight (which in french is to be
+# intrepreted as the night between saturday and sunday)
+# sunday night the 28th  at midnight
+#
+# Seeing that the 28th is monday, I am guessing that she intends to say
+# the midnight of the 28th which is the midnight between sunday and
+# monday, which jives with other sources that say that it's inclusive
+# june1st to sept 27th.
+#
+# The decision was taken by decree *2-08-224 *but I can't find the decree
+# published on the web.
+#
+# It's also confirmed here:
+# 
+# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
+# 
+# on a government portal as being  between june 1st and sept 27th (not yet
+# posted in english).
+#
+# The following google query will generate many relevant hits:
+# 
+# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
+# 
+
+# From Alex Krivenyshev (2008-05-09):
+# Is Western Sahara (part which administrated by Morocco) going to follow
+# Morocco DST changes?  Any information?  What about other part of
+# Western Sahara - under administration of POLISARIO Front (also named
+# SADR Saharawi Arab Democratic Republic)?
+
+# From Arthur David Olson (2008-05-09):
+# XXX--guess that it is only Morocco for now; guess only 2008 for now.
+
 # RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
 Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
@@ -440,11 +511,13 @@
 Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
 Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
 Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
+Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
+Rule	Morocco	2008	only	-	Sep	28	 0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
 			 0:00	Morocco	WE%sT	1984 Mar 16
 			 1:00	-	CET	1986
-			 0:00	-	WET
+			 0:00	Morocco	WE%sT
 # Western Sahara
 Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
 			-1:00	-	WAT	1976 Apr 14
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/javazic/tzdata/asia
--- a/jdk/make/sun/javazic/tzdata/asia	Fri Apr 11 00:00:00 2008 +0200
+++ b/jdk/make/sun/javazic/tzdata/asia	Fri May 30 00:00:00 2008 +0200
@@ -22,7 +22,7 @@
 # have any questions.
 #
 
-# @(#)asia	8.18
+# @(#)asia	8.20
 # 
 
 # This data is by no means authoritative; if you think you know better,
@@ -1400,6 +1400,42 @@
 # They decided not to adopt daylight-saving time....
 # http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742
 
+# From Deborah Goldsmith (2008-03-30):
+# We received a bug report claiming that the tz database UTC offset for
+# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT
+# +08:00 instead. Different sources appear to disagree with the tz
+# database on this, e.g.:
+#
+# 
+# http://www.timeanddate.com/worldclock/city.html?n=1026
+# 
+# 
+# http://www.worldtimeserver.com/current_time_in_MN.aspx
+# 
+#
+# both say GMT+08:00.
+
+# From Steffen Thorsen (2008-03-31):
+# eznis airways, which operates several domestic flights, has a flight
+# schedule here:
+# 
+# (click the English flag for English)
+#
+# There it appears that flights between Choibalsan and Ulaanbatar arrive
+# about 1:35 - 1:50 hours later in local clock time, no matter the
+# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
+# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
+# in different time zones (like we know about), while Choibalsan and
+# Ulaanbatar are in the same time zone (correction needed).
+
+# From Arthur David Olson (2008-05-19):
+# Assume that Choibalsan is indeed offset by 8:00.
+# XXX--in the absence of better information, assume that transition
+# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
+# this is almost surely wrong.
+
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule	Mongol	1983	1984	-	Apr	1	0:00	1:00	S
 Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
@@ -1435,7 +1471,8 @@
 Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
 			7:00	-	ULAT	1978
 			8:00	-	ULAT	1983 Apr
-			9:00	Mongol	CHO%sT	# Choibalsan Time
+			9:00	Mongol	CHO%sT	2008 Mar 31 # Choibalsan Time
+			8:00	Mongol	CHO%sT
 
 # Nepal
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
@@ -1485,10 +1522,32 @@
 # The minister told a news conference that the experiment had rather
 # shown 8 per cent higher consumption of electricity.
 
+# From Alex Krivenyshev (2008-05-15):
+# 
+# Here is an article that Pakistan plan to introduce Daylight Saving Time 
+# on June 1, 2008 for 3 months.
+# 
+# "... The federal cabinet on Wednesday announced a new conservation plan to help 
+# reduce load shedding by approving the closure of commercial centres at 9pm and 
+# moving clocks forward by one hour for the next three months. 
+# ...."
+# 
+# 
+# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
+# 
+# OR
+# 
+# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
+# 
+
+# From Arthur David Olson (2008-05-19):
+# XXX--midnight transitions is a guess; 2008 only is a guess.
 
 # Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
 Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
 Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
+Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
+Rule Pakistan	2008	only	-	Sep	1	0:00	0	-
 # Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
 Zone	Asia/Karachi	4:28:12 -	LMT	1907
 			5:30	-	IST	1942 Sep
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/security/mscapi/Makefile
--- a/jdk/make/sun/security/mscapi/Makefile	Fri Apr 11 00:00:00 2008 +0200
+++ b/jdk/make/sun/security/mscapi/Makefile	Fri May 30 00:00:00 2008 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright 2005-2007 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -92,8 +92,25 @@
 PACKAGE = sun.security.mscapi
 LIBRARY = sunmscapi
 PRODUCT = sun
+
+#
+# The following is for when we need to do postprocessing
+# (signing/obfuscation) against a read-only build.  If the OUTPUTDIR
+# isn't writable, the build currently crashes out.
+#
+ifndef OPENJDK
+  ifdef ALT_JCE_BUILD_DIR
+    # =====================================================
+    # Where to place the output, in case we're building from a read-only
+    # build area.  (e.g. a release engineering build.)
+    JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
+    IGNORE_WRITABLE_OUTPUTDIR_TEST=true
+  else
+    JCE_BUILD_DIR=${TEMPDIR}
+  endif
+endif
+
 include $(BUILDDIR)/common/Defs.gmk
-include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
 
 CPLUSPLUSLIBRARY=true
 
@@ -163,6 +180,8 @@
 	$(build-warning)
 endif
 
+include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
+
 
 # =====================================================
 # Build the unsigned sunmscapi.jar file.
@@ -200,14 +219,26 @@
 # Sign the provider jar file.  Not needed for OpenJDK.
 #
 
-SIGNED_DIR = $(TEMPDIR)/signed
+SIGNED_DIR = $(JCE_BUILD_DIR)/signed
 
 sign: sign-jar
 
 sign-jar: $(SIGNED_DIR)/sunmscapi.jar
 
+ifndef ALT_JCE_BUILD_DIR
 $(SIGNED_DIR)/sunmscapi.jar: $(UNSIGNED_DIR)/sunmscapi.jar
-	$(sign-file)
+else
+#
+# We have to remove the build dependency, otherwise, we'll try to rebuild it
+# which we can't do on a read-only filesystem.
+#
+$(SIGNED_DIR)/sunmscapi.jar:
+	@if [ ! -r $(UNSIGNED_DIR)/sunmscapi.jar ] ; then \
+	    $(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunmscapi.jar"; \
+	    exit 1; \
+	fi
+endif
+	$(call sign-file, $(UNSIGNED_DIR)/sunmscapi.jar)
 
 
 # =====================================================
@@ -215,9 +246,9 @@
 #
 
 release: $(SIGNED_DIR)/sunmscapi.jar
-	$(RM) $(RELEASE_DIR)/sunmscapi.jar
-	$(MKDIR) -p $(RELEASE_DIR)
-	$(CP) $(SIGNED_DIR)/sunmscapi.jar $(RELEASE_DIR)
+	$(RM) $(JCE_BUILD_DIR)/release/sunmscapi.jar
+	$(MKDIR) -p $(JCE_BUILD_DIR)/release
+	$(CP) $(SIGNED_DIR)/sunmscapi.jar $(JCE_BUILD_DIR)/release
 	$(release-warning)
 
 endif # OPENJDK
@@ -255,7 +286,7 @@
 #
 
 clobber clean::
-	$(RM) -r $(JAR_DESTFILE) $(TEMPDIR)
+	$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
 
 .PHONY: build-jar jar install-jar
 ifndef OPENJDK
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/make/sun/security/pkcs11/Makefile
--- a/jdk/make/sun/security/pkcs11/Makefile	Fri Apr 11 00:00:00 2008 +0200
+++ b/jdk/make/sun/security/pkcs11/Makefile	Fri May 30 00:00:00 2008 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright 2003-2007 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -92,8 +92,25 @@
 PACKAGE = sun.security.pkcs11
 LIBRARY = j2pkcs11
 PRODUCT = sun
+
+#
+# The following is for when we need to do postprocessing
+# (signing/obfuscation) against a read-only build.  If the OUTPUTDIR
+# isn't writable, the build currently crashes out.
+#
+ifndef OPENJDK
+  ifdef ALT_JCE_BUILD_DIR
+    # =====================================================
+    # Where to place the output, in case we're building from a read-only
+    # build area.  (e.g. a release engineering build.)
+    JCE_BUILD_DIR=${ALT_JCE_BUILD_DIR}
+    IGNORE_WRITABLE_OUTPUTDIR_TEST=true
+  else
+    JCE_BUILD_DIR=${TEMPDIR}
+  endif
+endif
+
 include $(BUILDDIR)/common/Defs.gmk
-include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
 
 #
 # C and Java Files
@@ -163,6 +180,8 @@
 	$(build-warning)
 endif
 
+include $(BUILDDIR)/javax/crypto/Defs-jce.gmk
+
 
 # =====================================================
 # Build the unsigned sunpkcs11.jar file.
@@ -200,14 +219,26 @@
 # Sign the provider jar file.  Not needed for OpenJDK.
 #
 
-SIGNED_DIR = $(TEMPDIR)/signed
+SIGNED_DIR = $(JCE_BUILD_DIR)/signed
 
 sign: sign-jar
 
 sign-jar: $(SIGNED_DIR)/sunpkcs11.jar
 
+ifndef ALT_JCE_BUILD_DIR
 $(SIGNED_DIR)/sunpkcs11.jar: $(UNSIGNED_DIR)/sunpkcs11.jar
-	$(sign-file)
+else
+#
+# We have to remove the build dependency, otherwise, we'll try to rebuild it
+# which we can't do on a read-only filesystem.
+#
+$(SIGNED_DIR)/sunpkcs11.jar:
+	@if [ ! -r $(UNSIGNED_DIR)/sunpkcs11.jar ] ; then \
+            $(ECHO) "Couldn't find $(UNSIGNED_DIR)/sunpkcs11.jar"; \
+            exit 1; \
+        fi
+endif
+	$(call sign-file, $(UNSIGNED_DIR)/sunpkcs11.jar)
 
 
 # =====================================================
@@ -215,9 +246,9 @@
 #
 
 release: $(SIGNED_DIR)/sunpkcs11.jar
-	$(RM) $(RELEASE_DIR)/sunpkcs11.jar
-	$(MKDIR) -p $(RELEASE_DIR)
-	$(CP) $(SIGNED_DIR)/sunpkcs11.jar $(RELEASE_DIR)
+	$(RM) $(JCE_BUILD_DIR)/release/sunpkcs11.jar
+	$(MKDIR) -p $(JCE_BUILD_DIR)/release
+	$(CP) $(SIGNED_DIR)/sunpkcs11.jar $(JCE_BUILD_DIR)/release
 	$(release-warning)
 
 endif # OPENJDK
@@ -255,7 +286,7 @@
 #
 
 clobber clean::
-	$(RM) -r $(JAR_DESTFILE) $(TEMPDIR)
+	$(RM) -r $(JAR_DESTFILE) $(TEMPDIR) $(JCE_BUILD_DIR)
 
 .PHONY: build-jar jar install-jar
 ifndef OPENJDK
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/bin/java.c
--- a/jdk/src/share/bin/java.c	Fri Apr 11 00:00:00 2008 +0200
+++ b/jdk/src/share/bin/java.c	Fri May 30 00:00:00 2008 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1995-2008 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -498,8 +498,12 @@
         }
         mainClass = LoadClass(env, classname);
         if(mainClass == NULL) { /* exception occured */
+            const char * format = "Could not find the main class: %s. Program will exit.";
             ReportExceptionDescription(env);
-            message = "Could not find the main class.  Program will exit.";
+            message = (char *)JLI_MemAlloc((strlen(format) +
+					   strlen(classname)) * sizeof(char));
+            messageDest = JNI_TRUE;
+	    sprintf(message, format, classname);
             goto leave;
         }
         (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
@@ -520,8 +524,12 @@
       }
       mainClass = LoadClass(env, classname);
       if(mainClass == NULL) { /* exception occured */
+        const char * format = "Could not find the main class: %s. Program will exit.";
         ReportExceptionDescription(env);
-        message = "Could not find the main class. Program will exit.";
+        message = (char *)JLI_MemAlloc((strlen(format) +
+                                          strlen(classname)) * sizeof(char));
+        messageDest = JNI_TRUE;
+        sprintf(message, format, classname);
         goto leave;
       }
       (*env)->ReleaseStringUTFChars(env, mainClassName, classname);
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFileSoundbankReader.java	Fri May 30 00:00:00 2008 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.sound.midi.InvalidMidiDataException;
+import javax.sound.midi.Soundbank;
+import javax.sound.midi.spi.SoundbankReader;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * Soundbank reader that uses audio files as soundbanks.
+ *
+ * @author Karl Helgason
+ */
+public class AudioFileSoundbankReader extends SoundbankReader {
+
+    public Soundbank getSoundbank(URL url)
+            throws InvalidMidiDataException, IOException {
+        try {
+            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
+            Soundbank sbk = getSoundbank(ais);
+            ais.close();
+            return sbk;
+        } catch (UnsupportedAudioFileException e) {
+            return null;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    public Soundbank getSoundbank(InputStream stream)
+            throws InvalidMidiDataException, IOException {
+        stream.mark(512);
+        try {
+            AudioInputStream ais = AudioSystem.getAudioInputStream(stream);
+            Soundbank sbk = getSoundbank(ais);
+            if (sbk != null)
+                return sbk;
+        } catch (UnsupportedAudioFileException e) {
+        } catch (IOException e) {
+        }
+        stream.reset();
+        return null;
+    }
+
+    public Soundbank getSoundbank(AudioInputStream ais)
+            throws InvalidMidiDataException, IOException {
+        try {
+            try {
+                byte[] buffer;
+                if (ais.getFrameLength() == -1) {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    byte[] buff = new byte[1024
+                            - (1024 % ais.getFormat().getFrameSize())];
+                    int ret;
+                    while ((ret = ais.read(buff)) != -1) {
+                        baos.write(buff, 0, ret);
+                    }
+                    ais.close();
+                    buffer = baos.toByteArray();
+                } else {
+                    buffer = new byte[(int)(ais.getFrameLength()
+                                        * ais.getFormat().getFrameSize())];
+                    ais.read(buffer);
+                }
+                ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
+                        new ModelByteBuffer(buffer), ais.getFormat(), -4800);
+                ModelPerformer performer = new ModelPerformer();
+                performer.getOscillators().add(osc);
+
+                SimpleSoundbank sbk = new SimpleSoundbank();
+                SimpleInstrument ins = new SimpleInstrument();
+                ins.add(performer);
+                sbk.addInstrument(ins);
+                return sbk;
+            } finally {
+            }
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public Soundbank getSoundbank(File file)
+            throws InvalidMidiDataException, IOException {
+        try {
+            AudioInputStream ais = AudioSystem.getAudioInputStream(file);
+            ais.close();
+            ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
+                    new ModelByteBuffer(file, 0, file.length()), -4800);
+            ModelPerformer performer = new ModelPerformer();
+            performer.getOscillators().add(osc);
+            SimpleSoundbank sbk = new SimpleSoundbank();
+            SimpleInstrument ins = new SimpleInstrument();
+            ins.add(performer);
+            sbk.addInstrument(ins);
+            return sbk;
+        } catch (UnsupportedAudioFileException e1) {
+            return null;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+}
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatConverter.java	Fri May 30 00:00:00 2008 +0200
@@ -0,0 +1,679 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioFormat.Encoding;
+
+/**
+ * This class is used to convert between 8,16,24,32 bit signed/unsigned
+ * big/litle endian fixed/floating point byte buffers and float buffers.
+ *
+ * @author Karl Helgason
+ */
+public abstract class AudioFloatConverter {
+
+    public static final Encoding PCM_FLOAT = new Encoding("PCM_FLOAT");
+
+    /***************************************************************************
+     *
+     * 32 bit float, little/big-endian
+     *
+     **************************************************************************/
+
+    // PCM 32 bit float, little-endian
+    private static class AudioFloatConversion32L extends AudioFloatConverter {
+
+        ByteBuffer bytebuffer = null;
+        FloatBuffer floatbuffer = null;
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int in_len = out_len * 4;
+            if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+                bytebuffer = ByteBuffer.allocate(in_len).order(
+                        ByteOrder.LITTLE_ENDIAN);
+                floatbuffer = bytebuffer.asFloatBuffer();
+            }
+            bytebuffer.position(0);
+            floatbuffer.position(0);
+            bytebuffer.put(in_buff, in_offset, in_len);
+            floatbuffer.get(out_buff, out_offset, out_len);
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int out_len = in_len * 4;
+            if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+                bytebuffer = ByteBuffer.allocate(out_len).order(
+                        ByteOrder.LITTLE_ENDIAN);
+                floatbuffer = bytebuffer.asFloatBuffer();
+            }
+            floatbuffer.position(0);
+            bytebuffer.position(0);
+            floatbuffer.put(in_buff, in_offset, in_len);
+            bytebuffer.get(out_buff, out_offset, out_len);
+            return out_buff;
+        }
+    }
+
+    // PCM 32 bit float, big-endian
+    private static class AudioFloatConversion32B extends AudioFloatConverter {
+
+        ByteBuffer bytebuffer = null;
+        FloatBuffer floatbuffer = null;
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int in_len = out_len * 4;
+            if (bytebuffer == null || bytebuffer.capacity() < in_len) {
+                bytebuffer = ByteBuffer.allocate(in_len).order(
+                        ByteOrder.BIG_ENDIAN);
+                floatbuffer = bytebuffer.asFloatBuffer();
+            }
+            bytebuffer.position(0);
+            floatbuffer.position(0);
+            bytebuffer.put(in_buff, in_offset, in_len);
+            floatbuffer.get(out_buff, out_offset, out_len);
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int out_len = in_len * 4;
+            if (bytebuffer == null || bytebuffer.capacity() < out_len) {
+                bytebuffer = ByteBuffer.allocate(out_len).order(
+                        ByteOrder.BIG_ENDIAN);
+                floatbuffer = bytebuffer.asFloatBuffer();
+            }
+            floatbuffer.position(0);
+            bytebuffer.position(0);
+            floatbuffer.put(in_buff, in_offset, in_len);
+            bytebuffer.get(out_buff, out_offset, out_len);
+            return out_buff;
+        }
+    }
+
+    /***************************************************************************
+     *
+     * 8 bit signed/unsigned
+     *
+     **************************************************************************/
+
+    // PCM 8 bit, signed
+    private static class AudioFloatConversion8S extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++)
+                out_buff[ox++] = in_buff[ix++] * (1.0f / 127.0f);
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++)
+                out_buff[ox++] = (byte)(in_buff[ix++] * 127.0f);
+            return out_buff;
+        }
+    }
+
+    // PCM 8 bit, unsigned
+    private static class AudioFloatConversion8U extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++)
+                out_buff[ox++] = ((in_buff[ix++] & 0xFF) - 127) * (1.0f/127.0f);
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++)
+                out_buff[ox++] = (byte)(127 + in_buff[ix++] * 127.0f);
+            return out_buff;
+        }
+    }
+
+    /***************************************************************************
+     *
+     * 16 bit signed/unsigned, little/big-endian
+     *
+     **************************************************************************/
+
+    // PCM 16 bit, signed, little-endian
+    private static class AudioFloatConversion16SL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int len = out_offset + out_len;
+            for (int ox = out_offset; ox < len; ox++) {
+                out_buff[ox] = ((short)((in_buff[ix++] & 0xFF) |
+                        (in_buff[ix++] << 8))) * (1.0f / 32767.0f);
+            }
+
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ox = out_offset;
+            int len = in_offset + in_len;
+            for (int ix = in_offset; ix < len; ix++) {
+                int x = (int)(in_buff[ix] * 32767.0);
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 16 bit, signed, big-endian
+    private static class AudioFloatConversion16SB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                out_buff[ox++] = ((short)((in_buff[ix++] << 8) |
+                        (in_buff[ix++] & 0xFF))) * (1.0f / 32767.0f);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * 32767.0);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 16 bit, unsigned, little-endian
+    private static class AudioFloatConversion16UL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8);
+                out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = 32767 + (int)(in_buff[ix++] * 32767.0);
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 16 bit, unsigned, big-endian
+    private static class AudioFloatConversion16UB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+                out_buff[ox++] = (x - 32767) * (1.0f / 32767.0f);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = 32767 + (int)(in_buff[ix++] * 32767.0);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    /***************************************************************************
+     *
+     * 24 bit signed/unsigned, little/big-endian
+     *
+     **************************************************************************/
+
+    // PCM 24 bit, signed, little-endian
+    private static class AudioFloatConversion24SL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+                        | ((in_buff[ix++] & 0xFF) << 16);
+                if (x > 0x7FFFFF)
+                    x -= 0x1000000;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFF);
+                if (x < 0)
+                    x += 0x1000000;
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)(x >>> 16);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 24 bit, signed, big-endian
+    private static class AudioFloatConversion24SB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = ((in_buff[ix++] & 0xFF) << 16)
+                        | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+                if (x > 0x7FFFFF)
+                    x -= 0x1000000;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFF);
+                if (x < 0)
+                    x += 0x1000000;
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 24 bit, unsigned, little-endian
+    private static class AudioFloatConversion24UL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8)
+                        | ((in_buff[ix++] & 0xFF) << 16);
+                x -= 0x7FFFFF;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFF);
+                x += 0x7FFFFF;
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)(x >>> 16);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 24 bit, unsigned, big-endian
+    private static class AudioFloatConversion24UB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = ((in_buff[ix++] & 0xFF) << 16)
+                        | ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+                x -= 0x7FFFFF;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFF);
+                x += 0x7FFFFF;
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    /***************************************************************************
+     *
+     * 32 bit signed/unsigned, little/big-endian
+     *
+     **************************************************************************/
+
+    // PCM 32 bit, signed, little-endian
+    private static class AudioFloatConversion32SL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) |
+                        ((in_buff[ix++] & 0xFF) << 16) |
+                        ((in_buff[ix++] & 0xFF) << 24);
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFFFF);
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 24);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 32 bit, signed, big-endian
+    private static class AudioFloatConversion32SB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = ((in_buff[ix++] & 0xFF) << 24) |
+                        ((in_buff[ix++] & 0xFF) << 16) |
+                        ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFFFF);
+                out_buff[ox++] = (byte)(x >>> 24);
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 32 bit, unsigned, little-endian
+    private static class AudioFloatConversion32UL extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = (in_buff[ix++] & 0xFF) | ((in_buff[ix++] & 0xFF) << 8) |
+                        ((in_buff[ix++] & 0xFF) << 16) |
+                        ((in_buff[ix++] & 0xFF) << 24);
+                x -= 0x7FFFFFFF;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFFFF);
+                x += 0x7FFFFFFF;
+                out_buff[ox++] = (byte)x;
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 24);
+            }
+            return out_buff;
+        }
+    }
+
+    // PCM 32 bit, unsigned, big-endian
+    private static class AudioFloatConversion32UB extends AudioFloatConverter {
+
+        public float[] toFloatArray(byte[] in_buff, int in_offset,
+                float[] out_buff, int out_offset, int out_len) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < out_len; i++) {
+                int x = ((in_buff[ix++] & 0xFF) << 24) |
+                        ((in_buff[ix++] & 0xFF) << 16) |
+                        ((in_buff[ix++] & 0xFF) << 8) | (in_buff[ix++] & 0xFF);
+                x -= 0x7FFFFFFF;
+                out_buff[ox++] = x * (1.0f / (float)0x7FFFFFFF);
+            }
+            return out_buff;
+        }
+
+        public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+                byte[] out_buff, int out_offset) {
+            int ix = in_offset;
+            int ox = out_offset;
+            for (int i = 0; i < in_len; i++) {
+                int x = (int)(in_buff[ix++] * (float)0x7FFFFFFF);
+                x += 0x7FFFFFFF;
+                out_buff[ox++] = (byte)(x >>> 24);
+                out_buff[ox++] = (byte)(x >>> 16);
+                out_buff[ox++] = (byte)(x >>> 8);
+                out_buff[ox++] = (byte)x;
+            }
+            return out_buff;
+        }
+    }
+
+    public static AudioFloatConverter getConverter(AudioFormat format) {
+        AudioFloatConverter conv = null;
+        if (format.getFrameSize() !=
+                (format.getSampleSizeInBits() / 8) * format.getChannels()) {
+            return null;
+        }
+        if (format.getEncoding().equals(Encoding.PCM_SIGNED)) {
+            if (format.isBigEndian()) {
+                if (format.getSampleSizeInBits() == 8) {
+                    conv = new AudioFloatConversion8S();
+                } else if (format.getSampleSizeInBits() > 8 &&
+                        format.getSampleSizeInBits() <= 16) {
+                    conv = new AudioFloatConversion16SB();
+                } else if (format.getSampleSizeInBits() > 16 &&
+                        format.getSampleSizeInBits() <= 24) {
+                    conv = new AudioFloatConversion24SB();
+                } else if (format.getSampleSizeInBits() > 24 &&
+                        format.getSampleSizeInBits() <= 32) {
+                    conv = new AudioFloatConversion32SB();
+                }
+            } else {
+                if (format.getSampleSizeInBits() == 8) {
+                    conv = new AudioFloatConversion8S();
+                } else if (format.getSampleSizeInBits() > 8 &&
+                        format.getSampleSizeInBits() <= 16) {
+                    conv = new AudioFloatConversion16SL();
+                } else if (format.getSampleSizeInBits() > 16 &&
+                        format.getSampleSizeInBits() <= 24) {
+                    conv = new AudioFloatConversion24SL();
+                } else if (format.getSampleSizeInBits() > 24 &&
+                        format.getSampleSizeInBits() <= 32) {
+                    conv = new AudioFloatConversion32SL();
+                }
+            }
+        } else if (format.getEncoding().equals(Encoding.PCM_UNSIGNED)) {
+            if (format.isBigEndian()) {
+                if (format.getSampleSizeInBits() == 8) {
+                    conv = new AudioFloatConversion8U();
+                } else if (format.getSampleSizeInBits() > 8 &&
+                        format.getSampleSizeInBits() <= 16) {
+                    conv = new AudioFloatConversion16UB();
+                } else if (format.getSampleSizeInBits() > 16 &&
+                        format.getSampleSizeInBits() <= 24) {
+                    conv = new AudioFloatConversion24UB();
+                } else if (format.getSampleSizeInBits() > 24 &&
+                        format.getSampleSizeInBits() <= 32) {
+                    conv = new AudioFloatConversion32UB();
+                }
+            } else {
+                if (format.getSampleSizeInBits() == 8) {
+                    conv = new AudioFloatConversion8U();
+                } else if (format.getSampleSizeInBits() > 8 &&
+                        format.getSampleSizeInBits() <= 16) {
+                    conv = new AudioFloatConversion16UL();
+                } else if (format.getSampleSizeInBits() > 16 &&
+                        format.getSampleSizeInBits() <= 24) {
+                    conv = new AudioFloatConversion24UL();
+                } else if (format.getSampleSizeInBits() > 24 &&
+                        format.getSampleSizeInBits() <= 32) {
+                    conv = new AudioFloatConversion32UL();
+                }
+            }
+        } else if (format.getEncoding().equals(PCM_FLOAT)) {
+            if (format.getSampleSizeInBits() == 32) {
+                if (format.isBigEndian())
+                    conv = new AudioFloatConversion32B();
+                else
+                    conv = new AudioFloatConversion32L();
+            }
+        }
+
+        if (conv != null)
+            conv.format = format;
+        return conv;
+    }
+    private AudioFormat format;
+
+    public AudioFormat getFormat() {
+        return format;
+    }
+
+    public abstract float[] toFloatArray(byte[] in_buff, int in_offset,
+            float[] out_buff, int out_offset, int out_len);
+
+    public float[] toFloatArray(byte[] in_buff, float[] out_buff,
+            int out_offset, int out_len) {
+        return toFloatArray(in_buff, 0, out_buff, out_offset, out_len);
+    }
+
+    public float[] toFloatArray(byte[] in_buff, int in_offset,
+            float[] out_buff, int out_len) {
+        return toFloatArray(in_buff, in_offset, out_buff, 0, out_len);
+    }
+
+    public float[] toFloatArray(byte[] in_buff, float[] out_buff, int out_len) {
+        return toFloatArray(in_buff, 0, out_buff, 0, out_len);
+    }
+
+    public float[] toFloatArray(byte[] in_buff, float[] out_buff) {
+        return toFloatArray(in_buff, 0, out_buff, 0, out_buff.length);
+    }
+
+    public abstract byte[] toByteArray(float[] in_buff, int in_offset,
+            int in_len, byte[] out_buff, int out_offset);
+
+    public byte[] toByteArray(float[] in_buff, int in_len, byte[] out_buff,
+            int out_offset) {
+        return toByteArray(in_buff, 0, in_len, out_buff, out_offset);
+    }
+
+    public byte[] toByteArray(float[] in_buff, int in_offset, int in_len,
+            byte[] out_buff) {
+        return toByteArray(in_buff, in_offset, in_len, out_buff, 0);
+    }
+
+    public byte[] toByteArray(float[] in_buff, int in_len, byte[] out_buff) {
+        return toByteArray(in_buff, 0, in_len, out_buff, 0);
+    }
+
+    public byte[] toByteArray(float[] in_buff, byte[] out_buff) {
+        return toByteArray(in_buff, 0, in_buff.length, out_buff, 0);
+    }
+}
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/AudioFloatInputStream.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioFloatInputStream.java	Fri May 30 00:00:00 2008 +0200
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+
+/**
+ * This class is used to create AudioFloatInputStream from AudioInputStream and
+ * byte buffers.
+ *
+ * @author Karl Helgason
+ */
+public abstract class AudioFloatInputStream {
+
+    private static class BytaArrayAudioFloatInputStream
+            extends AudioFloatInputStream {
+
+        private int pos = 0;
+        private int markpos = 0;
+        private AudioFloatConverter converter;
+        private AudioFormat format;
+        private byte[] buffer;
+        private int buffer_offset;
+        private int buffer_len;
+        private int framesize_pc;
+
+        public BytaArrayAudioFloatInputStream(AudioFloatConverter converter,
+                byte[] buffer, int offset, int len) {
+            this.converter = converter;
+            this.format = converter.getFormat();
+            this.buffer = buffer;
+            this.buffer_offset = offset;
+            framesize_pc = format.getFrameSize() / format.getChannels();
+            this.buffer_len = len / framesize_pc;
+
+        }
+
+        public AudioFormat getFormat() {
+            return format;
+        }
+
+        public long getFrameLength() {
+            return buffer_len;// / format.getFrameSize();
+        }
+
+        public int read(float[] b, int off, int len) throws IOException {
+            if (b == null)
+                throw new NullPointerException();
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new IndexOutOfBoundsException();
+            if (pos >= buffer_len)
+                return -1;
+            if (len == 0)
+                return 0;
+            if (pos + len > buffer_len)
+                len = buffer_len - pos;
+            converter.toFloatArray(buffer, buffer_offset + pos * framesize_pc,
+                    b, off, len);
+            pos += len;
+            return len;
+        }
+
+        public long skip(long len) throws IOException {
+            if (pos >= buffer_len)
+                return -1;
+            if (len <= 0)
+                return 0;
+            if (pos + len > buffer_len)
+                len = buffer_len - pos;
+            pos += len;
+            return len;
+        }
+
+        public int available() throws IOException {
+            return buffer_len - pos;
+        }
+
+        public void close() throws IOException {
+        }
+
+        public void mark(int readlimit) {
+            markpos = pos;
+        }
+
+        public boolean markSupported() {
+            return true;
+        }
+
+        public void reset() throws IOException {
+            pos = markpos;
+        }
+    }
+
+    private static class DirectAudioFloatInputStream
+            extends AudioFloatInputStream {
+
+        private AudioInputStream stream;
+        private AudioFloatConverter converter;
+        private int framesize_pc; // framesize / channels
+        private byte[] buffer;
+
+        public DirectAudioFloatInputStream(AudioInputStream stream) {
+            converter = AudioFloatConverter.getConverter(stream.getFormat());
+            if (converter == null) {
+                AudioFormat format = stream.getFormat();
+                AudioFormat newformat;
+
+                AudioFormat[] formats = AudioSystem.getTargetFormats(
+                        AudioFormat.Encoding.PCM_SIGNED, format);
+                if (formats.length != 0) {
+                    newformat = formats[0];
+                } else {
+                    float samplerate = format.getSampleRate();
+                    int samplesizeinbits = format.getSampleSizeInBits();
+                    int framesize = format.getFrameSize();
+                    float framerate = format.getFrameRate();
+                    samplesizeinbits = 16;
+                    framesize = format.getChannels() * (samplesizeinbits / 8);
+                    framerate = samplerate;
+
+                    newformat = new AudioFormat(
+                            AudioFormat.Encoding.PCM_SIGNED, samplerate,
+                            samplesizeinbits, format.getChannels(), framesize,
+                            framerate, false);
+                }
+
+                stream = AudioSystem.getAudioInputStream(newformat, stream);
+                converter = AudioFloatConverter.getConverter(stream.getFormat());
+            }
+            framesize_pc = stream.getFormat().getFrameSize()
+                    / stream.getFormat().getChannels();
+            this.stream = stream;
+        }
+
+        public AudioFormat getFormat() {
+            return stream.getFormat();
+        }
+
+        public long getFrameLength() {
+            return stream.getFrameLength();
+        }
+
+        public int read(float[] b, int off, int len) throws IOException {
+            int b_len = len * framesize_pc;
+            if (buffer == null || buffer.length < b_len)
+                buffer = new byte[b_len];
+            int ret = stream.read(buffer, 0, b_len);
+            if (ret == -1)
+                return -1;
+            converter.toFloatArray(buffer, b, off, ret / framesize_pc);
+            return ret / framesize_pc;
+        }
+
+        public long skip(long len) throws IOException {
+            long b_len = len * framesize_pc;
+            long ret = stream.skip(b_len);
+            if (ret == -1)
+                return -1;
+            return ret / framesize_pc;
+        }
+
+        public int available() throws IOException {
+            return stream.available() / framesize_pc;
+        }
+
+        public void close() throws IOException {
+            stream.close();
+        }
+
+        public void mark(int readlimit) {
+            stream.mark(readlimit * framesize_pc);
+        }
+
+        public boolean markSupported() {
+            return stream.markSupported();
+        }
+
+        public void reset() throws IOException {
+            stream.reset();
+        }
+    }
+
+    public static AudioFloatInputStream getInputStream(URL url)
+            throws UnsupportedAudioFileException, IOException {
+        return new DirectAudioFloatInputStream(AudioSystem
+                .getAudioInputStream(url));
+    }
+
+    public static AudioFloatInputStream getInputStream(File file)
+            throws UnsupportedAudioFileException, IOException {
+        return new DirectAudioFloatInputStream(AudioSystem
+                .getAudioInputStream(file));
+    }
+
+    public static AudioFloatInputStream getInputStream(InputStream stream)
+            throws UnsupportedAudioFileException, IOException {
+        return new DirectAudioFloatInputStream(AudioSystem
+                .getAudioInputStream(stream));
+    }
+
+    public static AudioFloatInputStream getInputStream(
+            AudioInputStream stream) {
+        return new DirectAudioFloatInputStream(stream);
+    }
+
+    public static AudioFloatInputStream getInputStream(AudioFormat format,
+            byte[] buffer, int offset, int len) {
+        AudioFloatConverter converter = AudioFloatConverter
+                .getConverter(format);
+        if (converter != null)
+            return new BytaArrayAudioFloatInputStream(converter, buffer,
+                    offset, len);
+
+        InputStream stream = new ByteArrayInputStream(buffer, offset, len);
+        long aLen = format.getFrameSize() == AudioSystem.NOT_SPECIFIED
+                ? AudioSystem.NOT_SPECIFIED : len / format.getFrameSize();
+        AudioInputStream astream = new AudioInputStream(stream, format, aLen);
+        return getInputStream(astream);
+    }
+
+    public abstract AudioFormat getFormat();
+
+    public abstract long getFrameLength();
+
+    public abstract int read(float[] b, int off, int len) throws IOException;
+
+    public int read(float[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    public float read() throws IOException {
+        float[] b = new float[1];
+        int ret = read(b, 0, 1);
+        if (ret == -1 || ret == 0)
+            return 0;
+        return b[0];
+    }
+
+    public abstract long skip(long len) throws IOException;
+
+    public abstract int available() throws IOException;
+
+    public abstract void close() throws IOException;
+
+    public abstract void mark(int readlimit);
+
+    public abstract boolean markSupported();
+
+    public abstract void reset() throws IOException;
+}
diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/AudioSynthesizer.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizer.java	Fri May 30 00:00:00 2008 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.media.sound;
+
+import java.util.Map;
+import javax.sound.midi.MidiUnavailableException;
+import javax.sound.midi.Synthesizer;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.SourceDataLine;
+
+/**
+ * AudioSynthesizer is a Synthesizer
+ * which renders it's output audio into SourceDataLine
+ * or AudioInputStream.
+ *
+ * @see MidiSystem#getSynthesizer
+ * @see Synthesizer
+ *
+ * @author Karl Helgason
+ */
+public interface AudioSynthesizer extends Synthesizer {
+
+    /**
+     * Obtains the current format (encoding, sample rate, number of channels,
+     * etc.) of the synthesizer audio data.
+     *
+     * 

If the synthesizer is not open and has never been opened, it returns + * the default format. + * + * @return current audio data format + * @see AudioFormat + */ + public AudioFormat getFormat(); + + /** + * Gets information about the possible properties for the synthesizer. + * + * @param info a proposed list of tag/value pairs that will be sent on open. + * @return an array of AudioSynthesizerPropertyInfo objects + * describing possible properties. This array may be an empty array if + * no properties are required. + */ + public AudioSynthesizerPropertyInfo[] getPropertyInfo( + Map info); + + /** + * Opens the synthesizer and starts rendering audio into + * SourceDataLine. + * + *

An application opening a synthesizer explicitly with this call + * has to close the synthesizer by calling {@link #close}. This is + * necessary to release system resources and allow applications to + * exit cleanly. + * + *

Note that some synthesizers, once closed, cannot be reopened. + * Attempts to reopen such a synthesizer will always result in + * a MidiUnavailableException. + * + * @param line which AudioSynthesizer writes output audio into. + * If line is null, then line from system default mixer is used. + * @param info a Map object containing + * properties for additional configuration supported by synthesizer. + * If info is null then default settings are used. + * + * @throws MidiUnavailableException thrown if the synthesizer cannot be + * opened due to resource restrictions. + * @throws SecurityException thrown if the synthesizer cannot be + * opened due to security restrictions. + * + * @see #close + * @see #isOpen + */ + public void open(SourceDataLine line, Map info) + throws MidiUnavailableException; + + /** + * Opens the synthesizer and renders audio into returned + * AudioInputStream. + * + *

An application opening a synthesizer explicitly with this call + * has to close the synthesizer by calling {@link #close}. This is + * necessary to release system resources and allow applications to + * exit cleanly. + * + *

Note that some synthesizers, once closed, cannot be reopened. + * Attempts to reopen such a synthesizer will always result in + * a MidiUnavailableException. + * + * @param targetFormat specifies the AudioFormat + * used in returned AudioInputStream. + * @param info a Map object containing + * properties for additional configuration supported by synthesizer. + * If info is null then default settings are used. + * + * @throws MidiUnavailableException thrown if the synthesizer cannot be + * opened due to resource restrictions. + * @throws SecurityException thrown if the synthesizer cannot be + * opened due to security restrictions. + * + * @see #close + * @see #isOpen + */ + public AudioInputStream openStream(AudioFormat targetFormat, + Map info) throws MidiUnavailableException; +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/AudioSynthesizerPropertyInfo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Information about property used in opening AudioSynthesizer. + * + * @author Karl Helgason + */ +public class AudioSynthesizerPropertyInfo { + + /** + * Constructs a AudioSynthesizerPropertyInfo object with a given + * name and value. The description and choices + * are intialized by null values. + * + * @param name the name of the property + * @param value the current value or class used for values. + * + */ + public AudioSynthesizerPropertyInfo(String name, Object value) { + this.name = name; + this.value = value; + if (value instanceof Class) + valueClass = (Class)value; + else if (value != null) + valueClass = value.getClass(); + } + /** + * The name of the property. + */ + public String name; + /** + * A brief description of the property, which may be null. + */ + public String description = null; + /** + * The value field specifies the current value of + * the property. + */ + public Object value = null; + /** + * The valueClass field specifies class + * used in value field. + */ + public Class valueClass = null; + /** + * An array of possible values if the value for the field + * AudioSynthesizerPropertyInfo.value may be selected + * from a particular set of values; otherwise null. + */ + public Object[] choices = null; + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSInfo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class is used to store information to describe soundbanks, instruments + * and samples. It is stored inside a "INFO" List Chunk inside DLS files. + * + * @author Karl Helgason + */ +public class DLSInfo { + + /** + * (INAM) Title or subject. + */ + public String name = "untitled"; + /** + * (ICRD) Date of creation, the format is: YYYY-MM-DD. + * For example 2007-01-01 for 1. january of year 2007. + */ + public String creationDate = null; + /** + * (IENG) Name of engineer who created the object. + */ + public String engineers = null; + /** + * (IPRD) Name of the product which the object is intended for. + */ + public String product = null; + /** + * (ICOP) Copyright information. + */ + public String copyright = null; + /** + * (ICMT) General comments. Doesn't contain newline characters. + */ + public String comments = null; + /** + * (ISFT) Name of software package used to create the file. + */ + public String tools = null; + /** + * (IARL) Where content is archived. + */ + public String archival_location = null; + /** + * (IART) Artists of original content. + */ + public String artist = null; + /** + * (ICMS) Names of persons or orginizations who commissioned the file. + */ + public String commissioned = null; + /** + * (IGNR) Genre of the work. + * Example: jazz, classical, rock, etc. + */ + public String genre = null; + /** + * (IKEY) List of keyword that describe the content. + * Examples: FX, bird, piano, etc. + */ + public String keywords = null; + /** + * (IMED) Describes original medium of the data. + * For example: record, CD, etc. + */ + public String medium = null; + /** + * (ISBJ) Description of the content. + */ + public String subject = null; + /** + * (ISRC) Name of person or orginization who supplied + * orginal material for the file. + */ + public String source = null; + /** + * (ISRF) Source media for sample data is from. + * For example: CD, TV, etc. + */ + public String source_form = null; + /** + * (ITCH) Technician who sample the file/object. + */ + public String technician = null; +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,448 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sound.midi.Patch; + +/** + * This class is used to store information to describe instrument. + * It contains list of regions and modulators. + * It is stored inside a "ins " List Chunk inside DLS files. + * In the DLS documentation a modulator is called articulator. + * + * @author Karl Helgason + */ +public class DLSInstrument extends ModelInstrument { + + protected int preset = 0; + protected int bank = 0; + protected boolean druminstrument = false; + protected byte[] guid = null; + protected DLSInfo info = new DLSInfo(); + protected List regions = new ArrayList(); + protected List modulators = new ArrayList(); + + public DLSInstrument() { + super(null, null, null, null); + } + + public DLSInstrument(DLSSoundbank soundbank) { + super(soundbank, null, null, null); + } + + public DLSInfo getInfo() { + return info; + } + + public String getName() { + return info.name; + } + + public void setName(String name) { + info.name = name; + } + + public ModelPatch getPatch() { + return new ModelPatch(bank, preset, druminstrument); + } + + public void setPatch(Patch patch) { + if (patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion()) { + druminstrument = true; + bank = patch.getBank(); + preset = patch.getProgram(); + } else { + druminstrument = false; + bank = patch.getBank(); + preset = patch.getProgram(); + } + } + + public Object getData() { + return null; + } + + public List getRegions() { + return regions; + } + + public List getModulators() { + return modulators; + } + + public String toString() { + if (druminstrument) + return "Drumkit: " + info.name + + " bank #" + bank + " preset #" + preset; + else + return "Instrument: " + info.name + + " bank #" + bank + " preset #" + preset; + } + + private ModelIdentifier convertToModelDest(int dest) { + if (dest == DLSModulator.CONN_DST_NONE) + return null; + if (dest == DLSModulator.CONN_DST_GAIN) + return ModelDestination.DESTINATION_GAIN; + if (dest == DLSModulator.CONN_DST_PITCH) + return ModelDestination.DESTINATION_PITCH; + if (dest == DLSModulator.CONN_DST_PAN) + return ModelDestination.DESTINATION_PAN; + + if (dest == DLSModulator.CONN_DST_LFO_FREQUENCY) + return ModelDestination.DESTINATION_LFO1_FREQ; + if (dest == DLSModulator.CONN_DST_LFO_STARTDELAY) + return ModelDestination.DESTINATION_LFO1_DELAY; + + if (dest == DLSModulator.CONN_DST_EG1_ATTACKTIME) + return ModelDestination.DESTINATION_EG1_ATTACK; + if (dest == DLSModulator.CONN_DST_EG1_DECAYTIME) + return ModelDestination.DESTINATION_EG1_DECAY; + if (dest == DLSModulator.CONN_DST_EG1_RELEASETIME) + return ModelDestination.DESTINATION_EG1_RELEASE; + if (dest == DLSModulator.CONN_DST_EG1_SUSTAINLEVEL) + return ModelDestination.DESTINATION_EG1_SUSTAIN; + + if (dest == DLSModulator.CONN_DST_EG2_ATTACKTIME) + return ModelDestination.DESTINATION_EG2_ATTACK; + if (dest == DLSModulator.CONN_DST_EG2_DECAYTIME) + return ModelDestination.DESTINATION_EG2_DECAY; + if (dest == DLSModulator.CONN_DST_EG2_RELEASETIME) + return ModelDestination.DESTINATION_EG2_RELEASE; + if (dest == DLSModulator.CONN_DST_EG2_SUSTAINLEVEL) + return ModelDestination.DESTINATION_EG2_SUSTAIN; + + // DLS2 Destinations + if (dest == DLSModulator.CONN_DST_KEYNUMBER) + return ModelDestination.DESTINATION_KEYNUMBER; + + if (dest == DLSModulator.CONN_DST_CHORUS) + return ModelDestination.DESTINATION_CHORUS; + if (dest == DLSModulator.CONN_DST_REVERB) + return ModelDestination.DESTINATION_REVERB; + + if (dest == DLSModulator.CONN_DST_VIB_FREQUENCY) + return ModelDestination.DESTINATION_LFO2_FREQ; + if (dest == DLSModulator.CONN_DST_VIB_STARTDELAY) + return ModelDestination.DESTINATION_LFO2_DELAY; + + if (dest == DLSModulator.CONN_DST_EG1_DELAYTIME) + return ModelDestination.DESTINATION_EG1_DELAY; + if (dest == DLSModulator.CONN_DST_EG1_HOLDTIME) + return ModelDestination.DESTINATION_EG1_HOLD; + if (dest == DLSModulator.CONN_DST_EG1_SHUTDOWNTIME) + return ModelDestination.DESTINATION_EG1_SHUTDOWN; + + if (dest == DLSModulator.CONN_DST_EG2_DELAYTIME) + return ModelDestination.DESTINATION_EG2_DELAY; + if (dest == DLSModulator.CONN_DST_EG2_HOLDTIME) + return ModelDestination.DESTINATION_EG2_HOLD; + + if (dest == DLSModulator.CONN_DST_FILTER_CUTOFF) + return ModelDestination.DESTINATION_FILTER_FREQ; + if (dest == DLSModulator.CONN_DST_FILTER_Q) + return ModelDestination.DESTINATION_FILTER_Q; + + return null; + } + + private ModelIdentifier convertToModelSrc(int src) { + if (src == DLSModulator.CONN_SRC_NONE) + return null; + + if (src == DLSModulator.CONN_SRC_LFO) + return ModelSource.SOURCE_LFO1; + if (src == DLSModulator.CONN_SRC_KEYONVELOCITY) + return ModelSource.SOURCE_NOTEON_VELOCITY; + if (src == DLSModulator.CONN_SRC_KEYNUMBER) + return ModelSource.SOURCE_NOTEON_KEYNUMBER; + if (src == DLSModulator.CONN_SRC_EG1) + return ModelSource.SOURCE_EG1; + if (src == DLSModulator.CONN_SRC_EG2) + return ModelSource.SOURCE_EG2; + if (src == DLSModulator.CONN_SRC_PITCHWHEEL) + return ModelSource.SOURCE_MIDI_PITCH; + if (src == DLSModulator.CONN_SRC_CC1) + return new ModelIdentifier("midi_cc", "1", 0); + if (src == DLSModulator.CONN_SRC_CC7) + return new ModelIdentifier("midi_cc", "7", 0); + if (src == DLSModulator.CONN_SRC_CC10) + return new ModelIdentifier("midi_cc", "10", 0); + if (src == DLSModulator.CONN_SRC_CC11) + return new ModelIdentifier("midi_cc", "11", 0); + if (src == DLSModulator.CONN_SRC_RPN0) + return new ModelIdentifier("midi_rpn", "0", 0); + if (src == DLSModulator.CONN_SRC_RPN1) + return new ModelIdentifier("midi_rpn", "1", 0); + + if (src == DLSModulator.CONN_SRC_POLYPRESSURE) + return ModelSource.SOURCE_MIDI_POLY_PRESSURE; + if (src == DLSModulator.CONN_SRC_CHANNELPRESSURE) + return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE; + if (src == DLSModulator.CONN_SRC_VIBRATO) + return ModelSource.SOURCE_LFO2; + if (src == DLSModulator.CONN_SRC_MONOPRESSURE) + return ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE; + + if (src == DLSModulator.CONN_SRC_CC91) + return new ModelIdentifier("midi_cc", "91", 0); + if (src == DLSModulator.CONN_SRC_CC93) + return new ModelIdentifier("midi_cc", "93", 0); + + return null; + } + + private ModelConnectionBlock convertToModel(DLSModulator mod) { + ModelIdentifier source = convertToModelSrc(mod.getSource()); + ModelIdentifier control = convertToModelSrc(mod.getControl()); + ModelIdentifier destination_id = + convertToModelDest(mod.getDestination()); + + int scale = mod.getScale(); + double f_scale; + if (scale == Integer.MIN_VALUE) + f_scale = Double.NEGATIVE_INFINITY; + else + f_scale = scale / 65536.0; + + if (destination_id != null) { + ModelSource src = null; + ModelSource ctrl = null; + ModelConnectionBlock block = new ModelConnectionBlock(); + if (control != null) { + ModelSource s = new ModelSource(); + if (control == ModelSource.SOURCE_MIDI_PITCH) { + ((ModelStandardTransform)s.getTransform()).setPolarity( + ModelStandardTransform.POLARITY_BIPOLAR); + } else if (control == ModelSource.SOURCE_LFO1 + || control == ModelSource.SOURCE_LFO2) { + ((ModelStandardTransform)s.getTransform()).setPolarity( + ModelStandardTransform.POLARITY_BIPOLAR); + } + s.setIdentifier(control); + block.addSource(s); + ctrl = s; + } + if (source != null) { + ModelSource s = new ModelSource(); + if (source == ModelSource.SOURCE_MIDI_PITCH) { + ((ModelStandardTransform)s.getTransform()).setPolarity( + ModelStandardTransform.POLARITY_BIPOLAR); + } else if (source == ModelSource.SOURCE_LFO1 + || source == ModelSource.SOURCE_LFO2) { + ((ModelStandardTransform)s.getTransform()).setPolarity( + ModelStandardTransform.POLARITY_BIPOLAR); + } + s.setIdentifier(source); + block.addSource(s); + src = s; + } + ModelDestination destination = new ModelDestination(); + destination.setIdentifier(destination_id); + block.setDestination(destination); + + if (mod.getVersion() == 1) { + //if (mod.getTransform() == DLSModulator.CONN_TRN_CONCAVE) { + // ((ModelStandardTransform)destination.getTransform()) + // .setTransform( + // ModelStandardTransform.TRANSFORM_CONCAVE); + //} + if (mod.getTransform() == DLSModulator.CONN_TRN_CONCAVE) { + if (src != null) { + ((ModelStandardTransform)src.getTransform()) + .setTransform( + ModelStandardTransform.TRANSFORM_CONCAVE); + ((ModelStandardTransform)src.getTransform()) + .setDirection( + ModelStandardTransform.DIRECTION_MAX2MIN); + } + if (ctrl != null) { + ((ModelStandardTransform)ctrl.getTransform()) + .setTransform( + ModelStandardTransform.TRANSFORM_CONCAVE); + ((ModelStandardTransform)ctrl.getTransform()) + .setDirection( + ModelStandardTransform.DIRECTION_MAX2MIN); + } + } + + } else if (mod.getVersion() == 2) { + int transform = mod.getTransform(); + int src_transform_invert = (transform >> 15) & 1; + int src_transform_bipolar = (transform >> 14) & 1; + int src_transform = (transform >> 10) & 8; + int ctr_transform_invert = (transform >> 9) & 1; + int ctr_transform_bipolar = (transform >> 8) & 1; + int ctr_transform = (transform >> 4) & 8; + + + if (src != null) { + int trans = ModelStandardTransform.TRANSFORM_LINEAR; + if (src_transform == DLSModulator.CONN_TRN_SWITCH) + trans = ModelStandardTransform.TRANSFORM_SWITCH; + if (src_transform == DLSModulator.CONN_TRN_CONCAVE) + trans = ModelStandardTransform.TRANSFORM_CONCAVE; + if (src_transform == DLSModulator.CONN_TRN_CONVEX) + trans = ModelStandardTransform.TRANSFORM_CONVEX; + ((ModelStandardTransform)src.getTransform()) + .setTransform(trans); + ((ModelStandardTransform)src.getTransform()) + .setPolarity(src_transform_bipolar == 1); + ((ModelStandardTransform)src.getTransform()) + .setDirection(src_transform_invert == 1); + + } + + if (ctrl != null) { + int trans = ModelStandardTransform.TRANSFORM_LINEAR; + if (ctr_transform == DLSModulator.CONN_TRN_SWITCH) + trans = ModelStandardTransform.TRANSFORM_SWITCH; + if (ctr_transform == DLSModulator.CONN_TRN_CONCAVE) + trans = ModelStandardTransform.TRANSFORM_CONCAVE; + if (ctr_transform == DLSModulator.CONN_TRN_CONVEX) + trans = ModelStandardTransform.TRANSFORM_CONVEX; + ((ModelStandardTransform)ctrl.getTransform()) + .setTransform(trans); + ((ModelStandardTransform)ctrl.getTransform()) + .setPolarity(ctr_transform_bipolar == 1); + ((ModelStandardTransform)ctrl.getTransform()) + .setDirection(ctr_transform_invert == 1); + } + + /* No output transforms are defined the DLS Level 2 + int out_transform = transform % 8; + int trans = ModelStandardTransform.TRANSFORM_LINEAR; + if (out_transform == DLSModulator.CONN_TRN_SWITCH) + trans = ModelStandardTransform.TRANSFORM_SWITCH; + if (out_transform == DLSModulator.CONN_TRN_CONCAVE) + trans = ModelStandardTransform.TRANSFORM_CONCAVE; + if (out_transform == DLSModulator.CONN_TRN_CONVEX) + trans = ModelStandardTransform.TRANSFORM_CONVEX; + if (ctrl != null) { + ((ModelStandardTransform)destination.getTransform()) + .setTransform(trans); + } + */ + + } + + block.setScale(f_scale); + + return block; + } + + return null; + } + + public ModelPerformer[] getPerformers() { + List performers = new ArrayList(); + + Map modmap = new HashMap(); + for (DLSModulator mod: getModulators()) { + modmap.put(mod.getSource() + "x" + mod.getControl() + "=" + + mod.getDestination(), mod); + } + + Map insmodmap = + new HashMap(); + + for (DLSRegion zone: regions) { + ModelPerformer performer = new ModelPerformer(); + performer.setName(zone.getSample().getName()); + performer.setSelfNonExclusive((zone.getFusoptions() & + DLSRegion.OPTION_SELFNONEXCLUSIVE) != 0); + performer.setExclusiveClass(zone.getExclusiveClass()); + performer.setKeyFrom(zone.getKeyfrom()); + performer.setKeyTo(zone.getKeyto()); + performer.setVelFrom(zone.getVelfrom()); + performer.setVelTo(zone.getVelto()); + + insmodmap.clear(); + insmodmap.putAll(modmap); + for (DLSModulator mod: zone.getModulators()) { + insmodmap.put(mod.getSource() + "x" + mod.getControl() + "=" + + mod.getDestination(), mod); + } + + List blocks = performer.getConnectionBlocks(); + for (DLSModulator mod: insmodmap.values()) { + ModelConnectionBlock p = convertToModel(mod); + if (p != null) + blocks.add(p); + } + + + DLSSample sample = zone.getSample(); + DLSSampleOptions sampleopt = zone.getSampleoptions(); + if (sampleopt == null) + sampleopt = sample.getSampleoptions(); + + ModelByteBuffer buff = sample.getDataBuffer(); + + float pitchcorrection = (-sampleopt.unitynote * 100) + + sampleopt.finetune; + + ModelByteBufferWavetable osc = new ModelByteBufferWavetable(buff, + sample.getFormat(), pitchcorrection); + osc.setAttenuation(osc.getAttenuation() / 65536f); + if (sampleopt.getLoops().size() != 0) { + DLSSampleLoop loop = sampleopt.getLoops().get(0); + osc.setLoopStart((int)loop.getStart()); + osc.setLoopLength((int)loop.getLength()); + if (loop.getType() == DLSSampleLoop.LOOP_TYPE_FORWARD) + osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD); + if (loop.getType() == DLSSampleLoop.LOOP_TYPE_RELEASE) + osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE); + else + osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD); + } + + performer.getConnectionBlocks().add( + new ModelConnectionBlock(SoftFilter.FILTERTYPE_LP12, + new ModelDestination( + new ModelIdentifier("filter", "type", 1)))); + + performer.getOscillators().add(osc); + + performers.add(performer); + + } + + return performers.toArray(new ModelPerformer[performers.size()]); + } + + public byte[] getGuid() { + return guid; + } + + public void setGuid(byte[] guid) { + this.guid = guid; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSModulator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSModulator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,351 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class is used to store modulator/artiuclation data. + * A modulator connects one synthesizer source to + * a destination. For example a note on velocity + * can be mapped to the gain of the synthesized voice. + * It is stored as a "art1" or "art2" chunk inside DLS files. + * + * @author Karl Helgason + */ +public class DLSModulator { + + // DLS1 Destinations + public static final int CONN_DST_NONE = 0x000; // 0 + public static final int CONN_DST_GAIN = 0x001; // cB + public static final int CONN_DST_PITCH = 0x003; // cent + public static final int CONN_DST_PAN = 0x004; // 0.1% + public static final int CONN_DST_LFO_FREQUENCY = 0x104; // cent (default 5 Hz) + public static final int CONN_DST_LFO_STARTDELAY = 0x105; // timecent + public static final int CONN_DST_EG1_ATTACKTIME = 0x206; // timecent + public static final int CONN_DST_EG1_DECAYTIME = 0x207; // timecent + public static final int CONN_DST_EG1_RELEASETIME = 0x209; // timecent + public static final int CONN_DST_EG1_SUSTAINLEVEL = 0x20A; // 0.1% + public static final int CONN_DST_EG2_ATTACKTIME = 0x30A; // timecent + public static final int CONN_DST_EG2_DECAYTIME = 0x30B; // timecent + public static final int CONN_DST_EG2_RELEASETIME = 0x30D; // timecent + public static final int CONN_DST_EG2_SUSTAINLEVEL = 0x30E; // 0.1% + // DLS2 Destinations + public static final int CONN_DST_KEYNUMBER = 0x005; + public static final int CONN_DST_LEFT = 0x010; // 0.1% + public static final int CONN_DST_RIGHT = 0x011; // 0.1% + public static final int CONN_DST_CENTER = 0x012; // 0.1% + public static final int CONN_DST_LEFTREAR = 0x013; // 0.1% + public static final int CONN_DST_RIGHTREAR = 0x014; // 0.1% + public static final int CONN_DST_LFE_CHANNEL = 0x015; // 0.1% + public static final int CONN_DST_CHORUS = 0x080; // 0.1% + public static final int CONN_DST_REVERB = 0x081; // 0.1% + public static final int CONN_DST_VIB_FREQUENCY = 0x114; // cent + public static final int CONN_DST_VIB_STARTDELAY = 0x115; // dB + public static final int CONN_DST_EG1_DELAYTIME = 0x20B; // timecent + public static final int CONN_DST_EG1_HOLDTIME = 0x20C; // timecent + public static final int CONN_DST_EG1_SHUTDOWNTIME = 0x20D; // timecent + public static final int CONN_DST_EG2_DELAYTIME = 0x30F; // timecent + public static final int CONN_DST_EG2_HOLDTIME = 0x310; // timecent + public static final int CONN_DST_FILTER_CUTOFF = 0x500; // cent + public static final int CONN_DST_FILTER_Q = 0x501; // dB + + // DLS1 Sources + public static final int CONN_SRC_NONE = 0x000; // 1 + public static final int CONN_SRC_LFO = 0x001; // linear (sine wave) + public static final int CONN_SRC_KEYONVELOCITY = 0x002; // ??db or velocity?? + public static final int CONN_SRC_KEYNUMBER = 0x003; // ??cent or keynumber?? + public static final int CONN_SRC_EG1 = 0x004; // linear direct from eg + public static final int CONN_SRC_EG2 = 0x005; // linear direct from eg + public static final int CONN_SRC_PITCHWHEEL = 0x006; // linear -1..1 + public static final int CONN_SRC_CC1 = 0x081; // linear 0..1 + public static final int CONN_SRC_CC7 = 0x087; // linear 0..1 + public static final int CONN_SRC_CC10 = 0x08A; // linear 0..1 + public static final int CONN_SRC_CC11 = 0x08B; // linear 0..1 + public static final int CONN_SRC_RPN0 = 0x100; // ?? // Pitch Bend Range + public static final int CONN_SRC_RPN1 = 0x101; // ?? // Fine Tune + public static final int CONN_SRC_RPN2 = 0x102; // ?? // Course Tune + // DLS2 Sources + public static final int CONN_SRC_POLYPRESSURE = 0x007; // linear 0..1 + public static final int CONN_SRC_CHANNELPRESSURE = 0x008; // linear 0..1 + public static final int CONN_SRC_VIBRATO = 0x009; // linear 0..1 + public static final int CONN_SRC_MONOPRESSURE = 0x00A; // linear 0..1 + public static final int CONN_SRC_CC91 = 0x0DB; // linear 0..1 + public static final int CONN_SRC_CC93 = 0x0DD; // linear 0..1 + // DLS1 Transforms + public static final int CONN_TRN_NONE = 0x000; + public static final int CONN_TRN_CONCAVE = 0x001; + // DLS2 Transforms + public static final int CONN_TRN_CONVEX = 0x002; + public static final int CONN_TRN_SWITCH = 0x003; + public static final int DST_FORMAT_CB = 1; + public static final int DST_FORMAT_CENT = 1; + public static final int DST_FORMAT_TIMECENT = 2; + public static final int DST_FORMAT_PERCENT = 3; + protected int source; + protected int control; + protected int destination; + protected int transform; + protected int scale; + protected int version = 1; + + public int getControl() { + return control; + } + + public void setControl(int control) { + this.control = control; + } + + public static int getDestinationFormat(int destination) { + + if (destination == CONN_DST_GAIN) + return DST_FORMAT_CB; + if (destination == CONN_DST_PITCH) + return DST_FORMAT_CENT; + if (destination == CONN_DST_PAN) + return DST_FORMAT_PERCENT; + + if (destination == CONN_DST_LFO_FREQUENCY) + return DST_FORMAT_CENT; + if (destination == CONN_DST_LFO_STARTDELAY) + return DST_FORMAT_TIMECENT; + + if (destination == CONN_DST_EG1_ATTACKTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG1_DECAYTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG1_RELEASETIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG1_SUSTAINLEVEL) + return DST_FORMAT_PERCENT; + + if (destination == CONN_DST_EG2_ATTACKTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG2_DECAYTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG2_RELEASETIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG2_SUSTAINLEVEL) + return DST_FORMAT_PERCENT; + + if (destination == CONN_DST_KEYNUMBER) + return DST_FORMAT_CENT; // NOT SURE WITHOUT DLS 2 SPEC + if (destination == CONN_DST_LEFT) + return DST_FORMAT_CB; + if (destination == CONN_DST_RIGHT) + return DST_FORMAT_CB; + if (destination == CONN_DST_CENTER) + return DST_FORMAT_CB; + if (destination == CONN_DST_LEFTREAR) + return DST_FORMAT_CB; + if (destination == CONN_DST_RIGHTREAR) + return DST_FORMAT_CB; + if (destination == CONN_DST_LFE_CHANNEL) + return DST_FORMAT_CB; + if (destination == CONN_DST_CHORUS) + return DST_FORMAT_PERCENT; + if (destination == CONN_DST_REVERB) + return DST_FORMAT_PERCENT; + + if (destination == CONN_DST_VIB_FREQUENCY) + return DST_FORMAT_CENT; + if (destination == CONN_DST_VIB_STARTDELAY) + return DST_FORMAT_TIMECENT; + + if (destination == CONN_DST_EG1_DELAYTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG1_HOLDTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG1_SHUTDOWNTIME) + return DST_FORMAT_TIMECENT; + + if (destination == CONN_DST_EG2_DELAYTIME) + return DST_FORMAT_TIMECENT; + if (destination == CONN_DST_EG2_HOLDTIME) + return DST_FORMAT_TIMECENT; + + if (destination == CONN_DST_FILTER_CUTOFF) + return DST_FORMAT_CENT; + if (destination == CONN_DST_FILTER_Q) + return DST_FORMAT_CB; + + return -1; + } + + public static String getDestinationName(int destination) { + + if (destination == CONN_DST_GAIN) + return "gain"; + if (destination == CONN_DST_PITCH) + return "pitch"; + if (destination == CONN_DST_PAN) + return "pan"; + + if (destination == CONN_DST_LFO_FREQUENCY) + return "lfo1.freq"; + if (destination == CONN_DST_LFO_STARTDELAY) + return "lfo1.delay"; + + if (destination == CONN_DST_EG1_ATTACKTIME) + return "eg1.attack"; + if (destination == CONN_DST_EG1_DECAYTIME) + return "eg1.decay"; + if (destination == CONN_DST_EG1_RELEASETIME) + return "eg1.release"; + if (destination == CONN_DST_EG1_SUSTAINLEVEL) + return "eg1.sustain"; + + if (destination == CONN_DST_EG2_ATTACKTIME) + return "eg2.attack"; + if (destination == CONN_DST_EG2_DECAYTIME) + return "eg2.decay"; + if (destination == CONN_DST_EG2_RELEASETIME) + return "eg2.release"; + if (destination == CONN_DST_EG2_SUSTAINLEVEL) + return "eg2.sustain"; + + if (destination == CONN_DST_KEYNUMBER) + return "keynumber"; + if (destination == CONN_DST_LEFT) + return "left"; + if (destination == CONN_DST_RIGHT) + return "right"; + if (destination == CONN_DST_CENTER) + return "center"; + if (destination == CONN_DST_LEFTREAR) + return "leftrear"; + if (destination == CONN_DST_RIGHTREAR) + return "rightrear"; + if (destination == CONN_DST_LFE_CHANNEL) + return "lfe_channel"; + if (destination == CONN_DST_CHORUS) + return "chorus"; + if (destination == CONN_DST_REVERB) + return "reverb"; + + if (destination == CONN_DST_VIB_FREQUENCY) + return "vib.freq"; + if (destination == CONN_DST_VIB_STARTDELAY) + return "vib.delay"; + + if (destination == CONN_DST_EG1_DELAYTIME) + return "eg1.delay"; + if (destination == CONN_DST_EG1_HOLDTIME) + return "eg1.hold"; + if (destination == CONN_DST_EG1_SHUTDOWNTIME) + return "eg1.shutdown"; + + if (destination == CONN_DST_EG2_DELAYTIME) + return "eg2.delay"; + if (destination == CONN_DST_EG2_HOLDTIME) + return "eg.2hold"; + + if (destination == CONN_DST_FILTER_CUTOFF) + return "filter.cutoff"; // NOT SURE WITHOUT DLS 2 SPEC + if (destination == CONN_DST_FILTER_Q) + return "filter.q"; // NOT SURE WITHOUT DLS 2 SPEC + + return null; + } + + public static String getSourceName(int source) { + + if (source == CONN_SRC_NONE) + return "none"; + if (source == CONN_SRC_LFO) + return "lfo"; + if (source == CONN_SRC_KEYONVELOCITY) + return "keyonvelocity"; + if (source == CONN_SRC_KEYNUMBER) + return "keynumber"; + if (source == CONN_SRC_EG1) + return "eg1"; + if (source == CONN_SRC_EG2) + return "eg2"; + if (source == CONN_SRC_PITCHWHEEL) + return "pitchweel"; + if (source == CONN_SRC_CC1) + return "cc1"; + if (source == CONN_SRC_CC7) + return "cc7"; + if (source == CONN_SRC_CC10) + return "c10"; + if (source == CONN_SRC_CC11) + return "cc11"; + + if (source == CONN_SRC_POLYPRESSURE) + return "polypressure"; + if (source == CONN_SRC_CHANNELPRESSURE) + return "channelpressure"; + if (source == CONN_SRC_VIBRATO) + return "vibrato"; + if (source == CONN_SRC_MONOPRESSURE) + return "monopressure"; + if (source == CONN_SRC_CC91) + return "cc91"; + if (source == CONN_SRC_CC93) + return "cc93"; + return null; + } + + public int getDestination() { + return destination; + } + + public void setDestination(int destination) { + this.destination = destination; + } + + public int getScale() { + return scale; + } + + public void setScale(int scale) { + this.scale = scale; + } + + public int getSource() { + return source; + } + + public void setSource(int source) { + this.source = source; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public int getTransform() { + return transform; + } + + public void setTransform(int transform) { + this.transform = transform; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSRegion.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,150 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class is used to store region parts for instrument. + * A region has a velocity and key range which it response to. + * And it has a list of modulators/articulators which + * is used how to synthesize a single voice. + * It is stored inside a "rgn " List Chunk inside DLS files. + * + * @author Karl Helgason + */ +public class DLSRegion { + + public final static int OPTION_SELFNONEXCLUSIVE = 0x0001; + protected List modulators = new ArrayList(); + protected int keyfrom; + protected int keyto; + protected int velfrom; + protected int velto; + protected int options; + protected int exclusiveClass; + protected int fusoptions; + protected int phasegroup; + protected long channel; + protected DLSSample sample = null; + protected DLSSampleOptions sampleoptions; + + public List getModulators() { + return modulators; + } + + public long getChannel() { + return channel; + } + + public void setChannel(long channel) { + this.channel = channel; + } + + public int getExclusiveClass() { + return exclusiveClass; + } + + public void setExclusiveClass(int exclusiveClass) { + this.exclusiveClass = exclusiveClass; + } + + public int getFusoptions() { + return fusoptions; + } + + public void setFusoptions(int fusoptions) { + this.fusoptions = fusoptions; + } + + public int getKeyfrom() { + return keyfrom; + } + + public void setKeyfrom(int keyfrom) { + this.keyfrom = keyfrom; + } + + public int getKeyto() { + return keyto; + } + + public void setKeyto(int keyto) { + this.keyto = keyto; + } + + public int getOptions() { + return options; + } + + public void setOptions(int options) { + this.options = options; + } + + public int getPhasegroup() { + return phasegroup; + } + + public void setPhasegroup(int phasegroup) { + this.phasegroup = phasegroup; + } + + public DLSSample getSample() { + return sample; + } + + public void setSample(DLSSample sample) { + this.sample = sample; + } + + public int getVelfrom() { + return velfrom; + } + + public void setVelfrom(int velfrom) { + this.velfrom = velfrom; + } + + public int getVelto() { + return velto; + } + + public void setVelto(int velto) { + this.velto = velto; + } + + public void setModulators(List modulators) { + this.modulators = modulators; + } + + public DLSSampleOptions getSampleoptions() { + return sampleoptions; + } + + public void setSampleoptions(DLSSampleOptions sampleOptions) { + this.sampleoptions = sampleOptions; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSSample.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSample.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,122 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.InputStream; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +/** + * This class is used to store the sample data itself. + * A sample is encoded as PCM audio stream + * and in DLS Level 1 files it is always a mono 8/16 bit stream. + * They are stored just like RIFF WAVE files are stored. + * It is stored inside a "wave" List Chunk inside DLS files. + * + * @author Karl Helgason + */ +public class DLSSample extends SoundbankResource { + + protected byte[] guid = null; + protected DLSInfo info = new DLSInfo(); + protected DLSSampleOptions sampleoptions; + protected ModelByteBuffer data; + protected AudioFormat format; + + public DLSSample(Soundbank soundBank) { + super(soundBank, null, AudioInputStream.class); + } + + public DLSSample() { + super(null, null, AudioInputStream.class); + } + + public DLSInfo getInfo() { + return info; + } + + public Object getData() { + AudioFormat format = getFormat(); + + InputStream is = data.getInputStream(); + if (is == null) + return null; + return new AudioInputStream(is, format, data.capacity()); + } + + public ModelByteBuffer getDataBuffer() { + return data; + } + + public AudioFormat getFormat() { + return format; + } + + public void setFormat(AudioFormat format) { + this.format = format; + } + + public void setData(ModelByteBuffer data) { + this.data = data; + } + + public void setData(byte[] data) { + this.data = new ModelByteBuffer(data); + } + + public void setData(byte[] data, int offset, int length) { + this.data = new ModelByteBuffer(data, offset, length); + } + + public String getName() { + return info.name; + } + + public void setName(String name) { + info.name = name; + } + + public DLSSampleOptions getSampleoptions() { + return sampleoptions; + } + + public void setSampleoptions(DLSSampleOptions sampleOptions) { + this.sampleoptions = sampleOptions; + } + + public String toString() { + return "Sample: " + info.name; + } + + public byte[] getGuid() { + return guid; + } + + public void setGuid(byte[] guid) { + this.guid = guid; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSSampleLoop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSampleLoop.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class is used to store loop points inside DLSSampleOptions class. + * + * @author Karl Helgason + */ +public class DLSSampleLoop { + + public final static int LOOP_TYPE_FORWARD = 0; + public final static int LOOP_TYPE_RELEASE = 1; + protected long type; + protected long start; + protected long length; + + public long getLength() { + return length; + } + + public void setLength(long length) { + this.length = length; + } + + public long getStart() { + return start; + } + + public void setStart(long start) { + this.start = start; + } + + public long getType() { + return type; + } + + public void setType(long type) { + this.type = type; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSSampleOptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSampleOptions.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class stores options how to playback sampled data like pitch/tuning, + * attenuation and loops. + * It is stored as a "wsmp" chunk inside DLS files. + * + * @author Karl Helgason + */ +public class DLSSampleOptions { + + protected int unitynote; + protected short finetune; + protected int attenuation; + protected long options; + protected List loops = new ArrayList(); + + public int getAttenuation() { + return attenuation; + } + + public void setAttenuation(int attenuation) { + this.attenuation = attenuation; + } + + public short getFinetune() { + return finetune; + } + + public void setFinetune(short finetune) { + this.finetune = finetune; + } + + public List getLoops() { + return loops; + } + + public long getOptions() { + return options; + } + + public void setOptions(long options) { + this.options = options; + } + + public int getUnitynote() { + return unitynote; + } + + public void setUnitynote(int unitynote) { + this.unitynote = unitynote; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbank.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,1286 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.sound.midi.Instrument; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFormat.Encoding; + +/** + * A DLS Level 1 and Level 2 soundbank reader (from files/url/streams). + * + * @author Karl Helgason + */ +public class DLSSoundbank implements Soundbank { + + static private class DLSID { + long i1; + int s1; + int s2; + int x1; + int x2; + int x3; + int x4; + int x5; + int x6; + int x7; + int x8; + + private DLSID() { + } + + public DLSID(long i1, int s1, int s2, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, int x8) { + this.i1 = i1; + this.s1 = s1; + this.s2 = s2; + this.x1 = x1; + this.x2 = x2; + this.x3 = x3; + this.x4 = x4; + this.x5 = x5; + this.x6 = x6; + this.x7 = x7; + this.x8 = x8; + } + + public static DLSID read(RIFFReader riff) throws IOException { + DLSID d = new DLSID(); + d.i1 = riff.readUnsignedInt(); + d.s1 = riff.readUnsignedShort(); + d.s2 = riff.readUnsignedShort(); + d.x1 = riff.readByte(); + d.x2 = riff.readByte(); + d.x3 = riff.readByte(); + d.x4 = riff.readByte(); + d.x5 = riff.readByte(); + d.x6 = riff.readByte(); + d.x7 = riff.readByte(); + d.x8 = riff.readByte(); + return d; + } + + public boolean equals(Object obj) { + if (!(obj instanceof DLSID)) { + return false; + } + DLSID t = (DLSID) obj; + return i1 == t.i1 && s1 == t.s1 && s2 == t.s2 + && x1 == t.x1 && x2 == t.x2 && x3 == t.x3 && x4 == t.x4 + && x5 == t.x5 && x6 == t.x6 && x7 == t.x7 && x8 == t.x8; + } + } + + /** X = X & Y */ + private static final int DLS_CDL_AND = 0x0001; + /** X = X | Y */ + private static final int DLS_CDL_OR = 0x0002; + /** X = X ^ Y */ + private static final int DLS_CDL_XOR = 0x0003; + /** X = X + Y */ + private static final int DLS_CDL_ADD = 0x0004; + /** X = X - Y */ + private static final int DLS_CDL_SUBTRACT = 0x0005; + /** X = X * Y */ + private static final int DLS_CDL_MULTIPLY = 0x0006; + /** X = X / Y */ + private static final int DLS_CDL_DIVIDE = 0x0007; + /** X = X && Y */ + private static final int DLS_CDL_LOGICAL_AND = 0x0008; + /** X = X || Y */ + private static final int DLS_CDL_LOGICAL_OR = 0x0009; + /** X = (X < Y) */ + private static final int DLS_CDL_LT = 0x000A; + /** X = (X <= Y) */ + private static final int DLS_CDL_LE = 0x000B; + /** X = (X > Y) */ + private static final int DLS_CDL_GT = 0x000C; + /** X = (X >= Y) */ + private static final int DLS_CDL_GE = 0x000D; + /** X = (X == Y) */ + private static final int DLS_CDL_EQ = 0x000E; + /** X = !X */ + private static final int DLS_CDL_NOT = 0x000F; + /** 32-bit constant */ + private static final int DLS_CDL_CONST = 0x0010; + /** 32-bit value returned from query */ + private static final int DLS_CDL_QUERY = 0x0011; + /** 32-bit value returned from query */ + private static final int DLS_CDL_QUERYSUPPORTED = 0x0012; + + private static final DLSID DLSID_GMInHardware = new DLSID(0x178f2f24, + 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); + private static final DLSID DLSID_GSInHardware = new DLSID(0x178f2f25, + 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); + private static final DLSID DLSID_XGInHardware = new DLSID(0x178f2f26, + 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); + private static final DLSID DLSID_SupportsDLS1 = new DLSID(0x178f2f27, + 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); + private static final DLSID DLSID_SupportsDLS2 = new DLSID(0xf14599e5, + 0x4689, 0x11d2, 0xaf, 0xa6, 0x0, 0xaa, 0x0, 0x24, 0xd8, 0xb6); + private static final DLSID DLSID_SampleMemorySize = new DLSID(0x178f2f28, + 0xc364, 0x11d1, 0xa7, 0x60, 0x00, 0x00, 0xf8, 0x75, 0xac, 0x12); + private static final DLSID DLSID_ManufacturersID = new DLSID(0xb03e1181, + 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); + private static final DLSID DLSID_ProductID = new DLSID(0xb03e1182, + 0x8095, 0x11d2, 0xa1, 0xef, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); + private static final DLSID DLSID_SamplePlaybackRate = new DLSID(0x2a91f713, + 0xa4bf, 0x11d2, 0xbb, 0xdf, 0x0, 0x60, 0x8, 0x33, 0xdb, 0xd8); + + private long major = -1; + private long minor = -1; + + private DLSInfo info = new DLSInfo(); + + private List instruments = new ArrayList(); + private List samples = new ArrayList(); + + private boolean largeFormat = false; + private File sampleFile; + + public DLSSoundbank() { + } + + public DLSSoundbank(URL url) throws IOException { + InputStream is = url.openStream(); + try { + readSoundbank(is); + } finally { + is.close(); + } + } + + public DLSSoundbank(File file) throws IOException { + largeFormat = true; + sampleFile = file; + InputStream is = new FileInputStream(file); + try { + readSoundbank(is); + } finally { + is.close(); + } + } + + public DLSSoundbank(InputStream inputstream) throws IOException { + readSoundbank(inputstream); + } + + private void readSoundbank(InputStream inputstream) throws IOException { + RIFFReader riff = new RIFFReader(inputstream); + if (!riff.getFormat().equals("RIFF")) { + throw new RIFFInvalidFormatException( + "Input stream is not a valid RIFF stream!"); + } + if (!riff.getType().equals("DLS ")) { + throw new RIFFInvalidFormatException( + "Input stream is not a valid DLS soundbank!"); + } + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("LIST")) { + if (chunk.getType().equals("INFO")) + readInfoChunk(chunk); + if (chunk.getType().equals("lins")) + readLinsChunk(chunk); + if (chunk.getType().equals("wvpl")) + readWvplChunk(chunk); + } else { + if (chunk.getFormat().equals("cdl ")) { + if (!readCdlChunk(chunk)) { + throw new RIFFInvalidFormatException( + "DLS file isn't supported!"); + } + } + if (chunk.getFormat().equals("colh")) { + // skipped because we will load the entire bank into memory + // long instrumentcount = chunk.readUnsignedInt(); + // System.out.println("instrumentcount = "+ instrumentcount); + } + if (chunk.getFormat().equals("ptbl")) { + // Pool Table Chunk + // skipped because we will load the entire bank into memory + } + if (chunk.getFormat().equals("vers")) { + major = chunk.readUnsignedInt(); + minor = chunk.readUnsignedInt(); + } + } + } + + for (Map.Entry entry : temp_rgnassign.entrySet()) { + entry.getKey().sample = samples.get((int)entry.getValue().longValue()); + } + + temp_rgnassign = null; + } + + private boolean cdlIsQuerySupported(DLSID uuid) { + return uuid.equals(DLSID_GMInHardware) + || uuid.equals(DLSID_GSInHardware) + || uuid.equals(DLSID_XGInHardware) + || uuid.equals(DLSID_SupportsDLS1) + || uuid.equals(DLSID_SupportsDLS2) + || uuid.equals(DLSID_SampleMemorySize) + || uuid.equals(DLSID_ManufacturersID) + || uuid.equals(DLSID_ProductID) + || uuid.equals(DLSID_SamplePlaybackRate); + } + + private long cdlQuery(DLSID uuid) { + if (uuid.equals(DLSID_GMInHardware)) + return 1; + if (uuid.equals(DLSID_GSInHardware)) + return 0; + if (uuid.equals(DLSID_XGInHardware)) + return 0; + if (uuid.equals(DLSID_SupportsDLS1)) + return 1; + if (uuid.equals(DLSID_SupportsDLS2)) + return 1; + if (uuid.equals(DLSID_SampleMemorySize)) + return Runtime.getRuntime().totalMemory(); + if (uuid.equals(DLSID_ManufacturersID)) + return 0; + if (uuid.equals(DLSID_ProductID)) + return 0; + if (uuid.equals(DLSID_SamplePlaybackRate)) + return 44100; + return 0; + } + + + // Reading cdl-ck Chunk + // "cdl " chunk can only appear inside : DLS,lart,lar2,rgn,rgn2 + private boolean readCdlChunk(RIFFReader riff) throws IOException { + + DLSID uuid; + long x; + long y; + Stack stack = new Stack(); + + while (riff.available() != 0) { + int opcode = riff.readUnsignedShort(); + switch (opcode) { + case DLS_CDL_AND: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(((x != 0) & (y != 0)) ? 1 : 0)); + break; + case DLS_CDL_OR: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(((x != 0) | (y != 0)) ? 1 : 0)); + break; + case DLS_CDL_XOR: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(((x != 0) ^ (y != 0)) ? 1 : 0)); + break; + case DLS_CDL_ADD: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(x + y)); + break; + case DLS_CDL_SUBTRACT: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(x - y)); + break; + case DLS_CDL_MULTIPLY: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(x * y)); + break; + case DLS_CDL_DIVIDE: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(x / y)); + break; + case DLS_CDL_LOGICAL_AND: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(((x != 0) & (y != 0)) ? 1 : 0)); + break; + case DLS_CDL_LOGICAL_OR: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long(((x != 0) | (y != 0)) ? 1 : 0)); + break; + case DLS_CDL_LT: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x < y) ? 1 : 0)); + break; + case DLS_CDL_LE: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x <= y) ? 1 : 0)); + break; + case DLS_CDL_GT: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x > y) ? 1 : 0)); + break; + case DLS_CDL_GE: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x >= y) ? 1 : 0)); + break; + case DLS_CDL_EQ: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x == y) ? 1 : 0)); + break; + case DLS_CDL_NOT: + x = stack.pop(); + y = stack.pop(); + stack.push(new Long((x == 0) ? 1 : 0)); + break; + case DLS_CDL_CONST: + stack.push(new Long(riff.readUnsignedInt())); + break; + case DLS_CDL_QUERY: + uuid = DLSID.read(riff); + stack.push(cdlQuery(uuid)); + break; + case DLS_CDL_QUERYSUPPORTED: + uuid = DLSID.read(riff); + stack.push(new Long(cdlIsQuerySupported(uuid) ? 1 : 0)); + break; + default: + break; + } + } + if (stack.isEmpty()) + return false; + + return stack.pop() == 1; + } + + private void readInfoChunk(RIFFReader riff) throws IOException { + info.name = null; + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("INAM")) + info.name = chunk.readString(chunk.available()); + else if (format.equals("ICRD")) + info.creationDate = chunk.readString(chunk.available()); + else if (format.equals("IENG")) + info.engineers = chunk.readString(chunk.available()); + else if (format.equals("IPRD")) + info.product = chunk.readString(chunk.available()); + else if (format.equals("ICOP")) + info.copyright = chunk.readString(chunk.available()); + else if (format.equals("ICMT")) + info.comments = chunk.readString(chunk.available()); + else if (format.equals("ISFT")) + info.tools = chunk.readString(chunk.available()); + else if (format.equals("IARL")) + info.archival_location = chunk.readString(chunk.available()); + else if (format.equals("IART")) + info.artist = chunk.readString(chunk.available()); + else if (format.equals("ICMS")) + info.commissioned = chunk.readString(chunk.available()); + else if (format.equals("IGNR")) + info.genre = chunk.readString(chunk.available()); + else if (format.equals("IKEY")) + info.keywords = chunk.readString(chunk.available()); + else if (format.equals("IMED")) + info.medium = chunk.readString(chunk.available()); + else if (format.equals("ISBJ")) + info.subject = chunk.readString(chunk.available()); + else if (format.equals("ISRC")) + info.source = chunk.readString(chunk.available()); + else if (format.equals("ISRF")) + info.source_form = chunk.readString(chunk.available()); + else if (format.equals("ITCH")) + info.technician = chunk.readString(chunk.available()); + } + } + + private void readLinsChunk(RIFFReader riff) throws IOException { + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("LIST")) { + if (chunk.getType().equals("ins ")) + readInsChunk(chunk); + } + } + } + + private void readInsChunk(RIFFReader riff) throws IOException { + DLSInstrument instrument = new DLSInstrument(this); + + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("LIST")) { + if (chunk.getType().equals("INFO")) { + readInsInfoChunk(instrument, chunk); + } + if (chunk.getType().equals("lrgn")) { + while (chunk.hasNextChunk()) { + RIFFReader subchunk = chunk.nextChunk(); + if (subchunk.getFormat().equals("LIST")) { + if (subchunk.getType().equals("rgn ")) { + DLSRegion split = new DLSRegion(); + if (readRgnChunk(split, subchunk)) + instrument.getRegions().add(split); + } + if (subchunk.getType().equals("rgn2")) { + // support for DLS level 2 regions + DLSRegion split = new DLSRegion(); + if (readRgnChunk(split, subchunk)) + instrument.getRegions().add(split); + } + } + } + } + if (chunk.getType().equals("lart")) { + List modlist = new ArrayList(); + while (chunk.hasNextChunk()) { + RIFFReader subchunk = chunk.nextChunk(); + if (chunk.getFormat().equals("cdl ")) { + if (!readCdlChunk(chunk)) { + modlist.clear(); + break; + } + } + if (subchunk.getFormat().equals("art1")) + readArt1Chunk(modlist, subchunk); + } + instrument.getModulators().addAll(modlist); + } + if (chunk.getType().equals("lar2")) { + // support for DLS level 2 ART + List modlist = new ArrayList(); + while (chunk.hasNextChunk()) { + RIFFReader subchunk = chunk.nextChunk(); + if (chunk.getFormat().equals("cdl ")) { + if (!readCdlChunk(chunk)) { + modlist.clear(); + break; + } + } + if (subchunk.getFormat().equals("art2")) + readArt2Chunk(modlist, subchunk); + } + instrument.getModulators().addAll(modlist); + } + } else { + if (format.equals("dlid")) { + instrument.guid = new byte[16]; + chunk.read(instrument.guid); + } + if (format.equals("insh")) { + chunk.readUnsignedInt(); // Read Region Count - ignored + + int bank = chunk.read(); // LSB + bank += (chunk.read() & 127) << 7; // MSB + chunk.read(); // Read Reserved byte + int drumins = chunk.read(); // Drum Instrument + + int id = chunk.read() & 127; // Read only first 7 bits + chunk.read(); // Read Reserved byte + chunk.read(); // Read Reserved byte + chunk.read(); // Read Reserved byte + + instrument.bank = bank; + instrument.preset = (int) id; + instrument.druminstrument = (drumins & 128) > 0; + //System.out.println("bank="+bank+" drumkit="+drumkit + // +" id="+id); + } + + } + } + instruments.add(instrument); + } + + private void readArt1Chunk(List modulators, RIFFReader riff) + throws IOException { + long size = riff.readUnsignedInt(); + long count = riff.readUnsignedInt(); + + if (size - 8 != 0) + riff.skip(size - 8); + + for (int i = 0; i < count; i++) { + DLSModulator modulator = new DLSModulator(); + modulator.version = 1; + modulator.source = riff.readUnsignedShort(); + modulator.control = riff.readUnsignedShort(); + modulator.destination = riff.readUnsignedShort(); + modulator.transform = riff.readUnsignedShort(); + modulator.scale = riff.readInt(); + modulators.add(modulator); + } + } + + private void readArt2Chunk(List modulators, RIFFReader riff) + throws IOException { + long size = riff.readUnsignedInt(); + long count = riff.readUnsignedInt(); + + if (size - 8 != 0) + riff.skip(size - 8); + + for (int i = 0; i < count; i++) { + DLSModulator modulator = new DLSModulator(); + modulator.version = 2; + modulator.source = riff.readUnsignedShort(); + modulator.control = riff.readUnsignedShort(); + modulator.destination = riff.readUnsignedShort(); + modulator.transform = riff.readUnsignedShort(); + modulator.scale = riff.readInt(); + modulators.add(modulator); + } + } + + private Map temp_rgnassign = new HashMap(); + + private boolean readRgnChunk(DLSRegion split, RIFFReader riff) + throws IOException { + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("LIST")) { + if (chunk.getType().equals("lart")) { + List modlist = new ArrayList(); + while (chunk.hasNextChunk()) { + RIFFReader subchunk = chunk.nextChunk(); + if (chunk.getFormat().equals("cdl ")) { + if (!readCdlChunk(chunk)) { + modlist.clear(); + break; + } + } + if (subchunk.getFormat().equals("art1")) + readArt1Chunk(modlist, subchunk); + } + split.getModulators().addAll(modlist); + } + if (chunk.getType().equals("lar2")) { + // support for DLS level 2 ART + List modlist = new ArrayList(); + while (chunk.hasNextChunk()) { + RIFFReader subchunk = chunk.nextChunk(); + if (chunk.getFormat().equals("cdl ")) { + if (!readCdlChunk(chunk)) { + modlist.clear(); + break; + } + } + if (subchunk.getFormat().equals("art2")) + readArt2Chunk(modlist, subchunk); + } + split.getModulators().addAll(modlist); + } + } else { + + if (format.equals("cdl ")) { + if (!readCdlChunk(chunk)) + return false; + } + if (format.equals("rgnh")) { + split.keyfrom = chunk.readUnsignedShort(); + split.keyto = chunk.readUnsignedShort(); + split.velfrom = chunk.readUnsignedShort(); + split.velto = chunk.readUnsignedShort(); + split.options = chunk.readUnsignedShort(); + split.exclusiveClass = chunk.readUnsignedShort(); + } + if (format.equals("wlnk")) { + split.fusoptions = chunk.readUnsignedShort(); + split.phasegroup = chunk.readUnsignedShort(); + split.channel = chunk.readUnsignedInt(); + long sampleid = chunk.readUnsignedInt(); + temp_rgnassign.put(split, sampleid); + } + if (format.equals("wsmp")) { + split.sampleoptions = new DLSSampleOptions(); + readWsmpChunk(split.sampleoptions, chunk); + } + } + } + return true; + } + + private void readWsmpChunk(DLSSampleOptions sampleOptions, RIFFReader riff) + throws IOException { + long size = riff.readUnsignedInt(); + sampleOptions.unitynote = riff.readUnsignedShort(); + sampleOptions.finetune = riff.readShort(); + sampleOptions.attenuation = riff.readInt(); + sampleOptions.options = riff.readUnsignedInt(); + long loops = riff.readInt(); + + if (size > 20) + riff.skip(size - 20); + + for (int i = 0; i < loops; i++) { + DLSSampleLoop loop = new DLSSampleLoop(); + long size2 = riff.readUnsignedInt(); + loop.type = riff.readUnsignedInt(); + loop.start = riff.readUnsignedInt(); + loop.length = riff.readUnsignedInt(); + sampleOptions.loops.add(loop); + if (size2 > 16) + riff.skip(size2 - 16); + } + } + + private void readInsInfoChunk(DLSInstrument dlsinstrument, RIFFReader riff) + throws IOException { + dlsinstrument.info.name = null; + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("INAM")) { + dlsinstrument.info.name = chunk.readString(chunk.available()); + } else if (format.equals("ICRD")) { + dlsinstrument.info.creationDate = + chunk.readString(chunk.available()); + } else if (format.equals("IENG")) { + dlsinstrument.info.engineers = + chunk.readString(chunk.available()); + } else if (format.equals("IPRD")) { + dlsinstrument.info.product = chunk.readString(chunk.available()); + } else if (format.equals("ICOP")) { + dlsinstrument.info.copyright = + chunk.readString(chunk.available()); + } else if (format.equals("ICMT")) { + dlsinstrument.info.comments = + chunk.readString(chunk.available()); + } else if (format.equals("ISFT")) { + dlsinstrument.info.tools = chunk.readString(chunk.available()); + } else if (format.equals("IARL")) { + dlsinstrument.info.archival_location = + chunk.readString(chunk.available()); + } else if (format.equals("IART")) { + dlsinstrument.info.artist = chunk.readString(chunk.available()); + } else if (format.equals("ICMS")) { + dlsinstrument.info.commissioned = + chunk.readString(chunk.available()); + } else if (format.equals("IGNR")) { + dlsinstrument.info.genre = chunk.readString(chunk.available()); + } else if (format.equals("IKEY")) { + dlsinstrument.info.keywords = + chunk.readString(chunk.available()); + } else if (format.equals("IMED")) { + dlsinstrument.info.medium = chunk.readString(chunk.available()); + } else if (format.equals("ISBJ")) { + dlsinstrument.info.subject = chunk.readString(chunk.available()); + } else if (format.equals("ISRC")) { + dlsinstrument.info.source = chunk.readString(chunk.available()); + } else if (format.equals("ISRF")) { + dlsinstrument.info.source_form = + chunk.readString(chunk.available()); + } else if (format.equals("ITCH")) { + dlsinstrument.info.technician = + chunk.readString(chunk.available()); + } + } + } + + private void readWvplChunk(RIFFReader riff) throws IOException { + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("LIST")) { + if (chunk.getType().equals("wave")) + readWaveChunk(chunk); + } + } + } + + private void readWaveChunk(RIFFReader riff) throws IOException { + DLSSample sample = new DLSSample(this); + + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("LIST")) { + if (chunk.getType().equals("INFO")) { + readWaveInfoChunk(sample, chunk); + } + } else { + if (format.equals("dlid")) { + sample.guid = new byte[16]; + chunk.read(sample.guid); + } + + if (format.equals("fmt ")) { + int sampleformat = chunk.readUnsignedShort(); + if (sampleformat != 1 && sampleformat != 3) { + throw new RIFFInvalidDataException( + "Only PCM samples are supported!"); + } + int channels = chunk.readUnsignedShort(); + long samplerate = chunk.readUnsignedInt(); + // bytes per sec + /* long framerate = */ chunk.readUnsignedInt(); + // block align, framesize + int framesize = chunk.readUnsignedShort(); + int bits = chunk.readUnsignedShort(); + AudioFormat audioformat = null; + if (sampleformat == 1) { + if (bits == 8) { + audioformat = new AudioFormat( + Encoding.PCM_UNSIGNED, samplerate, bits, + channels, framesize, samplerate, false); + } else { + audioformat = new AudioFormat( + Encoding.PCM_SIGNED, samplerate, bits, + channels, framesize, samplerate, false); + } + } + if (sampleformat == 3) { + audioformat = new AudioFormat( + AudioFloatConverter.PCM_FLOAT, samplerate, bits, + channels, framesize, samplerate, false); + } + + sample.format = audioformat; + } + + if (format.equals("data")) { + if (largeFormat) { + sample.setData(new ModelByteBuffer(sampleFile, + chunk.getFilePointer(), chunk.available())); + } else { + byte[] buffer = new byte[chunk.available()]; + // chunk.read(buffer); + sample.setData(buffer); + + int read = 0; + int avail = chunk.available(); + while (read != avail) { + if (avail - read > 65536) { + chunk.read(buffer, read, 65536); + read += 65536; + } else { + chunk.read(buffer, read, avail - read); + read = avail; + } + } + } + } + + if (format.equals("wsmp")) { + sample.sampleoptions = new DLSSampleOptions(); + readWsmpChunk(sample.sampleoptions, chunk); + } + } + } + + samples.add(sample); + + } + + private void readWaveInfoChunk(DLSSample dlssample, RIFFReader riff) + throws IOException { + dlssample.info.name = null; + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("INAM")) { + dlssample.info.name = chunk.readString(chunk.available()); + } else if (format.equals("ICRD")) { + dlssample.info.creationDate = + chunk.readString(chunk.available()); + } else if (format.equals("IENG")) { + dlssample.info.engineers = chunk.readString(chunk.available()); + } else if (format.equals("IPRD")) { + dlssample.info.product = chunk.readString(chunk.available()); + } else if (format.equals("ICOP")) { + dlssample.info.copyright = chunk.readString(chunk.available()); + } else if (format.equals("ICMT")) { + dlssample.info.comments = chunk.readString(chunk.available()); + } else if (format.equals("ISFT")) { + dlssample.info.tools = chunk.readString(chunk.available()); + } else if (format.equals("IARL")) { + dlssample.info.archival_location = + chunk.readString(chunk.available()); + } else if (format.equals("IART")) { + dlssample.info.artist = chunk.readString(chunk.available()); + } else if (format.equals("ICMS")) { + dlssample.info.commissioned = + chunk.readString(chunk.available()); + } else if (format.equals("IGNR")) { + dlssample.info.genre = chunk.readString(chunk.available()); + } else if (format.equals("IKEY")) { + dlssample.info.keywords = chunk.readString(chunk.available()); + } else if (format.equals("IMED")) { + dlssample.info.medium = chunk.readString(chunk.available()); + } else if (format.equals("ISBJ")) { + dlssample.info.subject = chunk.readString(chunk.available()); + } else if (format.equals("ISRC")) { + dlssample.info.source = chunk.readString(chunk.available()); + } else if (format.equals("ISRF")) { + dlssample.info.source_form = chunk.readString(chunk.available()); + } else if (format.equals("ITCH")) { + dlssample.info.technician = chunk.readString(chunk.available()); + } + } + } + + public void save(String name) throws IOException { + writeSoundbank(new RIFFWriter(name, "DLS ")); + } + + public void save(File file) throws IOException { + writeSoundbank(new RIFFWriter(file, "DLS ")); + } + + public void save(OutputStream out) throws IOException { + writeSoundbank(new RIFFWriter(out, "DLS ")); + } + + private void writeSoundbank(RIFFWriter writer) throws IOException { + RIFFWriter colh_chunk = writer.writeChunk("colh"); + colh_chunk.writeUnsignedInt(instruments.size()); + + if (major != -1 && minor != -1) { + RIFFWriter vers_chunk = writer.writeChunk("vers"); + vers_chunk.writeUnsignedInt(major); + vers_chunk.writeUnsignedInt(minor); + } + + writeInstruments(writer.writeList("lins")); + + RIFFWriter ptbl = writer.writeChunk("ptbl"); + ptbl.writeUnsignedInt(8); + ptbl.writeUnsignedInt(samples.size()); + long ptbl_offset = writer.getFilePointer(); + for (int i = 0; i < samples.size(); i++) + ptbl.writeUnsignedInt(0); + + RIFFWriter wvpl = writer.writeList("wvpl"); + long off = wvpl.getFilePointer(); + List offsettable = new ArrayList(); + for (DLSSample sample : samples) { + offsettable.add(new Long(wvpl.getFilePointer() - off)); + writeSample(wvpl.writeList("wave"), sample); + } + + // small cheat, we are going to rewrite data back in wvpl + long bak = writer.getFilePointer(); + writer.seek(ptbl_offset); + writer.setWriteOverride(true); + for (Long offset : offsettable) + writer.writeUnsignedInt(offset.longValue()); + writer.setWriteOverride(false); + writer.seek(bak); + + writeInfo(writer.writeList("INFO"), info); + + writer.close(); + } + + private void writeSample(RIFFWriter writer, DLSSample sample) + throws IOException { + + AudioFormat audioformat = sample.getFormat(); + + Encoding encoding = audioformat.getEncoding(); + float sampleRate = audioformat.getSampleRate(); + int sampleSizeInBits = audioformat.getSampleSizeInBits(); + int channels = audioformat.getChannels(); + int frameSize = audioformat.getFrameSize(); + float frameRate = audioformat.getFrameRate(); + boolean bigEndian = audioformat.isBigEndian(); + + boolean convert_needed = false; + + if (audioformat.getSampleSizeInBits() == 8) { + if (!encoding.equals(Encoding.PCM_UNSIGNED)) { + encoding = Encoding.PCM_UNSIGNED; + convert_needed = true; + } + } else { + if (!encoding.equals(Encoding.PCM_SIGNED)) { + encoding = Encoding.PCM_SIGNED; + convert_needed = true; + } + if (bigEndian) { + bigEndian = false; + convert_needed = true; + } + } + + if (convert_needed) { + audioformat = new AudioFormat(encoding, sampleRate, + sampleSizeInBits, channels, frameSize, frameRate, bigEndian); + } + + // fmt + RIFFWriter fmt_chunk = writer.writeChunk("fmt "); + int sampleformat = 0; + if (audioformat.getEncoding().equals(Encoding.PCM_UNSIGNED)) + sampleformat = 1; + else if (audioformat.getEncoding().equals(Encoding.PCM_SIGNED)) + sampleformat = 1; + else if (audioformat.getEncoding().equals(AudioFloatConverter.PCM_FLOAT)) + sampleformat = 3; + + fmt_chunk.writeUnsignedShort(sampleformat); + fmt_chunk.writeUnsignedShort(audioformat.getChannels()); + fmt_chunk.writeUnsignedInt((long) audioformat.getSampleRate()); + long srate = (long)audioformat.getSampleRate(); + srate *= audioformat.getChannels(); + srate *= audioformat.getSampleSizeInBits() / 8; + //fmt_chunk.writeUnsignedInt((long)audioformat.getFrameRate()); + fmt_chunk.writeUnsignedInt(srate); + fmt_chunk.writeUnsignedShort(audioformat.getFrameSize()); + fmt_chunk.writeUnsignedShort(audioformat.getSampleSizeInBits()); + fmt_chunk.write(0); + fmt_chunk.write(0); + + writeSampleOptions(writer.writeChunk("wsmp"), sample.sampleoptions); + + if (convert_needed) { + RIFFWriter data_chunk = writer.writeChunk("data"); + AudioInputStream stream = AudioSystem.getAudioInputStream( + audioformat, (AudioInputStream)sample.getData()); + byte[] buff = new byte[1024]; + int ret; + while ((ret = stream.read(buff)) != -1) { + data_chunk.write(buff, 0, ret); + } + } else { + RIFFWriter data_chunk = writer.writeChunk("data"); + ModelByteBuffer databuff = sample.getDataBuffer(); + databuff.writeTo(data_chunk); + /* + data_chunk.write(databuff.array(), + databuff.arrayOffset(), + databuff.capacity()); + */ + } + + writeInfo(writer.writeList("INFO"), sample.info); + } + + private void writeInstruments(RIFFWriter writer) throws IOException { + for (DLSInstrument instrument : instruments) { + writeInstrument(writer.writeList("ins "), instrument); + } + } + + private void writeInstrument(RIFFWriter writer, DLSInstrument instrument) + throws IOException { + + int art1_count = 0; + int art2_count = 0; + for (DLSModulator modulator : instrument.getModulators()) { + if (modulator.version == 1) + art1_count++; + if (modulator.version == 2) + art2_count++; + } + for (DLSRegion region : instrument.regions) { + for (DLSModulator modulator : region.getModulators()) { + if (modulator.version == 1) + art1_count++; + if (modulator.version == 2) + art2_count++; + } + } + + int version = 1; + if (art2_count > 0) + version = 2; + + RIFFWriter insh_chunk = writer.writeChunk("insh"); + insh_chunk.writeUnsignedInt(instrument.getRegions().size()); + insh_chunk.writeUnsignedInt(instrument.bank + + (instrument.druminstrument ? 2147483648L : 0)); + insh_chunk.writeUnsignedInt(instrument.preset); + + RIFFWriter lrgn = writer.writeList("lrgn"); + for (DLSRegion region: instrument.regions) + writeRegion(lrgn, region, version); + + writeArticulators(writer, instrument.getModulators()); + + writeInfo(writer.writeList("INFO"), instrument.info); + + } + + private void writeArticulators(RIFFWriter writer, + List modulators) throws IOException { + int art1_count = 0; + int art2_count = 0; + for (DLSModulator modulator : modulators) { + if (modulator.version == 1) + art1_count++; + if (modulator.version == 2) + art2_count++; + } + if (art1_count > 0) { + RIFFWriter lar1 = writer.writeList("lart"); + RIFFWriter art1 = lar1.writeChunk("art1"); + art1.writeUnsignedInt(8); + art1.writeUnsignedInt(art1_count); + for (DLSModulator modulator : modulators) { + if (modulator.version == 1) { + art1.writeUnsignedShort(modulator.source); + art1.writeUnsignedShort(modulator.control); + art1.writeUnsignedShort(modulator.destination); + art1.writeUnsignedShort(modulator.transform); + art1.writeInt(modulator.scale); + } + } + } + if (art2_count > 0) { + RIFFWriter lar2 = writer.writeList("lar2"); + RIFFWriter art2 = lar2.writeChunk("art2"); + art2.writeUnsignedInt(8); + art2.writeUnsignedInt(art2_count); + for (DLSModulator modulator : modulators) { + if (modulator.version == 2) { + art2.writeUnsignedShort(modulator.source); + art2.writeUnsignedShort(modulator.control); + art2.writeUnsignedShort(modulator.destination); + art2.writeUnsignedShort(modulator.transform); + art2.writeInt(modulator.scale); + } + } + } + } + + private void writeRegion(RIFFWriter writer, DLSRegion region, int version) + throws IOException { + RIFFWriter rgns = null; + if (version == 1) + rgns = writer.writeList("rgn "); + if (version == 2) + rgns = writer.writeList("rgn2"); + if (rgns == null) + return; + + RIFFWriter rgnh = rgns.writeChunk("rgnh"); + rgnh.writeUnsignedShort(region.keyfrom); + rgnh.writeUnsignedShort(region.keyto); + rgnh.writeUnsignedShort(region.velfrom); + rgnh.writeUnsignedShort(region.velto); + rgnh.writeUnsignedShort(region.options); + rgnh.writeUnsignedShort(region.exclusiveClass); + + if (region.sampleoptions != null) + writeSampleOptions(rgns.writeChunk("wsmp"), region.sampleoptions); + + if (region.sample != null) { + if (samples.indexOf(region.sample) != -1) { + RIFFWriter wlnk = rgns.writeChunk("wlnk"); + wlnk.writeUnsignedShort(region.fusoptions); + wlnk.writeUnsignedShort(region.phasegroup); + wlnk.writeUnsignedInt(region.channel); + wlnk.writeUnsignedInt(samples.indexOf(region.sample)); + } + } + writeArticulators(rgns, region.getModulators()); + rgns.close(); + } + + private void writeSampleOptions(RIFFWriter wsmp, + DLSSampleOptions sampleoptions) throws IOException { + wsmp.writeUnsignedInt(20); + wsmp.writeUnsignedShort(sampleoptions.unitynote); + wsmp.writeShort(sampleoptions.finetune); + wsmp.writeInt(sampleoptions.attenuation); + wsmp.writeUnsignedInt(sampleoptions.options); + wsmp.writeInt(sampleoptions.loops.size()); + + for (DLSSampleLoop loop : sampleoptions.loops) { + wsmp.writeUnsignedInt(16); + wsmp.writeUnsignedInt(loop.type); + wsmp.writeUnsignedInt(loop.start); + wsmp.writeUnsignedInt(loop.length); + } + } + + private void writeInfoStringChunk(RIFFWriter writer, + String name, String value) throws IOException { + if (value == null) + return; + RIFFWriter chunk = writer.writeChunk(name); + chunk.writeString(value); + int len = value.getBytes("ascii").length; + chunk.write(0); + len++; + if (len % 2 != 0) + chunk.write(0); + } + + private void writeInfo(RIFFWriter writer, DLSInfo info) throws IOException { + writeInfoStringChunk(writer, "INAM", info.name); + writeInfoStringChunk(writer, "ICRD", info.creationDate); + writeInfoStringChunk(writer, "IENG", info.engineers); + writeInfoStringChunk(writer, "IPRD", info.product); + writeInfoStringChunk(writer, "ICOP", info.copyright); + writeInfoStringChunk(writer, "ICMT", info.comments); + writeInfoStringChunk(writer, "ISFT", info.tools); + writeInfoStringChunk(writer, "IARL", info.archival_location); + writeInfoStringChunk(writer, "IART", info.artist); + writeInfoStringChunk(writer, "ICMS", info.commissioned); + writeInfoStringChunk(writer, "IGNR", info.genre); + writeInfoStringChunk(writer, "IKEY", info.keywords); + writeInfoStringChunk(writer, "IMED", info.medium); + writeInfoStringChunk(writer, "ISBJ", info.subject); + writeInfoStringChunk(writer, "ISRC", info.source); + writeInfoStringChunk(writer, "ISRF", info.source_form); + writeInfoStringChunk(writer, "ITCH", info.technician); + } + + public DLSInfo getInfo() { + return info; + } + + public String getName() { + return info.name; + } + + public String getVersion() { + return major + "." + minor; + } + + public String getVendor() { + return info.engineers; + } + + public String getDescription() { + return info.comments; + } + + public void setName(String s) { + info.name = s; + } + + public void setVendor(String s) { + info.engineers = s; + } + + public void setDescription(String s) { + info.comments = s; + } + + public SoundbankResource[] getResources() { + SoundbankResource[] resources = new SoundbankResource[samples.size()]; + int j = 0; + for (int i = 0; i < samples.size(); i++) + resources[j++] = samples.get(i); + return resources; + } + + public DLSInstrument[] getInstruments() { + DLSInstrument[] inslist_array = + instruments.toArray(new DLSInstrument[instruments.size()]); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; + } + + public DLSSample[] getSamples() { + return samples.toArray(new DLSSample[samples.size()]); + } + + public Instrument getInstrument(Patch patch) { + int program = patch.getProgram(); + int bank = patch.getBank(); + boolean percussion = false; + if (patch instanceof ModelPatch) + percussion = ((ModelPatch) patch).isPercussion(); + for (Instrument instrument : instruments) { + Patch patch2 = instrument.getPatch(); + int program2 = patch2.getProgram(); + int bank2 = patch2.getBank(); + if (program == program2 && bank == bank2) { + boolean percussion2 = false; + if (patch2 instanceof ModelPatch) + percussion2 = ((ModelPatch) patch2).isPercussion(); + if (percussion == percussion2) + return instrument; + } + } + return null; + } + + public void addResource(SoundbankResource resource) { + if (resource instanceof DLSInstrument) + instruments.add((DLSInstrument) resource); + if (resource instanceof DLSSample) + samples.add((DLSSample) resource); + } + + public void removeResource(SoundbankResource resource) { + if (resource instanceof DLSInstrument) + instruments.remove((DLSInstrument) resource); + if (resource instanceof DLSSample) + samples.remove((DLSSample) resource); + } + + public void addInstrument(DLSInstrument resource) { + instruments.add(resource); + } + + public void removeInstrument(DLSInstrument resource) { + instruments.remove(resource); + } + + public long getMajor() { + return major; + } + + public void setMajor(long major) { + this.major = major; + } + + public long getMinor() { + return minor; + } + + public void setMinor(long minor) { + this.minor = minor; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/DLSSoundbankReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/DLSSoundbankReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.media.sound; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.Soundbank; +import javax.sound.midi.spi.SoundbankReader; + +/** + * This class is used to connect the DLSSoundBank class + * to the SoundbankReader SPI interface. + * + * @author Karl Helgason + */ +public class DLSSoundbankReader extends SoundbankReader { + + public Soundbank getSoundbank(URL url) + throws InvalidMidiDataException, IOException { + try { + return new DLSSoundbank(url); + } catch (RIFFInvalidFormatException e) { + return null; + } + } + + public Soundbank getSoundbank(InputStream stream) + throws InvalidMidiDataException, IOException { + try { + stream.mark(512); + return new DLSSoundbank(stream); + } catch (RIFFInvalidFormatException e) { + stream.reset(); + return null; + } + } + + public Soundbank getSoundbank(File file) + throws InvalidMidiDataException, IOException { + if (!file.getPath().toLowerCase().endsWith(".dls")) + return null; + try { + return new DLSSoundbank(file); + } catch (RIFFInvalidFormatException e) { + return null; + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/EmergencySoundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/EmergencySoundbank.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,2695 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.Random; + +import javax.sound.midi.Patch; +import javax.sound.sampled.AudioFormat; + +/** + * Emergency Soundbank generator. + * Used when no other default soundbank can be found. + * + * @author Karl Helgason + */ +public class EmergencySoundbank { + + public static String[] general_midi_instruments = { + "Acoustic Grand Piano", + "Bright Acoustic Piano", + "Electric Grand Piano", + "Honky-tonk Piano", + "Electric Piano 1", + "Electric Piano 2", + "Harpsichord", + "Clavi", + "Celesta", + "Glockenspiel", + "Music Box", + "Vibraphone", + "Marimba", + "Xylophone", + "Tubular Bells", + "Dulcimer", + "Drawbar Organ", + "Percussive Organ", + "Rock Organ", + "Church Organ", + "Reed Organ", + "Accordion", + "Harmonica", + "Tango Accordion", + "Acoustic Guitar (nylon)", + "Acoustic Guitar (steel)", + "Electric Guitar (jazz)", + "Electric Guitar (clean)", + "Electric Guitar (muted)", + "Overdriven Guitar", + "Distortion Guitar", + "Guitar harmonics", + "Acoustic Bass", + "Electric Bass (finger)", + "Electric Bass (pick)", + "Fretless Bass", + "Slap Bass 1", + "Slap Bass 2", + "Synth Bass 1", + "Synth Bass 2", + "Violin", + "Viola", + "Cello", + "Contrabass", + "Tremolo Strings", + "Pizzicato Strings", + "Orchestral Harp", + "Timpani", + "String Ensemble 1", + "String Ensemble 2", + "SynthStrings 1", + "SynthStrings 2", + "Choir Aahs", + "Voice Oohs", + "Synth Voice", + "Orchestra Hit", + "Trumpet", + "Trombone", + "Tuba", + "Muted Trumpet", + "French Horn", + "Brass Section", + "SynthBrass 1", + "SynthBrass 2", + "Soprano Sax", + "Alto Sax", + "Tenor Sax", + "Baritone Sax", + "Oboe", + "English Horn", + "Bassoon", + "Clarinet", + "Piccolo", + "Flute", + "Recorder", + "Pan Flute", + "Blown Bottle", + "Shakuhachi", + "Whistle", + "Ocarina", + "Lead 1 (square)", + "Lead 2 (sawtooth)", + "Lead 3 (calliope)", + "Lead 4 (chiff)", + "Lead 5 (charang)", + "Lead 6 (voice)", + "Lead 7 (fifths)", + "Lead 8 (bass + lead)", + "Pad 1 (new age)", + "Pad 2 (warm)", + "Pad 3 (polysynth)", + "Pad 4 (choir)", + "Pad 5 (bowed)", + "Pad 6 (metallic)", + "Pad 7 (halo)", + "Pad 8 (sweep)", + "FX 1 (rain)", + "FX 2 (soundtrack)", + "FX 3 (crystal)", + "FX 4 (atmosphere)", + "FX 5 (brightness)", + "FX 6 (goblins)", + "FX 7 (echoes)", + "FX 8 (sci-fi)", + "Sitar", + "Banjo", + "Shamisen", + "Koto", + "Kalimba", + "Bag pipe", + "Fiddle", + "Shanai", + "Tinkle Bell", + "Agogo", + "Steel Drums", + "Woodblock", + "Taiko Drum", + "Melodic Tom", + "Synth Drum", + "Reverse Cymbal", + "Guitar Fret Noise", + "Breath Noise", + "Seashore", + "Bird Tweet", + "Telephone Ring", + "Helicopter", + "Applause", + "Gunshot" + }; + + public static SF2Soundbank createSoundbank() throws Exception { + SF2Soundbank sf2 = new SF2Soundbank(); + sf2.setName("Emergency GM sound set"); + sf2.setVendor("Generated"); + sf2.setDescription("Emergency generated soundbank"); + + /* + * percussion instruments + */ + + SF2Layer bass_drum = new_bass_drum(sf2); + SF2Layer snare_drum = new_snare_drum(sf2); + SF2Layer tom = new_tom(sf2); + SF2Layer open_hihat = new_open_hihat(sf2); + SF2Layer closed_hihat = new_closed_hihat(sf2); + SF2Layer crash_cymbal = new_crash_cymbal(sf2); + SF2Layer side_stick = new_side_stick(sf2); + + SF2Layer[] drums = new SF2Layer[128]; + drums[35] = bass_drum; + drums[36] = bass_drum; + drums[38] = snare_drum; + drums[40] = snare_drum; + drums[41] = tom; + drums[43] = tom; + drums[45] = tom; + drums[47] = tom; + drums[48] = tom; + drums[50] = tom; + drums[42] = closed_hihat; + drums[44] = closed_hihat; + drums[46] = open_hihat; + drums[49] = crash_cymbal; + drums[51] = crash_cymbal; + drums[52] = crash_cymbal; + drums[55] = crash_cymbal; + drums[57] = crash_cymbal; + drums[59] = crash_cymbal; + + // Use side_stick for missing drums: + drums[37] = side_stick; + drums[39] = side_stick; + drums[53] = side_stick; + drums[54] = side_stick; + drums[56] = side_stick; + drums[58] = side_stick; + drums[69] = side_stick; + drums[70] = side_stick; + drums[75] = side_stick; + drums[60] = side_stick; + drums[61] = side_stick; + drums[62] = side_stick; + drums[63] = side_stick; + drums[64] = side_stick; + drums[65] = side_stick; + drums[66] = side_stick; + drums[67] = side_stick; + drums[68] = side_stick; + drums[71] = side_stick; + drums[72] = side_stick; + drums[73] = side_stick; + drums[74] = side_stick; + drums[76] = side_stick; + drums[77] = side_stick; + drums[78] = side_stick; + drums[79] = side_stick; + drums[80] = side_stick; + drums[81] = side_stick; + + + SF2Instrument drum_instrument = new SF2Instrument(sf2); + drum_instrument.setName("Standard Kit"); + drum_instrument.setPatch(new ModelPatch(0, 0, true)); + sf2.addInstrument(drum_instrument); + for (int i = 0; i < drums.length; i++) { + if (drums[i] != null) { + SF2InstrumentRegion region = new SF2InstrumentRegion(); + region.setLayer(drums[i]); + region.putBytes(SF2InstrumentRegion.GENERATOR_KEYRANGE, + new byte[]{(byte) i, (byte) i}); + drum_instrument.getRegions().add(region); + } + } + + + /* + * melodic instruments + */ + + SF2Layer gpiano = new_gpiano(sf2); + SF2Layer gpiano2 = new_gpiano2(sf2); + SF2Layer gpiano_hammer = new_piano_hammer(sf2); + SF2Layer piano1 = new_piano1(sf2); + SF2Layer epiano1 = new_epiano1(sf2); + SF2Layer epiano2 = new_epiano2(sf2); + + SF2Layer guitar = new_guitar1(sf2); + SF2Layer guitar_pick = new_guitar_pick(sf2); + SF2Layer guitar_dist = new_guitar_dist(sf2); + SF2Layer bass1 = new_bass1(sf2); + SF2Layer bass2 = new_bass2(sf2); + SF2Layer synthbass = new_synthbass(sf2); + SF2Layer string2 = new_string2(sf2); + SF2Layer orchhit = new_orchhit(sf2); + SF2Layer choir = new_choir(sf2); + SF2Layer solostring = new_solostring(sf2); + SF2Layer organ = new_organ(sf2); + SF2Layer ch_organ = new_ch_organ(sf2); + SF2Layer bell = new_bell(sf2); + SF2Layer flute = new_flute(sf2); + + SF2Layer timpani = new_timpani(sf2); + SF2Layer melodic_toms = new_melodic_toms(sf2); + SF2Layer trumpet = new_trumpet(sf2); + SF2Layer trombone = new_trombone(sf2); + SF2Layer brass_section = new_brass_section(sf2); + SF2Layer horn = new_horn(sf2); + SF2Layer sax = new_sax(sf2); + SF2Layer oboe = new_oboe(sf2); + SF2Layer bassoon = new_bassoon(sf2); + SF2Layer clarinet = new_clarinet(sf2); + SF2Layer reverse_cymbal = new_reverse_cymbal(sf2); + + SF2Layer defaultsound = piano1; + + newInstrument(sf2, "Piano", new Patch(0, 0), gpiano, gpiano_hammer); + newInstrument(sf2, "Piano", new Patch(0, 1), gpiano2, gpiano_hammer); + newInstrument(sf2, "Piano", new Patch(0, 2), piano1); + { + SF2Instrument ins = newInstrument(sf2, "Honky-tonk Piano", + new Patch(0, 3), piano1, piano1); + SF2InstrumentRegion region = ins.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 80); + region.putInteger(SF2Region.GENERATOR_FINETUNE, 30); + region = ins.getRegions().get(1); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 30); + } + newInstrument(sf2, "Rhodes", new Patch(0, 4), epiano2); + newInstrument(sf2, "Rhodes", new Patch(0, 5), epiano2); + newInstrument(sf2, "Clavinet", new Patch(0, 6), epiano1); + newInstrument(sf2, "Clavinet", new Patch(0, 7), epiano1); + newInstrument(sf2, "Rhodes", new Patch(0, 8), epiano2); + newInstrument(sf2, "Bell", new Patch(0, 9), bell); + newInstrument(sf2, "Bell", new Patch(0, 10), bell); + newInstrument(sf2, "Vibraphone", new Patch(0, 11), bell); + newInstrument(sf2, "Marimba", new Patch(0, 12), bell); + newInstrument(sf2, "Marimba", new Patch(0, 13), bell); + newInstrument(sf2, "Bell", new Patch(0, 14), bell); + newInstrument(sf2, "Rock Organ", new Patch(0, 15), organ); + newInstrument(sf2, "Rock Organ", new Patch(0, 16), organ); + newInstrument(sf2, "Perc Organ", new Patch(0, 17), organ); + newInstrument(sf2, "Rock Organ", new Patch(0, 18), organ); + newInstrument(sf2, "Church Organ", new Patch(0, 19), ch_organ); + newInstrument(sf2, "Accordion", new Patch(0, 20), organ); + newInstrument(sf2, "Accordion", new Patch(0, 21), organ); + newInstrument(sf2, "Accordion", new Patch(0, 22), organ); + newInstrument(sf2, "Accordion", new Patch(0, 23), organ); + newInstrument(sf2, "Guitar", new Patch(0, 24), guitar, guitar_pick); + newInstrument(sf2, "Guitar", new Patch(0, 25), guitar, guitar_pick); + newInstrument(sf2, "Guitar", new Patch(0, 26), guitar, guitar_pick); + newInstrument(sf2, "Guitar", new Patch(0, 27), guitar, guitar_pick); + newInstrument(sf2, "Guitar", new Patch(0, 28), guitar, guitar_pick); + newInstrument(sf2, "Distorted Guitar", new Patch(0, 29), guitar_dist); + newInstrument(sf2, "Distorted Guitar", new Patch(0, 30), guitar_dist); + newInstrument(sf2, "Guitar", new Patch(0, 31), guitar, guitar_pick); + newInstrument(sf2, "Finger Bass", new Patch(0, 32), bass1); + newInstrument(sf2, "Finger Bass", new Patch(0, 33), bass1); + newInstrument(sf2, "Finger Bass", new Patch(0, 34), bass1); + newInstrument(sf2, "Frettless Bass", new Patch(0, 35), bass2); + newInstrument(sf2, "Frettless Bass", new Patch(0, 36), bass2); + newInstrument(sf2, "Frettless Bass", new Patch(0, 37), bass2); + newInstrument(sf2, "Synth Bass1", new Patch(0, 38), synthbass); + newInstrument(sf2, "Synth Bass2", new Patch(0, 39), synthbass); + newInstrument(sf2, "Solo String", new Patch(0, 40), string2, solostring); + newInstrument(sf2, "Solo String", new Patch(0, 41), string2, solostring); + newInstrument(sf2, "Solo String", new Patch(0, 42), string2, solostring); + newInstrument(sf2, "Solo String", new Patch(0, 43), string2, solostring); + newInstrument(sf2, "Solo String", new Patch(0, 44), string2, solostring); + newInstrument(sf2, "Def", new Patch(0, 45), defaultsound); + newInstrument(sf2, "Harp", new Patch(0, 46), bell); + newInstrument(sf2, "Timpani", new Patch(0, 47), timpani); + newInstrument(sf2, "Strings", new Patch(0, 48), string2); + SF2Instrument slow_strings = + newInstrument(sf2, "Slow Strings", new Patch(0, 49), string2); + SF2InstrumentRegion region = slow_strings.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, 2500); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 2000); + newInstrument(sf2, "Synth Strings", new Patch(0, 50), string2); + newInstrument(sf2, "Synth Strings", new Patch(0, 51), string2); + + + newInstrument(sf2, "Choir", new Patch(0, 52), choir); + newInstrument(sf2, "Choir", new Patch(0, 53), choir); + newInstrument(sf2, "Choir", new Patch(0, 54), choir); + { + SF2Instrument ins = newInstrument(sf2, "Orch Hit", + new Patch(0, 55), orchhit, orchhit, timpani); + region = ins.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_COARSETUNE, -12); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + } + newInstrument(sf2, "Trumpet", new Patch(0, 56), trumpet); + newInstrument(sf2, "Trombone", new Patch(0, 57), trombone); + newInstrument(sf2, "Trombone", new Patch(0, 58), trombone); + newInstrument(sf2, "Trumpet", new Patch(0, 59), trumpet); + newInstrument(sf2, "Horn", new Patch(0, 60), horn); + newInstrument(sf2, "Brass Section", new Patch(0, 61), brass_section); + newInstrument(sf2, "Brass Section", new Patch(0, 62), brass_section); + newInstrument(sf2, "Brass Section", new Patch(0, 63), brass_section); + newInstrument(sf2, "Sax", new Patch(0, 64), sax); + newInstrument(sf2, "Sax", new Patch(0, 65), sax); + newInstrument(sf2, "Sax", new Patch(0, 66), sax); + newInstrument(sf2, "Sax", new Patch(0, 67), sax); + newInstrument(sf2, "Oboe", new Patch(0, 68), oboe); + newInstrument(sf2, "Horn", new Patch(0, 69), horn); + newInstrument(sf2, "Bassoon", new Patch(0, 70), bassoon); + newInstrument(sf2, "Clarinet", new Patch(0, 71), clarinet); + newInstrument(sf2, "Flute", new Patch(0, 72), flute); + newInstrument(sf2, "Flute", new Patch(0, 73), flute); + newInstrument(sf2, "Flute", new Patch(0, 74), flute); + newInstrument(sf2, "Flute", new Patch(0, 75), flute); + newInstrument(sf2, "Flute", new Patch(0, 76), flute); + newInstrument(sf2, "Flute", new Patch(0, 77), flute); + newInstrument(sf2, "Flute", new Patch(0, 78), flute); + newInstrument(sf2, "Flute", new Patch(0, 79), flute); + newInstrument(sf2, "Organ", new Patch(0, 80), organ); + newInstrument(sf2, "Organ", new Patch(0, 81), organ); + newInstrument(sf2, "Flute", new Patch(0, 82), flute); + newInstrument(sf2, "Organ", new Patch(0, 83), organ); + newInstrument(sf2, "Organ", new Patch(0, 84), organ); + newInstrument(sf2, "Choir", new Patch(0, 85), choir); + newInstrument(sf2, "Organ", new Patch(0, 86), organ); + newInstrument(sf2, "Organ", new Patch(0, 87), organ); + newInstrument(sf2, "Synth Strings", new Patch(0, 88), string2); + newInstrument(sf2, "Organ", new Patch(0, 89), organ); + newInstrument(sf2, "Def", new Patch(0, 90), defaultsound); + newInstrument(sf2, "Choir", new Patch(0, 91), choir); + newInstrument(sf2, "Organ", new Patch(0, 92), organ); + newInstrument(sf2, "Organ", new Patch(0, 93), organ); + newInstrument(sf2, "Organ", new Patch(0, 94), organ); + newInstrument(sf2, "Organ", new Patch(0, 95), organ); + newInstrument(sf2, "Organ", new Patch(0, 96), organ); + newInstrument(sf2, "Organ", new Patch(0, 97), organ); + newInstrument(sf2, "Bell", new Patch(0, 98), bell); + newInstrument(sf2, "Organ", new Patch(0, 99), organ); + newInstrument(sf2, "Organ", new Patch(0, 100), organ); + newInstrument(sf2, "Organ", new Patch(0, 101), organ); + newInstrument(sf2, "Def", new Patch(0, 102), defaultsound); + newInstrument(sf2, "Synth Strings", new Patch(0, 103), string2); + newInstrument(sf2, "Def", new Patch(0, 104), defaultsound); + newInstrument(sf2, "Def", new Patch(0, 105), defaultsound); + newInstrument(sf2, "Def", new Patch(0, 106), defaultsound); + newInstrument(sf2, "Def", new Patch(0, 107), defaultsound); + newInstrument(sf2, "Marimba", new Patch(0, 108), bell); + newInstrument(sf2, "Sax", new Patch(0, 109), sax); + newInstrument(sf2, "Solo String", new Patch(0, 110), string2, solostring); + newInstrument(sf2, "Oboe", new Patch(0, 111), oboe); + newInstrument(sf2, "Bell", new Patch(0, 112), bell); + newInstrument(sf2, "Melodic Toms", new Patch(0, 113), melodic_toms); + newInstrument(sf2, "Marimba", new Patch(0, 114), bell); + newInstrument(sf2, "Melodic Toms", new Patch(0, 115), melodic_toms); + newInstrument(sf2, "Melodic Toms", new Patch(0, 116), melodic_toms); + newInstrument(sf2, "Melodic Toms", new Patch(0, 117), melodic_toms); + newInstrument(sf2, "Reverse Cymbal", new Patch(0, 118), reverse_cymbal); + newInstrument(sf2, "Reverse Cymbal", new Patch(0, 119), reverse_cymbal); + newInstrument(sf2, "Guitar", new Patch(0, 120), guitar); + newInstrument(sf2, "Def", new Patch(0, 121), defaultsound); + { + SF2Instrument ins = newInstrument(sf2, "Seashore/Reverse Cymbal", + new Patch(0, 122), reverse_cymbal); + region = ins.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 18500); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 4500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, -4500); + } + { + SF2Instrument ins = newInstrument(sf2, "Bird/Flute", + new Patch(0, 123), flute); + region = ins.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_COARSETUNE, 24); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, -3000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + } + newInstrument(sf2, "Def", new Patch(0, 124), side_stick); + { + SF2Instrument ins = newInstrument(sf2, "Seashore/Reverse Cymbal", + new Patch(0, 125), reverse_cymbal); + region = ins.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 18500); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 4500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, -4500); + } + newInstrument(sf2, "Applause/crash_cymbal", + new Patch(0, 126), crash_cymbal); + newInstrument(sf2, "Gunshot/side_stick", new Patch(0, 127), side_stick); + + for (SF2Instrument instrument : sf2.getInstruments()) { + Patch patch = instrument.getPatch(); + if (patch instanceof ModelPatch) { + if (((ModelPatch) patch).isPercussion()) + continue; + } + instrument.setName(general_midi_instruments[patch.getProgram()]); + } + + return sf2; + + } + + public static SF2Layer new_bell(SF2Soundbank sf2) { + Random random = new Random(102030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.01; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.00001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + double detune = 1 + (random.nextDouble() * 2 - 1) * 0.01; + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1) * detune, w, a); + a *= a_step; + } + SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base); + SF2Layer layer = newLayer(sf2, "EPiano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 1200); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000); + return layer; + } + + public static SF2Layer new_guitar1(SF2Soundbank sf2) { + + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.01; + double end_w = 0.01; + double start_a = 2; + double end_a = 0.01; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + + double[] aa = new double[40]; + for (int i = 0; i < 40; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] = 2; + aa[1] = 0.5; + aa[2] = 0.45; + aa[3] = 0.2; + aa[4] = 1; + aa[5] = 0.5; + aa[6] = 2; + aa[7] = 1; + aa[8] = 0.5; + aa[9] = 1; + aa[9] = 0.5; + aa[10] = 0.2; + aa[11] = 1; + aa[12] = 0.7; + aa[13] = 0.5; + aa[14] = 1; + + for (int i = 0; i < 40; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Guitar", data, base); + SF2Layer layer = newLayer(sf2, "Guitar", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 2400); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -100); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -6000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -20); + return layer; + } + + public static SF2Layer new_guitar_dist(SF2Soundbank sf2) { + + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.01; + double end_w = 0.01; + double start_a = 2; + double end_a = 0.01; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + + double[] aa = new double[40]; + for (int i = 0; i < 40; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] = 5; + aa[1] = 2; + aa[2] = 0.45; + aa[3] = 0.2; + aa[4] = 1; + aa[5] = 0.5; + aa[6] = 2; + aa[7] = 1; + aa[8] = 0.5; + aa[9] = 1; + aa[9] = 0.5; + aa[10] = 0.2; + aa[11] = 1; + aa[12] = 0.7; + aa[13] = 0.5; + aa[14] = 1; + + for (int i = 0; i < 40; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + + + SF2Sample sample = newSimpleFFTSample_dist(sf2, "Distorted Guitar", + data, base, 10000.0); + + + SF2Layer layer = newLayer(sf2, "Distorted Guitar", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + //region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 2400); + //region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 200); + + //region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -100); + //region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + //region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -1000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 8000); + //region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -20); + return layer; + } + + public static SF2Layer new_guitar_pick(SF2Soundbank sf2) { + + double datab[]; + + // Make treble part + { + int m = 2; + int fftlen = 4096 * m; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)); + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 0; i < 2048 * m; i++) { + data[i] *= Math.exp(-Math.abs((i - 23) / ((double) m)) * 1.2) + + Math.exp(-Math.abs((i - 40) / ((double) m)) * 0.9); + } + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.8); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9994; + } + datab = data; + + fadeUp(data, 80); + } + + SF2Sample sample = newSimpleDrumSample(sf2, "Guitar Noise", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Guitar Noise"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); +// region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); +/* + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 0); + region.putInteger(SF2Region.GENERATOR_SUSTAINMODENV, 1000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -11000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 12000); + */ + + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_gpiano(SF2Soundbank sf2) { + //Random random = new Random(302030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 15.0); + + double[] aa = new double[30]; + for (int i = 0; i < 30; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 2; + //aa[2] *= 0.1; + aa[4] *= 2; + + + aa[12] *= 0.9; + aa[13] *= 0.7; + for (int i = 14; i < 30; i++) { + aa[i] *= 0.5; + } + + + for (int i = 0; i < 30; i++) { + //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001; + double w = 0.2; + double ai = aa[i]; + if (i > 10) { + w = 5; + ai *= 10; + } + int adjust = 0; + if (i > 5) { + adjust = (i - 5) * 7; + } + complexGaussianDist(data, base * (i + 1) + adjust, w, ai); + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Grand Piano", data, base, 200); + SF2Layer layer = newLayer(sf2, "Grand Piano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -7000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 18000); + return layer; + } + + public static SF2Layer new_gpiano2(SF2Soundbank sf2) { + //Random random = new Random(302030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 20.0); + + double[] aa = new double[30]; + for (int i = 0; i < 30; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 1; + //aa[2] *= 0.1; + aa[4] *= 2; + + + aa[12] *= 0.9; + aa[13] *= 0.7; + for (int i = 14; i < 30; i++) { + aa[i] *= 0.5; + } + + + for (int i = 0; i < 30; i++) { + //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001; + double w = 0.2; + double ai = aa[i]; + if (i > 10) { + w = 5; + ai *= 10; + } + int adjust = 0; + if (i > 5) { + adjust = (i - 5) * 7; + } + complexGaussianDist(data, base * (i + 1) + adjust, w, ai); + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Grand Piano", data, base, 200); + SF2Layer layer = newLayer(sf2, "Grand Piano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -7000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 18000); + return layer; + } + + public static SF2Layer new_piano_hammer(SF2Soundbank sf2) { + + double datab[]; + + // Make treble part + { + int m = 2; + int fftlen = 4096 * m; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)); + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 0; i < 2048 * m; i++) + data[i] *= Math.exp(-Math.abs((i - 37) / ((double) m)) * 0.05); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.6); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9997; + } + datab = data; + + fadeUp(data, 80); + } + + SF2Sample sample = newSimpleDrumSample(sf2, "Piano Hammer", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Piano Hammer"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); +/* + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 0); + region.putInteger(SF2Region.GENERATOR_SUSTAINMODENV, 1000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -11000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 12000); + */ + + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_piano1(SF2Soundbank sf2) { + //Random random = new Random(302030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_a = 0.2; + double end_a = 0.0001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + + double[] aa = new double[30]; + for (int i = 0; i < 30; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 5; + aa[2] *= 0.1; + aa[7] *= 5; + + + for (int i = 0; i < 30; i++) { + //double detune = 1 + (random.nextDouble()*2 - 1)*0.0001; + double w = 0.2; + double ai = aa[i]; + if (i > 12) { + w = 5; + ai *= 10; + } + int adjust = 0; + if (i > 5) { + adjust = (i - 5) * 7; + } + complexGaussianDist(data, base * (i + 1) + adjust, w, ai); + } + + complexGaussianDist(data, base * (15.5), 1, 0.1); + complexGaussianDist(data, base * (17.5), 1, 0.01); + + SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base, 200); + SF2Layer layer = newLayer(sf2, "EPiano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -1200); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000); + return layer; + } + + public static SF2Layer new_epiano1(SF2Soundbank sf2) { + Random random = new Random(302030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.05; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.0001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + double detune = 1 + (random.nextDouble() * 2 - 1) * 0.0001; + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1) * detune, w, a); + a *= a_step; + } + + + + SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base); + SF2Layer layer = newLayer(sf2, "EPiano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 1200); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000); + return layer; + } + + public static SF2Layer new_epiano2(SF2Soundbank sf2) { + Random random = new Random(302030201); + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.01; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.00001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + double detune = 1 + (random.nextDouble() * 2 - 1) * 0.0001; + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1) * detune, w, a); + a *= a_step; + } + + SF2Sample sample = newSimpleFFTSample(sf2, "EPiano", data, base); + SF2Layer layer = newLayer(sf2, "EPiano", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 8000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, 2400); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -9000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 16000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + return layer; + } + + public static SF2Layer new_bass1(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.05; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.02; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 25.0); + + double[] aa = new double[25]; + for (int i = 0; i < 25; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 8; + aa[1] *= 4; + aa[3] *= 8; + aa[5] *= 8; + + for (int i = 0; i < 25; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + + + SF2Sample sample = newSimpleFFTSample(sf2, "Bass", data, base); + SF2Layer layer = newLayer(sf2, "Bass", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 11000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + return layer; + } + + public static SF2Layer new_synthbass(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.05; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.02; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 25.0); + + double[] aa = new double[25]; + for (int i = 0; i < 25; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 16; + aa[1] *= 4; + aa[3] *= 16; + aa[5] *= 8; + + for (int i = 0; i < 25; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + + + SF2Sample sample = newSimpleFFTSample(sf2, "Bass", data, base); + SF2Layer layer = newLayer(sf2, "Bass", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, -3000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 8000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + return layer; + } + + public static SF2Layer new_bass2(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 0.05; + double end_w = 0.05; + double start_a = 0.2; + double end_a = 0.002; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 25.0); + + double[] aa = new double[25]; + for (int i = 0; i < 25; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 8; + aa[1] *= 4; + aa[3] *= 8; + aa[5] *= 8; + + for (int i = 0; i < 25; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + + + SF2Sample sample = newSimpleFFTSample(sf2, "Bass2", data, base); + SF2Layer layer = newLayer(sf2, "Bass2", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -8000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + return layer; + } + + public static SF2Layer new_solostring(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 2; + double end_w = 2; + double start_a = 0.2; + double end_a = 0.01; + + double[] aa = new double[18]; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < aa.length; i++) { + a *= a_step; + aa[i] = a; + } + + aa[0] *= 5; + aa[1] *= 5; + aa[2] *= 5; + aa[3] *= 4; + aa[4] *= 4; + aa[5] *= 3; + aa[6] *= 3; + aa[7] *= 2; + + for (int i = 0; i < aa.length; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, a); + } + SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base); + SF2Layer layer = newLayer(sf2, "Strings", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + region.putInteger(SF2Region.GENERATOR_FREQVIBLFO, -1000); + region.putInteger(SF2Region.GENERATOR_VIBLFOTOPITCH, 15); + return layer; + + } + + public static SF2Layer new_orchhit(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 2; + double end_w = 80; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, a); + a *= a_step; + } + complexGaussianDist(data, base * 4, 300, 1); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Och Strings", data, base); + SF2Layer layer = newLayer(sf2, "Och Strings", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 200); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 200); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_string2(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 2; + double end_w = 80; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, a); + a *= a_step; + } + SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base); + SF2Layer layer = newLayer(sf2, "Strings", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_choir(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 25; + double start_w = 2; + double end_w = 80; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + double[] aa = new double[40]; + for (int i = 0; i < aa.length; i++) { + a *= a_step; + aa[i] = a; + } + + aa[5] *= 0.1; + aa[6] *= 0.01; + aa[7] *= 0.1; + aa[8] *= 0.1; + + for (int i = 0; i < aa.length; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + } + SF2Sample sample = newSimpleFFTSample(sf2, "Strings", data, base); + SF2Layer layer = newLayer(sf2, "Strings", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -5000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_organ(SF2Soundbank sf2) { + Random random = new Random(102030201); + int x = 1; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + double start_w = 0.01; + double end_w = 0.01; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + + for (int i = 0; i < 12; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, + a * (0.5 + 3 * (random.nextDouble()))); + a *= a_step; + } + SF2Sample sample = newSimpleFFTSample(sf2, "Organ", data, base); + SF2Layer layer = newLayer(sf2, "Organ", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_ch_organ(SF2Soundbank sf2) { + int x = 1; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + double start_w = 0.01; + double end_w = 0.01; + double start_a = 0.2; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 60.0); + + double[] aa = new double[60]; + for (int i = 0; i < aa.length; i++) { + a *= a_step; + aa[i] = a; + } + + aa[0] *= 5; + aa[1] *= 2; + aa[2] = 0; + aa[4] = 0; + aa[5] = 0; + aa[7] *= 7; + aa[9] = 0; + aa[10] = 0; + aa[12] = 0; + aa[15] *= 7; + aa[18] = 0; + aa[20] = 0; + aa[24] = 0; + aa[27] *= 5; + aa[29] = 0; + aa[30] = 0; + aa[33] = 0; + aa[36] *= 4; + aa[37] = 0; + aa[39] = 0; + aa[42] = 0; + aa[43] = 0; + aa[47] = 0; + aa[50] *= 4; + aa[52] = 0; + aa[55] = 0; + aa[57] = 0; + + + aa[10] *= 0.1; + aa[11] *= 0.1; + aa[12] *= 0.1; + aa[13] *= 0.1; + + aa[17] *= 0.1; + aa[18] *= 0.1; + aa[19] *= 0.1; + aa[20] *= 0.1; + + for (int i = 0; i < 60; i++) { + double w = start_w + (end_w - start_w) * (i / 40.0); + complexGaussianDist(data, base * (i + 1), w, aa[i]); + a *= a_step; + } + SF2Sample sample = newSimpleFFTSample(sf2, "Organ", data, base); + SF2Layer layer = newLayer(sf2, "Organ", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -10000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + return layer; + + } + + public static SF2Layer new_flute(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + complexGaussianDist(data, base * 1, 0.001, 0.5); + complexGaussianDist(data, base * 2, 0.001, 0.5); + complexGaussianDist(data, base * 3, 0.001, 0.5); + complexGaussianDist(data, base * 4, 0.01, 0.5); + + complexGaussianDist(data, base * 4, 100, 120); + complexGaussianDist(data, base * 6, 100, 40); + complexGaussianDist(data, base * 8, 100, 80); + + complexGaussianDist(data, base * 5, 0.001, 0.05); + complexGaussianDist(data, base * 6, 0.001, 0.06); + complexGaussianDist(data, base * 7, 0.001, 0.04); + complexGaussianDist(data, base * 8, 0.005, 0.06); + complexGaussianDist(data, base * 9, 0.005, 0.06); + complexGaussianDist(data, base * 10, 0.01, 0.1); + complexGaussianDist(data, base * 11, 0.08, 0.7); + complexGaussianDist(data, base * 12, 0.08, 0.6); + complexGaussianDist(data, base * 13, 0.08, 0.6); + complexGaussianDist(data, base * 14, 0.08, 0.6); + complexGaussianDist(data, base * 15, 0.08, 0.5); + complexGaussianDist(data, base * 16, 0.08, 0.5); + complexGaussianDist(data, base * 17, 0.08, 0.2); + + + complexGaussianDist(data, base * 1, 10, 8); + complexGaussianDist(data, base * 2, 10, 8); + complexGaussianDist(data, base * 3, 10, 8); + complexGaussianDist(data, base * 4, 10, 8); + complexGaussianDist(data, base * 5, 10, 8); + complexGaussianDist(data, base * 6, 20, 9); + complexGaussianDist(data, base * 7, 20, 9); + complexGaussianDist(data, base * 8, 20, 9); + complexGaussianDist(data, base * 9, 20, 8); + complexGaussianDist(data, base * 10, 30, 8); + complexGaussianDist(data, base * 11, 30, 9); + complexGaussianDist(data, base * 12, 30, 9); + complexGaussianDist(data, base * 13, 30, 8); + complexGaussianDist(data, base * 14, 30, 8); + complexGaussianDist(data, base * 15, 30, 7); + complexGaussianDist(data, base * 16, 30, 7); + complexGaussianDist(data, base * 17, 30, 6); + + SF2Sample sample = newSimpleFFTSample(sf2, "Flute", data, base); + SF2Layer layer = newLayer(sf2, "Flute", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_horn(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + double start_a = 0.5; + double end_a = 0.00000000001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + if (i == 0) + complexGaussianDist(data, base * (i + 1), 0.1, a * 0.2); + else + complexGaussianDist(data, base * (i + 1), 0.1, a); + a *= a_step; + } + + complexGaussianDist(data, base * 2, 100, 1); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Horn", data, base); + SF2Layer layer = newLayer(sf2, "Horn", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -500); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500); + return layer; + + } + + public static SF2Layer new_trumpet(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + double start_a = 0.5; + double end_a = 0.00001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 80.0); + double[] aa = new double[80]; + for (int i = 0; i < 80; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 0.05; + aa[1] *= 0.2; + aa[2] *= 0.5; + aa[3] *= 0.85; + + for (int i = 0; i < 80; i++) { + complexGaussianDist(data, base * (i + 1), 0.1, aa[i]); + } + + complexGaussianDist(data, base * 5, 300, 3); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Trumpet", data, base); + SF2Layer layer = newLayer(sf2, "Trumpet", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -10000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 0); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -4000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, -2500); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 10); + return layer; + + } + + public static SF2Layer new_brass_section(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + double start_a = 0.5; + double end_a = 0.005; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 30.0); + double[] aa = new double[30]; + for (int i = 0; i < 30; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 0.8; + aa[1] *= 0.9; + + double w = 5; + for (int i = 0; i < 30; i++) { + complexGaussianDist(data, base * (i + 1), 0.1 * w, aa[i] * w); + w += 6; //*= w_step; + } + + complexGaussianDist(data, base * 6, 300, 2); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Brass Section", data, base); + SF2Layer layer = newLayer(sf2, "Brass Section", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -9200); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500); + return layer; + + } + + public static SF2Layer new_trombone(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + double start_a = 0.5; + double end_a = 0.001; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 80.0); + double[] aa = new double[80]; + for (int i = 0; i < 80; i++) { + aa[i] = a; + a *= a_step; + } + + aa[0] *= 0.3; + aa[1] *= 0.7; + + for (int i = 0; i < 80; i++) { + complexGaussianDist(data, base * (i + 1), 0.1, aa[i]); + } + + complexGaussianDist(data, base * 6, 300, 2); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Trombone", data, base); + SF2Layer layer = newLayer(sf2, "Trombone", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -8000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -2000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERQ, 10); + return layer; + + } + + public static SF2Layer new_sax(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + double start_a = 0.5; + double end_a = 0.01; + double a = start_a; + double a_step = Math.pow(end_a / start_a, 1.0 / 40.0); + for (int i = 0; i < 40; i++) { + if (i == 0 || i == 2) + complexGaussianDist(data, base * (i + 1), 0.1, a * 4); + else + complexGaussianDist(data, base * (i + 1), 0.1, a); + a *= a_step; + } + + complexGaussianDist(data, base * 4, 200, 1); + + SF2Sample sample = newSimpleFFTSample(sf2, "Sax", data, base); + SF2Layer layer = newLayer(sf2, "Sax", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + + region.putInteger(SF2Region.GENERATOR_ATTACKMODENV, -3000); + region.putInteger(SF2Region.GENERATOR_RELEASEMODENV, 12000); + region.putInteger(SF2Region.GENERATOR_MODENVTOFILTERFC, 5000); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 4500); + return layer; + + } + + public static SF2Layer new_oboe(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + complexGaussianDist(data, base * 5, 100, 80); + + + complexGaussianDist(data, base * 1, 0.01, 0.53); + complexGaussianDist(data, base * 2, 0.01, 0.51); + complexGaussianDist(data, base * 3, 0.01, 0.48); + complexGaussianDist(data, base * 4, 0.01, 0.49); + complexGaussianDist(data, base * 5, 0.01, 5); + complexGaussianDist(data, base * 6, 0.01, 0.51); + complexGaussianDist(data, base * 7, 0.01, 0.50); + complexGaussianDist(data, base * 8, 0.01, 0.59); + complexGaussianDist(data, base * 9, 0.01, 0.61); + complexGaussianDist(data, base * 10, 0.01, 0.52); + complexGaussianDist(data, base * 11, 0.01, 0.49); + complexGaussianDist(data, base * 12, 0.01, 0.51); + complexGaussianDist(data, base * 13, 0.01, 0.48); + complexGaussianDist(data, base * 14, 0.01, 0.51); + complexGaussianDist(data, base * 15, 0.01, 0.46); + complexGaussianDist(data, base * 16, 0.01, 0.35); + complexGaussianDist(data, base * 17, 0.01, 0.20); + complexGaussianDist(data, base * 18, 0.01, 0.10); + complexGaussianDist(data, base * 19, 0.01, 0.5); + complexGaussianDist(data, base * 20, 0.01, 0.1); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Oboe", data, base); + SF2Layer layer = newLayer(sf2, "Oboe", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_bassoon(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + complexGaussianDist(data, base * 2, 100, 40); + complexGaussianDist(data, base * 4, 100, 20); + + complexGaussianDist(data, base * 1, 0.01, 0.53); + complexGaussianDist(data, base * 2, 0.01, 5); + complexGaussianDist(data, base * 3, 0.01, 0.51); + complexGaussianDist(data, base * 4, 0.01, 0.48); + complexGaussianDist(data, base * 5, 0.01, 1.49); + complexGaussianDist(data, base * 6, 0.01, 0.51); + complexGaussianDist(data, base * 7, 0.01, 0.50); + complexGaussianDist(data, base * 8, 0.01, 0.59); + complexGaussianDist(data, base * 9, 0.01, 0.61); + complexGaussianDist(data, base * 10, 0.01, 0.52); + complexGaussianDist(data, base * 11, 0.01, 0.49); + complexGaussianDist(data, base * 12, 0.01, 0.51); + complexGaussianDist(data, base * 13, 0.01, 0.48); + complexGaussianDist(data, base * 14, 0.01, 0.51); + complexGaussianDist(data, base * 15, 0.01, 0.46); + complexGaussianDist(data, base * 16, 0.01, 0.35); + complexGaussianDist(data, base * 17, 0.01, 0.20); + complexGaussianDist(data, base * 18, 0.01, 0.10); + complexGaussianDist(data, base * 19, 0.01, 0.5); + complexGaussianDist(data, base * 20, 0.01, 0.1); + + + SF2Sample sample = newSimpleFFTSample(sf2, "Flute", data, base); + SF2Layer layer = newLayer(sf2, "Flute", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_clarinet(SF2Soundbank sf2) { + int x = 8; + int fftsize = 4096 * x; + double[] data = new double[fftsize * 2]; + double base = x * 15; + + complexGaussianDist(data, base * 1, 0.001, 0.5); + complexGaussianDist(data, base * 2, 0.001, 0.02); + complexGaussianDist(data, base * 3, 0.001, 0.2); + complexGaussianDist(data, base * 4, 0.01, 0.1); + + complexGaussianDist(data, base * 4, 100, 60); + complexGaussianDist(data, base * 6, 100, 20); + complexGaussianDist(data, base * 8, 100, 20); + + complexGaussianDist(data, base * 5, 0.001, 0.1); + complexGaussianDist(data, base * 6, 0.001, 0.09); + complexGaussianDist(data, base * 7, 0.001, 0.02); + complexGaussianDist(data, base * 8, 0.005, 0.16); + complexGaussianDist(data, base * 9, 0.005, 0.96); + complexGaussianDist(data, base * 10, 0.01, 0.9); + complexGaussianDist(data, base * 11, 0.08, 1.2); + complexGaussianDist(data, base * 12, 0.08, 1.8); + complexGaussianDist(data, base * 13, 0.08, 1.6); + complexGaussianDist(data, base * 14, 0.08, 1.2); + complexGaussianDist(data, base * 15, 0.08, 0.9); + complexGaussianDist(data, base * 16, 0.08, 0.5); + complexGaussianDist(data, base * 17, 0.08, 0.2); + + + complexGaussianDist(data, base * 1, 10, 8); + complexGaussianDist(data, base * 2, 10, 8); + complexGaussianDist(data, base * 3, 10, 8); + complexGaussianDist(data, base * 4, 10, 8); + complexGaussianDist(data, base * 5, 10, 8); + complexGaussianDist(data, base * 6, 20, 9); + complexGaussianDist(data, base * 7, 20, 9); + complexGaussianDist(data, base * 8, 20, 9); + complexGaussianDist(data, base * 9, 20, 8); + complexGaussianDist(data, base * 10, 30, 8); + complexGaussianDist(data, base * 11, 30, 9); + complexGaussianDist(data, base * 12, 30, 9); + complexGaussianDist(data, base * 13, 30, 8); + complexGaussianDist(data, base * 14, 30, 8); + complexGaussianDist(data, base * 15, 30, 7); + complexGaussianDist(data, base * 16, 30, 7); + complexGaussianDist(data, base * 17, 30, 6); + + SF2Sample sample = newSimpleFFTSample(sf2, "Clarinet", data, base); + SF2Layer layer = newLayer(sf2, "Clarinet", sample); + SF2Region region = layer.getRegions().get(0); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -6000); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 4000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, -100); + region.putInteger(SF2Region.GENERATOR_INITIALFILTERFC, 9500); + return layer; + + } + + public static SF2Layer new_timpani(SF2Soundbank sf2) { + + double datab[]; + double datah[]; + + // Make Bass Part + { + int fftlen = 4096 * 8; + double[] data = new double[2 * fftlen]; + double base = 48; + complexGaussianDist(data, base * 2, 0.2, 1); + complexGaussianDist(data, base * 3, 0.2, 0.7); + complexGaussianDist(data, base * 5, 10, 1); + complexGaussianDist(data, base * 6, 9, 1); + complexGaussianDist(data, base * 8, 15, 1); + complexGaussianDist(data, base * 9, 18, 0.8); + complexGaussianDist(data, base * 11, 21, 0.5); + complexGaussianDist(data, base * 13, 28, 0.3); + complexGaussianDist(data, base * 14, 22, 0.1); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.5); + data = realPart(data); + + double d_len = data.length; + for (int i = 0; i < data.length; i++) { + double g = (1.0 - (i / d_len)); + data[i] *= g * g; + } + fadeUp(data, 40); + datab = data; + } + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) { + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + } + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 300; i++) { + double g = (1.0 - (i / 300.0)); + data[i] *= 1.0 + 20 * g * g; + } + for (int i = 0; i < 24; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9998; + } + datah = data; + } + + for (int i = 0; i < datah.length; i++) + datab[i] += datah[i] * 0.02; + + normalize(datab, 0.9); + + SF2Sample sample = newSimpleDrumSample(sf2, "Timpani", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Timpani"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_melodic_toms(SF2Soundbank sf2) { + + double datab[]; + double datah[]; + + // Make Bass Part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + complexGaussianDist(data, 30, 0.5, 1); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.8); + data = realPart(data); + + double d_len = data.length; + for (int i = 0; i < data.length; i++) + data[i] *= (1.0 - (i / d_len)); + datab = data; + } + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 200; i++) { + double g = (1.0 - (i / 200.0)); + data[i] *= 1.0 + 20 * g * g; + } + for (int i = 0; i < 30; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9996; + } + datah = data; + } + + for (int i = 0; i < datah.length; i++) + datab[i] += datah[i] * 0.5; + for (int i = 0; i < 5; i++) + datab[i] *= i / 5.0; + + normalize(datab, 0.99); + + SF2Sample sample = newSimpleDrumSample(sf2, "Melodic Toms", datab); + sample.setOriginalPitch(63); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Melodic Toms"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_reverse_cymbal(SF2Soundbank sf2) { + double datah[]; + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)); + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 0; i < 100; i++) + data[i] = 0; + + for (int i = 0; i < 512 * 2; i++) { + double gain = (i / (512.0 * 2.0)); + data[i] = 1 - gain; + } + datah = data; + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Reverse Cymbal", + datah, 100, 20); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Reverse Cymbal"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_ATTACKVOLENV, -200); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, -12000); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, -1000); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_snare_drum(SF2Soundbank sf2) { + + double datab[]; + double datah[]; + + // Make Bass Part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + complexGaussianDist(data, 24, 0.5, 1); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.5); + data = realPart(data); + + double d_len = data.length; + for (int i = 0; i < data.length; i++) + data[i] *= (1.0 - (i / d_len)); + datab = data; + } + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 300; i++) { + double g = (1.0 - (i / 300.0)); + data[i] *= 1.0 + 20 * g * g; + } + for (int i = 0; i < 24; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9998; + } + datah = data; + } + + for (int i = 0; i < datah.length; i++) + datab[i] += datah[i]; + for (int i = 0; i < 5; i++) + datab[i] *= i / 5.0; + + SF2Sample sample = newSimpleDrumSample(sf2, "Snare Drum", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Snare Drum"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_bass_drum(SF2Soundbank sf2) { + + double datab[]; + double datah[]; + + // Make Bass Part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + complexGaussianDist(data, 1.8 * 5 + 1, 2, 1); + complexGaussianDist(data, 1.8 * 9 + 1, 2, 1); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double d_len = data.length; + for (int i = 0; i < data.length; i++) + data[i] *= (1.0 - (i / d_len)); + datab = data; + } + + // Make treble part + { + int fftlen = 4096; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024; i < 2048; i++) + data[i] = 1.0 - (i - 1024) / 1024.0; + for (int i = 0; i < 512; i++) + data[i] = 10 * i / 512.0; + for (int i = 0; i < 10; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.999; + } + datah = data; + } + + for (int i = 0; i < datah.length; i++) + datab[i] += datah[i] * 0.5; + for (int i = 0; i < 5; i++) + datab[i] *= i / 5.0; + + SF2Sample sample = newSimpleDrumSample(sf2, "Bass Drum", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Bass Drum"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_tom(SF2Soundbank sf2) { + + double datab[]; + double datah[]; + + // Make Bass Part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + complexGaussianDist(data, 30, 0.5, 1); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.8); + data = realPart(data); + + double d_len = data.length; + for (int i = 0; i < data.length; i++) + data[i] *= (1.0 - (i / d_len)); + datab = data; + } + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 200; i++) { + double g = (1.0 - (i / 200.0)); + data[i] *= 1.0 + 20 * g * g; + } + for (int i = 0; i < 30; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9996; + } + datah = data; + } + + for (int i = 0; i < datah.length; i++) + datab[i] += datah[i] * 0.5; + for (int i = 0; i < 5; i++) + datab[i] *= i / 5.0; + + normalize(datab, 0.99); + + SF2Sample sample = newSimpleDrumSample(sf2, "Tom", datab); + sample.setOriginalPitch(50); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Tom"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + //region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -100); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_closed_hihat(SF2Soundbank sf2) { + double datah[]; + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 2048; i++) + data[i] = 0.2 + 0.8 * (i / 2048.0); + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9996; + } + datah = data; + } + + for (int i = 0; i < 5; i++) + datah[i] *= i / 5.0; + SF2Sample sample = newSimpleDrumSample(sf2, "Closed Hi-Hat", datah); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Closed Hi-Hat"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_EXCLUSIVECLASS, 1); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_open_hihat(SF2Soundbank sf2) { + double datah[]; + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)); + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 0; i < 200; i++) + data[i] = 0; + for (int i = 0; i < 2048 * 4; i++) { + double gain = (i / (2048.0 * 4.0)); + data[i] = gain; + } + datah = data; + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Open Hi-Hat", datah, 1000, 5); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Open Hi-Hat"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 1500); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1500); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_EXCLUSIVECLASS, 1); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_crash_cymbal(SF2Soundbank sf2) { + double datah[]; + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)); + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 0; i < 100; i++) + data[i] = 0; + for (int i = 0; i < 512 * 2; i++) { + double gain = (i / (512.0 * 2.0)); + data[i] = gain; + } + datah = data; + } + + SF2Sample sample = newSimpleFFTSample(sf2, "Crash Cymbal", datah, 1000, 5); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Crash Cymbal"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_DECAYVOLENV, 1800); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 1800); + region.putInteger(SF2Region.GENERATOR_SUSTAINVOLENV, 1000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + } + + public static SF2Layer new_side_stick(SF2Soundbank sf2) { + double datab[]; + + // Make treble part + { + int fftlen = 4096 * 4; + double[] data = new double[2 * fftlen]; + Random random = new Random(3049912); + for (int i = 0; i < data.length; i += 2) + data[i] = (2.0 * (random.nextDouble() - 0.5)) * 0.1; + fft(data); + // Remove all negative frequency + for (int i = fftlen / 2; i < data.length; i++) + data[i] = 0; + for (int i = 1024 * 4; i < 2048 * 4; i++) + data[i] = 1.0 - (i - 4096) / 4096.0; + for (int i = 0; i < 200; i++) { + double g = (1.0 - (i / 200.0)); + data[i] *= 1.0 + 20 * g * g; + } + for (int i = 0; i < 30; i++) + data[i] = 0; + randomPhase(data, new Random(3049912)); + ifft(data); + normalize(data, 0.9); + data = realPart(data); + double gain = 1.0; + for (int i = 0; i < data.length; i++) { + data[i] *= gain; + gain *= 0.9996; + } + datab = data; + } + + for (int i = 0; i < 10; i++) + datab[i] *= i / 10.0; + + SF2Sample sample = newSimpleDrumSample(sf2, "Side Stick", datab); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Side Stick"); + + SF2GlobalRegion global = new SF2GlobalRegion(); + layer.setGlobalZone(global); + sf2.addResource(layer); + + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_RELEASEVOLENV, 12000); + region.putInteger(SF2Region.GENERATOR_SCALETUNING, 0); + region.putInteger(SF2Region.GENERATOR_INITIALATTENUATION, -50); + region.setSample(sample); + layer.getRegions().add(region); + + return layer; + + } + + public static SF2Sample newSimpleFFTSample(SF2Soundbank sf2, String name, + double[] data, double base) { + return newSimpleFFTSample(sf2, name, data, base, 10); + } + + public static SF2Sample newSimpleFFTSample(SF2Soundbank sf2, String name, + double[] data, double base, int fadeuptime) { + + int fftsize = data.length / 2; + AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + double basefreq = (base / fftsize) * format.getSampleRate() * 0.5; + + randomPhase(data); + ifft(data); + data = realPart(data); + normalize(data, 0.9); + float[] fdata = toFloat(data); + fdata = loopExtend(fdata, fdata.length + 512); + fadeUp(fdata, fadeuptime); + byte[] bdata = toBytes(fdata, format); + + /* + * Create SoundFont2 sample. + */ + SF2Sample sample = new SF2Sample(sf2); + sample.setName(name); + sample.setData(bdata); + sample.setStartLoop(256); + sample.setEndLoop(fftsize + 256); + sample.setSampleRate((long) format.getSampleRate()); + double orgnote = (69 + 12) + + (12 * Math.log(basefreq / 440.0) / Math.log(2)); + sample.setOriginalPitch((int) orgnote); + sample.setPitchCorrection((byte) (-(orgnote - (int) orgnote) * 100.0)); + sf2.addResource(sample); + + return sample; + } + + public static SF2Sample newSimpleFFTSample_dist(SF2Soundbank sf2, + String name, double[] data, double base, double preamp) { + + int fftsize = data.length / 2; + AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + double basefreq = (base / fftsize) * format.getSampleRate() * 0.5; + + randomPhase(data); + ifft(data); + data = realPart(data); + + for (int i = 0; i < data.length; i++) { + data[i] = (1 - Math.exp(-Math.abs(data[i] * preamp))) + * Math.signum(data[i]); + } + + normalize(data, 0.9); + float[] fdata = toFloat(data); + fdata = loopExtend(fdata, fdata.length + 512); + fadeUp(fdata, 80); + byte[] bdata = toBytes(fdata, format); + + /* + * Create SoundFont2 sample. + */ + SF2Sample sample = new SF2Sample(sf2); + sample.setName(name); + sample.setData(bdata); + sample.setStartLoop(256); + sample.setEndLoop(fftsize + 256); + sample.setSampleRate((long) format.getSampleRate()); + double orgnote = (69 + 12) + + (12 * Math.log(basefreq / 440.0) / Math.log(2)); + sample.setOriginalPitch((int) orgnote); + sample.setPitchCorrection((byte) (-(orgnote - (int) orgnote) * 100.0)); + sf2.addResource(sample); + + return sample; + } + + public static SF2Sample newSimpleDrumSample(SF2Soundbank sf2, String name, + double[] data) { + + int fftsize = data.length; + AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + byte[] bdata = toBytes(toFloat(realPart(data)), format); + + /* + * Create SoundFont2 sample. + */ + SF2Sample sample = new SF2Sample(sf2); + sample.setName(name); + sample.setData(bdata); + sample.setStartLoop(256); + sample.setEndLoop(fftsize + 256); + sample.setSampleRate((long) format.getSampleRate()); + sample.setOriginalPitch(60); + sf2.addResource(sample); + + return sample; + } + + public static SF2Layer newLayer(SF2Soundbank sf2, String name, SF2Sample sample) { + SF2LayerRegion region = new SF2LayerRegion(); + region.setSample(sample); + + SF2Layer layer = new SF2Layer(sf2); + layer.setName(name); + layer.getRegions().add(region); + sf2.addResource(layer); + + return layer; + } + + public static SF2Instrument newInstrument(SF2Soundbank sf2, String name, + Patch patch, SF2Layer... layers) { + + /* + * Create SoundFont2 instrument. + */ + SF2Instrument ins = new SF2Instrument(sf2); + ins.setPatch(patch); + ins.setName(name); + sf2.addInstrument(ins); + + /* + * Create region for instrument. + */ + for (int i = 0; i < layers.length; i++) { + SF2InstrumentRegion insregion = new SF2InstrumentRegion(); + insregion.setLayer(layers[i]); + ins.getRegions().add(insregion); + } + + return ins; + } + + static public void ifft(double[] data) { + new FFT(data.length / 2, 1).transform(data); + } + + static public void fft(double[] data) { + new FFT(data.length / 2, -1).transform(data); + } + + public static void complexGaussianDist(double[] cdata, double m, + double s, double v) { + for (int x = 0; x < cdata.length / 4; x++) { + cdata[x * 2] += v * (1.0 / (s * Math.sqrt(2 * Math.PI)) + * Math.exp((-1.0 / 2.0) * Math.pow((x - m) / s, 2.0))); + } + } + + static public void randomPhase(double[] data) { + for (int i = 0; i < data.length; i += 2) { + double phase = Math.random() * 2 * Math.PI; + double d = data[i]; + data[i] = Math.sin(phase) * d; + data[i + 1] = Math.cos(phase) * d; + } + } + + static public void randomPhase(double[] data, Random random) { + for (int i = 0; i < data.length; i += 2) { + double phase = random.nextDouble() * 2 * Math.PI; + double d = data[i]; + data[i] = Math.sin(phase) * d; + data[i + 1] = Math.cos(phase) * d; + } + } + + static public void normalize(double[] data, double target) { + double maxvalue = 0; + for (int i = 0; i < data.length; i++) { + if (data[i] > maxvalue) + maxvalue = data[i]; + if (-data[i] > maxvalue) + maxvalue = -data[i]; + } + if (maxvalue == 0) + return; + double gain = target / maxvalue; + for (int i = 0; i < data.length; i++) + data[i] *= gain; + } + + static public void normalize(float[] data, double target) { + double maxvalue = 0.5; + for (int i = 0; i < data.length; i++) { + if (data[i * 2] > maxvalue) + maxvalue = data[i * 2]; + if (-data[i * 2] > maxvalue) + maxvalue = -data[i * 2]; + } + double gain = target / maxvalue; + for (int i = 0; i < data.length; i++) + data[i * 2] *= gain; + } + + static public double[] realPart(double[] in) { + double[] out = new double[in.length / 2]; + for (int i = 0; i < out.length; i++) { + out[i] = in[i * 2]; + } + return out; + } + + static public double[] imgPart(double[] in) { + double[] out = new double[in.length / 2]; + for (int i = 0; i < out.length; i++) { + out[i] = in[i * 2]; + } + return out; + } + + static public float[] toFloat(double[] in) { + float[] out = new float[in.length]; + for (int i = 0; i < out.length; i++) { + out[i] = (float) in[i]; + } + return out; + } + + static public byte[] toBytes(float[] in, AudioFormat format) { + byte[] out = new byte[in.length * format.getFrameSize()]; + return AudioFloatConverter.getConverter(format).toByteArray(in, out); + } + + static public void fadeUp(double[] data, int samples) { + double dsamples = samples; + for (int i = 0; i < samples; i++) + data[i] *= i / dsamples; + } + + static public void fadeUp(float[] data, int samples) { + double dsamples = samples; + for (int i = 0; i < samples; i++) + data[i] *= i / dsamples; + } + + static public double[] loopExtend(double[] data, int newsize) { + double[] outdata = new double[newsize]; + int p_len = data.length; + int p_ps = 0; + for (int i = 0; i < outdata.length; i++) { + outdata[i] = data[p_ps]; + p_ps++; + if (p_ps == p_len) + p_ps = 0; + } + return outdata; + } + + static public float[] loopExtend(float[] data, int newsize) { + float[] outdata = new float[newsize]; + int p_len = data.length; + int p_ps = 0; + for (int i = 0; i < outdata.length; i++) { + outdata[i] = data[p_ps]; + p_ps++; + if (p_ps == p_len) + p_ps = 0; + } + return outdata; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/FFT.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/FFT.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,749 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Fast Fourier Transformer. + * + * @author Karl Helgason + */ +public final class FFT { + + private double[] w; + private int fftFrameSize; + private int sign; + private int[] bitm_array; + private int fftFrameSize2; + + // Sign = -1 is FFT, 1 is IFFT (inverse FFT) + // Data = Interlaced double array to be transformed. + // The order is: real (sin), complex (cos) + // Framesize must be power of 2 + public FFT(int fftFrameSize, int sign) { + w = computeTwiddleFactors(fftFrameSize, sign); + + this.fftFrameSize = fftFrameSize; + this.sign = sign; + fftFrameSize2 = fftFrameSize << 1; + + // Pre-process Bit-Reversal + bitm_array = new int[fftFrameSize2]; + for (int i = 2; i < fftFrameSize2; i += 2) { + int j; + int bitm; + for (bitm = 2, j = 0; bitm < fftFrameSize2; bitm <<= 1) { + if ((i & bitm) != 0) + j++; + j <<= 1; + } + bitm_array[i] = j; + } + + } + + public void transform(double[] data) { + bitreversal(data); + calc(fftFrameSize, data, sign, w); + } + + private final static double[] computeTwiddleFactors(int fftFrameSize, + int sign) { + + int imax = (int) (Math.log(fftFrameSize) / Math.log(2.)); + + double[] warray = new double[(fftFrameSize - 1) * 4]; + int w_index = 0; + + for (int i = 0, nstep = 2; i < imax; i++) { + int jmax = nstep; + nstep <<= 1; + + double wr = 1.0; + double wi = 0.0; + + double arg = Math.PI / (jmax >> 1); + double wfr = Math.cos(arg); + double wfi = sign * Math.sin(arg); + + for (int j = 0; j < jmax; j += 2) { + warray[w_index++] = wr; + warray[w_index++] = wi; + + double tempr = wr; + wr = tempr * wfr - wi * wfi; + wi = tempr * wfi + wi * wfr; + } + } + + // PRECOMPUTATION of wwr1, wwi1 for factor 4 Decomposition (3 * complex + // operators and 8 +/- complex operators) + { + w_index = 0; + int w_index2 = warray.length >> 1; + for (int i = 0, nstep = 2; i < (imax - 1); i++) { + int jmax = nstep; + nstep *= 2; + + int ii = w_index + jmax; + for (int j = 0; j < jmax; j += 2) { + double wr = warray[w_index++]; + double wi = warray[w_index++]; + double wr1 = warray[ii++]; + double wi1 = warray[ii++]; + warray[w_index2++] = wr * wr1 - wi * wi1; + warray[w_index2++] = wr * wi1 + wi * wr1; + } + } + + } + + return warray; + } + + private final static void calc(int fftFrameSize, double[] data, int sign, + double[] w) { + + final int fftFrameSize2 = fftFrameSize << 1; + + int nstep = 2; + + if (nstep >= fftFrameSize2) + return; + int i = nstep - 2; + if (sign == -1) + calcF4F(fftFrameSize, data, i, nstep, w); + else + calcF4I(fftFrameSize, data, i, nstep, w); + + } + + private final static void calcF2E(int fftFrameSize, double[] data, int i, + int nstep, double[] w) { + int jmax = nstep; + nstep <<= 1; + for (int n = 0; n < jmax; n += 2) { + double wr = w[i++]; + double wi = w[i++]; + int m = n + jmax; + double datam_r = data[m]; + double datam_i = data[m + 1]; + double datan_r = data[n]; + double datan_i = data[n + 1]; + double tempr = datam_r * wr - datam_i * wi; + double tempi = datam_r * wi + datam_i * wr; + data[m] = datan_r - tempr; + data[m + 1] = datan_i - tempi; + data[n] = datan_r + tempr; + data[n + 1] = datan_i + tempi; + } + return; + + } + + // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- + // complex operators + private final static void calcF4F(int fftFrameSize, double[] data, int i, + int nstep, double[] w) { + final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; + // Factor-4 Decomposition + + int w_len = w.length >> 1; + while (nstep < fftFrameSize2) { + + if (nstep << 2 == fftFrameSize2) { + // Goto Factor-4 Final Decomposition + // calcF4E(data, i, nstep, -1, w); + calcF4FE(fftFrameSize, data, i, nstep, w); + return; + } + int jmax = nstep; + int nnstep = nstep << 1; + if (nnstep == fftFrameSize2) { + // Factor-4 Decomposition not possible + calcF2E(fftFrameSize, data, i, nstep, w); + return; + } + nstep <<= 2; + int ii = i + jmax; + int iii = i + w_len; + + { + i += 2; + ii += 2; + iii += 2; + + for (int n = 0; n < fftFrameSize2; n += nstep) { + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r; + double tempi = datam1_i; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r; + double n2w1i = datan2_i; + double m2ww1r = datam2_r; + double m2ww1i = datam2_i; + + tempr = m2ww1r - n2w1r; + tempi = m2ww1i - n2w1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + + } + } + + for (int j = 2; j < jmax; j += 2) { + double wr = w[i++]; + double wi = w[i++]; + double wr1 = w[ii++]; + double wi1 = w[ii++]; + double wwr1 = w[iii++]; + double wwi1 = w[iii++]; + // double wwr1 = wr * wr1 - wi * wi1; // these numbers can be + // precomputed!!! + // double wwi1 = wr * wi1 + wi * wr1; + + for (int n = j; n < fftFrameSize2; n += nstep) { + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r * wr - datam1_i * wi; + double tempi = datam1_r * wi + datam1_i * wr; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r * wr1 - datan2_i * wi1; + double n2w1i = datan2_r * wi1 + datan2_i * wr1; + double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1; + double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1; + + tempr = m2ww1r - n2w1r; + tempi = m2ww1i - n2w1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + } + } + + i += jmax << 1; + + } + + calcF2E(fftFrameSize, data, i, nstep, w); + + } + + // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- + // complex operators + private final static void calcF4I(int fftFrameSize, double[] data, int i, + int nstep, double[] w) { + final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; + // Factor-4 Decomposition + + int w_len = w.length >> 1; + while (nstep < fftFrameSize2) { + + if (nstep << 2 == fftFrameSize2) { + // Goto Factor-4 Final Decomposition + // calcF4E(data, i, nstep, 1, w); + calcF4IE(fftFrameSize, data, i, nstep, w); + return; + } + int jmax = nstep; + int nnstep = nstep << 1; + if (nnstep == fftFrameSize2) { + // Factor-4 Decomposition not possible + calcF2E(fftFrameSize, data, i, nstep, w); + return; + } + nstep <<= 2; + int ii = i + jmax; + int iii = i + w_len; + { + i += 2; + ii += 2; + iii += 2; + + for (int n = 0; n < fftFrameSize2; n += nstep) { + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r; + double tempi = datam1_i; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r; + double n2w1i = datan2_i; + double m2ww1r = datam2_r; + double m2ww1i = datam2_i; + + tempr = n2w1r - m2ww1r; + tempi = n2w1i - m2ww1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + + } + + } + for (int j = 2; j < jmax; j += 2) { + double wr = w[i++]; + double wi = w[i++]; + double wr1 = w[ii++]; + double wi1 = w[ii++]; + double wwr1 = w[iii++]; + double wwi1 = w[iii++]; + // double wwr1 = wr * wr1 - wi * wi1; // these numbers can be + // precomputed!!! + // double wwi1 = wr * wi1 + wi * wr1; + + for (int n = j; n < fftFrameSize2; n += nstep) { + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r * wr - datam1_i * wi; + double tempi = datam1_r * wi + datam1_i * wr; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r * wr1 - datan2_i * wi1; + double n2w1i = datan2_r * wi1 + datan2_i * wr1; + double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1; + double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1; + + tempr = n2w1r - m2ww1r; + tempi = n2w1i - m2ww1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + + } + } + + i += jmax << 1; + + } + + calcF2E(fftFrameSize, data, i, nstep, w); + + } + + // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- + // complex operators + private final static void calcF4FE(int fftFrameSize, double[] data, int i, + int nstep, double[] w) { + final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; + // Factor-4 Decomposition + + int w_len = w.length >> 1; + while (nstep < fftFrameSize2) { + + int jmax = nstep; + int nnstep = nstep << 1; + if (nnstep == fftFrameSize2) { + // Factor-4 Decomposition not possible + calcF2E(fftFrameSize, data, i, nstep, w); + return; + } + nstep <<= 2; + int ii = i + jmax; + int iii = i + w_len; + for (int n = 0; n < jmax; n += 2) { + double wr = w[i++]; + double wi = w[i++]; + double wr1 = w[ii++]; + double wi1 = w[ii++]; + double wwr1 = w[iii++]; + double wwi1 = w[iii++]; + // double wwr1 = wr * wr1 - wi * wi1; // these numbers can be + // precomputed!!! + // double wwi1 = wr * wi1 + wi * wr1; + + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r * wr - datam1_i * wi; + double tempi = datam1_r * wi + datam1_i * wr; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r * wr1 - datan2_i * wi1; + double n2w1i = datan2_r * wi1 + datan2_i * wr1; + double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1; + double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1; + + tempr = m2ww1r - n2w1r; + tempi = m2ww1i - n2w1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + + } + + i += jmax << 1; + + } + + } + + // Perform Factor-4 Decomposition with 3 * complex operators and 8 +/- + // complex operators + private final static void calcF4IE(int fftFrameSize, double[] data, int i, + int nstep, double[] w) { + final int fftFrameSize2 = fftFrameSize << 1; // 2*fftFrameSize; + // Factor-4 Decomposition + + int w_len = w.length >> 1; + while (nstep < fftFrameSize2) { + + int jmax = nstep; + int nnstep = nstep << 1; + if (nnstep == fftFrameSize2) { + // Factor-4 Decomposition not possible + calcF2E(fftFrameSize, data, i, nstep, w); + return; + } + nstep <<= 2; + int ii = i + jmax; + int iii = i + w_len; + for (int n = 0; n < jmax; n += 2) { + double wr = w[i++]; + double wi = w[i++]; + double wr1 = w[ii++]; + double wi1 = w[ii++]; + double wwr1 = w[iii++]; + double wwi1 = w[iii++]; + // double wwr1 = wr * wr1 - wi * wi1; // these numbers can be + // precomputed!!! + // double wwi1 = wr * wi1 + wi * wr1; + + int m = n + jmax; + + double datam1_r = data[m]; + double datam1_i = data[m + 1]; + double datan1_r = data[n]; + double datan1_i = data[n + 1]; + + n += nnstep; + m += nnstep; + double datam2_r = data[m]; + double datam2_i = data[m + 1]; + double datan2_r = data[n]; + double datan2_i = data[n + 1]; + + double tempr = datam1_r * wr - datam1_i * wi; + double tempi = datam1_r * wi + datam1_i * wr; + + datam1_r = datan1_r - tempr; + datam1_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + double n2w1r = datan2_r * wr1 - datan2_i * wi1; + double n2w1i = datan2_r * wi1 + datan2_i * wr1; + double m2ww1r = datam2_r * wwr1 - datam2_i * wwi1; + double m2ww1i = datam2_r * wwi1 + datam2_i * wwr1; + + tempr = n2w1r - m2ww1r; + tempi = n2w1i - m2ww1i; + + datam2_r = datam1_r + tempi; + datam2_i = datam1_i - tempr; + datam1_r = datam1_r - tempi; + datam1_i = datam1_i + tempr; + + tempr = n2w1r + m2ww1r; + tempi = n2w1i + m2ww1i; + + datan2_r = datan1_r - tempr; + datan2_i = datan1_i - tempi; + datan1_r = datan1_r + tempr; + datan1_i = datan1_i + tempi; + + data[m] = datam2_r; + data[m + 1] = datam2_i; + data[n] = datan2_r; + data[n + 1] = datan2_i; + + n -= nnstep; + m -= nnstep; + data[m] = datam1_r; + data[m + 1] = datam1_i; + data[n] = datan1_r; + data[n + 1] = datan1_i; + + } + + i += jmax << 1; + + } + + } + + private final void bitreversal(double[] data) { + if (fftFrameSize < 4) + return; + + int inverse = fftFrameSize2 - 2; + for (int i = 0; i < fftFrameSize; i += 4) { + int j = bitm_array[i]; + + // Performing Bit-Reversal, even v.s. even, O(2N) + if (i < j) { + + int n = i; + int m = j; + + // COMPLEX: SWAP(data[n], data[m]) + // Real Part + double tempr = data[n]; + data[n] = data[m]; + data[m] = tempr; + // Imagery Part + n++; + m++; + double tempi = data[n]; + data[n] = data[m]; + data[m] = tempi; + + n = inverse - i; + m = inverse - j; + + // COMPLEX: SWAP(data[n], data[m]) + // Real Part + tempr = data[n]; + data[n] = data[m]; + data[m] = tempr; + // Imagery Part + n++; + m++; + tempi = data[n]; + data[n] = data[m]; + data[m] = tempi; + } + + // Performing Bit-Reversal, odd v.s. even, O(N) + + int m = j + fftFrameSize; // bitm_array[i+2]; + // COMPLEX: SWAP(data[n], data[m]) + // Real Part + int n = i + 2; + double tempr = data[n]; + data[n] = data[m]; + data[m] = tempr; + // Imagery Part + n++; + m++; + double tempi = data[n]; + data[n] = data[m]; + data[m] = tempi; + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/InvalidDataException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/InvalidDataException.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; + +/** + * This exception is used when a file contains illegal or unexpected data. + * + * @author Karl Helgason + */ +public class InvalidDataException extends IOException { + + private static final long serialVersionUID = 1L; + + public InvalidDataException() { + super("Invalid Data!"); + } + + public InvalidDataException(String s) { + super(s); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/InvalidFormatException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/InvalidFormatException.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This exception is used when a reader is used to read file of a format + * it doesn't unterstand or support. + * + * @author Karl Helgason + */ +public class InvalidFormatException extends InvalidDataException { + + private static final long serialVersionUID = 1L; + + public InvalidFormatException() { + super("Invalid format!"); + } + + public InvalidFormatException(String s) { + super(s); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/JARSoundbankReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/JARSoundbankReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.Soundbank; +import javax.sound.midi.spi.SoundbankReader; + +/** + * JarSoundbankReader is used to read sounbank object from jar files. + * + * @author Karl Helgason + */ +public class JARSoundbankReader extends SoundbankReader { + + public boolean isZIP(URL url) { + boolean ok = false; + try { + InputStream stream = url.openStream(); + try { + byte[] buff = new byte[4]; + ok = stream.read(buff) == 4; + if (ok) { + ok = (buff[0] == 0x50 + && buff[1] == 0x4b + && buff[2] == 0x03 + && buff[3] == 0x04); + } + } finally { + stream.close(); + } + } catch (IOException e) { + } + return ok; + } + + public Soundbank getSoundbank(URL url) + throws InvalidMidiDataException, IOException { + if (!isZIP(url)) + return null; + ArrayList soundbanks = new ArrayList(); + URLClassLoader ucl = URLClassLoader.newInstance(new URL[]{url}); + InputStream stream = ucl.getResourceAsStream( + "META-INF/services/javax.sound.midi.Soundbank"); + if (stream == null) + return null; + BufferedReader r = new BufferedReader(new InputStreamReader(stream)); + String line = r.readLine(); + while (line != null) { + if (!line.startsWith("#")) { + try { + Class c = Class.forName(line.trim(), true, ucl); + Object o = c.newInstance(); + if (o instanceof Soundbank) { + soundbanks.add((Soundbank) o); + } + } catch (Exception e) { + //e.printStackTrace(); + } + } + line = r.readLine(); + } + stream.close(); + if (soundbanks.size() == 0) + return null; + if (soundbanks.size() == 1) + return soundbanks.get(0); + SimpleSoundbank sbk = new SimpleSoundbank(); + for (Soundbank soundbank : soundbanks) + sbk.addAllInstruments(soundbank); + return sbk; + } + + public Soundbank getSoundbank(InputStream stream) + throws InvalidMidiDataException, IOException { + return null; + } + + public Soundbank getSoundbank(File file) + throws InvalidMidiDataException, IOException { + return getSoundbank(file.toURI().toURL()); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelAbstractChannelMixer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelAbstractChannelMixer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,126 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * ModelAbstractChannelMixer is ready for use class to implement + * ModelChannelMixer interface. + * + * @author Karl Helgason + */ +public abstract class ModelAbstractChannelMixer implements ModelChannelMixer { + + public abstract boolean process(float[][] buffer, int offset, int len); + + public abstract void stop(); + + public void allNotesOff() { + } + + public void allSoundOff() { + } + + public void controlChange(int controller, int value) { + } + + public int getChannelPressure() { + return 0; + } + + public int getController(int controller) { + return 0; + } + + public boolean getMono() { + return false; + } + + public boolean getMute() { + return false; + } + + public boolean getOmni() { + return false; + } + + public int getPitchBend() { + return 0; + } + + public int getPolyPressure(int noteNumber) { + return 0; + } + + public int getProgram() { + return 0; + } + + public boolean getSolo() { + return false; + } + + public boolean localControl(boolean on) { + return false; + } + + public void noteOff(int noteNumber) { + } + + public void noteOff(int noteNumber, int velocity) { + } + + public void noteOn(int noteNumber, int velocity) { + } + + public void programChange(int program) { + } + + public void programChange(int bank, int program) { + } + + public void resetAllControllers() { + } + + public void setChannelPressure(int pressure) { + } + + public void setMono(boolean on) { + } + + public void setMute(boolean mute) { + } + + public void setOmni(boolean on) { + } + + public void setPitchBend(int bend) { + } + + public void setPolyPressure(int noteNumber, int pressure) { + } + + public void setSolo(boolean soloState) { + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelAbstractOscillator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelAbstractOscillator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,200 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.midi.VoiceStatus; + +/** + * A abstract class used to simplify creating custom ModelOscillator. + * + * @author Karl Helgason + */ +public abstract class ModelAbstractOscillator + implements ModelOscillator, ModelOscillatorStream, Soundbank { + + protected float pitch = 6000; + protected float samplerate; + protected MidiChannel channel; + protected VoiceStatus voice; + protected int noteNumber; + protected int velocity; + protected boolean on = false; + + public void init() { + } + + public void close() throws IOException { + } + + public void noteOff(int velocity) { + on = false; + } + + public void noteOn(MidiChannel channel, VoiceStatus voice, int noteNumber, + int velocity) { + this.channel = channel; + this.voice = voice; + this.noteNumber = noteNumber; + this.velocity = velocity; + on = true; + } + + public int read(float[][] buffer, int offset, int len) throws IOException { + return -1; + } + + public MidiChannel getChannel() { + return channel; + } + + public VoiceStatus getVoice() { + return voice; + } + + public int getNoteNumber() { + return noteNumber; + } + + public int getVelocity() { + return velocity; + } + + public boolean isOn() { + return on; + } + + public void setPitch(float pitch) { + this.pitch = pitch; + } + + public float getPitch() { + return pitch; + } + + public void setSampleRate(float samplerate) { + this.samplerate = samplerate; + } + + public float getSampleRate() { + return samplerate; + } + + public float getAttenuation() { + return 0; + } + + public int getChannels() { + return 1; + } + + public String getName() { + return getClass().getName(); + } + + public Patch getPatch() { + return new Patch(0, 0); + } + + public ModelOscillatorStream open(float samplerate) { + ModelAbstractOscillator oscs; + try { + oscs = this.getClass().newInstance(); + } catch (InstantiationException e) { + throw new IllegalArgumentException(e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } + oscs.setSampleRate(samplerate); + oscs.init(); + return oscs; + } + + public ModelPerformer getPerformer() { + // Create performer for my custom oscillirator + ModelPerformer performer = new ModelPerformer(); + performer.getOscillators().add(this); + return performer; + + } + + public ModelInstrument getInstrument() { + // Create Instrument object around my performer + SimpleInstrument ins = new SimpleInstrument(); + ins.setName(getName()); + ins.add(getPerformer()); + ins.setPatch(getPatch()); + return ins; + + } + + public Soundbank getSoundBank() { + // Create Soundbank object around the instrument + SimpleSoundbank sbk = new SimpleSoundbank(); + sbk.addInstrument(getInstrument()); + return sbk; + } + + public String getDescription() { + return getName(); + } + + public Instrument getInstrument(Patch patch) { + Instrument ins = getInstrument(); + Patch p = ins.getPatch(); + if (p.getBank() != patch.getBank()) + return null; + if (p.getProgram() != patch.getProgram()) + return null; + if (p instanceof ModelPatch && patch instanceof ModelPatch) { + if (((ModelPatch)p).isPercussion() + != ((ModelPatch)patch).isPercussion()) { + return null; + } + } + return ins; + } + + public Instrument[] getInstruments() { + return new Instrument[]{getInstrument()}; + } + + public SoundbankResource[] getResources() { + return new SoundbankResource[0]; + } + + public String getVendor() { + return null; + } + + public String getVersion() { + return null; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelByteBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelByteBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,326 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.util.Collection; + +/** + * This class is a pointer to a binary array either in memory or on disk. + * + * @author Karl Helgason + */ +public class ModelByteBuffer { + + private ModelByteBuffer root = this; + private File file; + private long fileoffset; + private byte[] buffer; + private long offset; + private long len; + + private class RandomFileInputStream extends InputStream { + + private RandomAccessFile raf; + private long left; + private long mark = 0; + private long markleft = 0; + + public RandomFileInputStream() throws IOException { + raf = new RandomAccessFile(root.file, "r"); + raf.seek(root.fileoffset + arrayOffset()); + left = capacity(); + } + + public int available() throws IOException { + if (left > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + return (int)left; + } + + public synchronized void mark(int readlimit) { + try { + mark = raf.getFilePointer(); + markleft = left; + } catch (IOException e) { + //e.printStackTrace(); + } + } + + public boolean markSupported() { + return true; + } + + public synchronized void reset() throws IOException { + raf.seek(mark); + left = markleft; + } + + public long skip(long n) throws IOException { + if (n > left) + n = left; + n = super.skip(n); + if (n == -1) + return -1; + left -= n; + return n; + } + + public int read(byte b[], int off, int len) throws IOException { + if (len > left) + len = (int)left; + if (left == 0) + return -1; + len = raf.read(b, off, len); + if (len == -1) + return -1; + left -= len; + return len; + } + + public int read(byte[] b) throws IOException { + if (len > left) + len = (int)left; + if (left == 0) + return -1; + int len = raf.read(b); + if (len == -1) + return -1; + left -= len; + return len; + } + + public int read() throws IOException { + if (len == 0) + return -1; + int b = raf.read(); + if (b == -1) + return -1; + len--; + return b; + } + + public void close() throws IOException { + raf.close(); + } + } + + private ModelByteBuffer(ModelByteBuffer parent, + long beginIndex, long endIndex, boolean independent) { + this.root = parent.root; + this.offset = 0; + this.len = parent.len; + if (beginIndex < 0) + beginIndex = 0; + if (beginIndex > len) + beginIndex = len; + if (endIndex < 0) + endIndex = 0; + if (endIndex > len) + endIndex = len; + if (beginIndex > endIndex) + beginIndex = endIndex; + offset = beginIndex; + len = endIndex - beginIndex; + if (independent) { + buffer = root.buffer; + if (root.file != null) { + file = root.file; + fileoffset = root.fileoffset + arrayOffset(); + offset = 0; + } else + offset = arrayOffset(); + root = this; + } + } + + public ModelByteBuffer(byte[] buffer) { + this.buffer = buffer; + this.offset = 0; + this.len = buffer.length; + } + + public ModelByteBuffer(byte[] buffer, int offset, int len) { + this.buffer = buffer; + this.offset = offset; + this.len = len; + } + + public ModelByteBuffer(File file) { + this.file = file; + this.fileoffset = 0; + this.len = file.length(); + } + + public ModelByteBuffer(File file, long offset, long len) { + this.file = file; + this.fileoffset = offset; + this.len = len; + } + + public void writeTo(OutputStream out) throws IOException { + if (root.file != null && root.buffer == null) { + InputStream is = getInputStream(); + byte[] buff = new byte[1024]; + int ret; + while ((ret = is.read(buff)) != -1) + out.write(buff, 0, ret); + } else + out.write(array(), (int) arrayOffset(), (int) capacity()); + } + + public InputStream getInputStream() { + if (root.file != null && root.buffer == null) { + try { + return new RandomFileInputStream(); + } catch (IOException e) { + //e.printStackTrace(); + return null; + } + } + return new ByteArrayInputStream(array(), + (int)arrayOffset(), (int)capacity()); + } + + public ModelByteBuffer subbuffer(long beginIndex) { + return subbuffer(beginIndex, capacity()); + } + + public ModelByteBuffer subbuffer(long beginIndex, long endIndex) { + return subbuffer(beginIndex, endIndex, false); + } + + public ModelByteBuffer subbuffer(long beginIndex, long endIndex, + boolean independent) { + return new ModelByteBuffer(this, beginIndex, endIndex, independent); + } + + public byte[] array() { + return root.buffer; + } + + public long arrayOffset() { + if (root != this) + return root.arrayOffset() + offset; + return offset; + } + + public long capacity() { + return len; + } + + public ModelByteBuffer getRoot() { + return root; + } + + public File getFile() { + return file; + } + + public long getFilePointer() { + return fileoffset; + } + + public static void loadAll(Collection col) + throws IOException { + File selfile = null; + RandomAccessFile raf = null; + try { + for (ModelByteBuffer mbuff : col) { + mbuff = mbuff.root; + if (mbuff.file == null) + continue; + if (mbuff.buffer != null) + continue; + if (selfile == null || !selfile.equals(mbuff.file)) { + if (raf != null) { + raf.close(); + raf = null; + } + selfile = mbuff.file; + raf = new RandomAccessFile(mbuff.file, "r"); + } + raf.seek(mbuff.fileoffset); + byte[] buffer = new byte[(int) mbuff.capacity()]; + + int read = 0; + int avail = buffer.length; + while (read != avail) { + if (avail - read > 65536) { + raf.read(buffer, read, 65536); + read += 65536; + } else { + raf.read(buffer, read, avail - read); + read = avail; + } + + } + + mbuff.buffer = buffer; + mbuff.offset = 0; + } + } finally { + if (raf != null) + raf.close(); + } + } + + public void load() throws IOException { + if (root != this) { + root.load(); + return; + } + if (buffer != null) + return; + if (file == null) { + throw new IllegalStateException( + "No file associated with this ByteBuffer!"); + } + + InputStream is = getInputStream(); + buffer = new byte[(int) capacity()]; + offset = 0; + is.read(buffer); + is.close(); + + } + + public void unload() { + if (root != this) { + root.unload(); + return; + } + if (file == null) { + throw new IllegalStateException( + "No file associated with this ByteBuffer!"); + } + root.buffer = null; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelByteBufferWavetable.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,281 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import java.io.InputStream; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFormat.Encoding; + +/** + * Wavetable oscillator for pre-loaded data. + * + * @author Karl Helgason + */ +public class ModelByteBufferWavetable implements ModelWavetable { + + private class Buffer8PlusInputStream extends InputStream { + + private boolean bigendian; + private int framesize_pc; + int pos = 0; + int pos2 = 0; + int markpos = 0; + int markpos2 = 0; + + public Buffer8PlusInputStream() { + framesize_pc = format.getFrameSize() / format.getChannels(); + bigendian = format.isBigEndian(); + } + + public int read(byte[] b, int off, int len) throws IOException { + int avail = available(); + if (avail <= 0) + return -1; + if (len > avail) + len = avail; + byte[] buff1 = buffer.array(); + byte[] buff2 = buffer8.array(); + pos += buffer.arrayOffset(); + pos2 += buffer8.arrayOffset(); + if (bigendian) { + for (int i = 0; i < len; i += (framesize_pc + 1)) { + System.arraycopy(buff1, pos, b, i, framesize_pc); + System.arraycopy(buff2, pos2, b, i + framesize_pc, 1); + pos += framesize_pc; + pos2 += 1; + } + } else { + for (int i = 0; i < len; i += (framesize_pc + 1)) { + System.arraycopy(buff2, pos2, b, i, 1); + System.arraycopy(buff1, pos, b, i + 1, framesize_pc); + pos += framesize_pc; + pos2 += 1; + } + } + pos -= buffer.arrayOffset(); + pos2 -= buffer8.arrayOffset(); + return len; + } + + public long skip(long n) throws IOException { + int avail = available(); + if (avail <= 0) + return -1; + if (n > avail) + n = avail; + pos += (n / (framesize_pc + 1)) * (framesize_pc); + pos2 += n / (framesize_pc + 1); + return super.skip(n); + } + + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + public int read() throws IOException { + byte[] b = new byte[1]; + int ret = read(b, 0, 1); + if (ret == -1) + return -1; + return 0 & 0xFF; + } + + public boolean markSupported() { + return true; + } + + public int available() throws IOException { + return (int)buffer.capacity() + (int)buffer8.capacity() - pos - pos2; + } + + public synchronized void mark(int readlimit) { + markpos = pos; + markpos2 = pos2; + } + + public synchronized void reset() throws IOException { + pos = markpos; + pos2 = markpos2; + + } + } + + private float loopStart = -1; + private float loopLength = -1; + private ModelByteBuffer buffer; + private ModelByteBuffer buffer8 = null; + private AudioFormat format = null; + private float pitchcorrection = 0; + private float attenuation = 0; + private int loopType = LOOP_TYPE_OFF; + + public ModelByteBufferWavetable(ModelByteBuffer buffer) { + this.buffer = buffer; + } + + public ModelByteBufferWavetable(ModelByteBuffer buffer, + float pitchcorrection) { + this.buffer = buffer; + this.pitchcorrection = pitchcorrection; + } + + public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format) { + this.format = format; + this.buffer = buffer; + } + + public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format, + float pitchcorrection) { + this.format = format; + this.buffer = buffer; + this.pitchcorrection = pitchcorrection; + } + + public void set8BitExtensionBuffer(ModelByteBuffer buffer) { + buffer8 = buffer; + } + + public ModelByteBuffer get8BitExtensionBuffer() { + return buffer8; + } + + public ModelByteBuffer getBuffer() { + return buffer; + } + + public AudioFormat getFormat() { + if (format == null) { + if (buffer == null) + return null; + InputStream is = buffer.getInputStream(); + AudioFormat format = null; + try { + format = AudioSystem.getAudioFileFormat(is).getFormat(); + } catch (Exception e) { + //e.printStackTrace(); + } + try { + is.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + return format; + } + return format; + } + + public AudioFloatInputStream openStream() { + if (buffer == null) + return null; + if (format == null) { + InputStream is = buffer.getInputStream(); + AudioInputStream ais = null; + try { + ais = AudioSystem.getAudioInputStream(is); + } catch (Exception e) { + //e.printStackTrace(); + return null; + } + return AudioFloatInputStream.getInputStream(ais); + } + if (buffer.array() == null) { + return AudioFloatInputStream.getInputStream(new AudioInputStream( + buffer.getInputStream(), format, buffer.capacity())); + } + if (buffer8 != null) { + if (format.getEncoding().equals(Encoding.PCM_SIGNED) + || format.getEncoding().equals(Encoding.PCM_UNSIGNED)) { + InputStream is = new Buffer8PlusInputStream(); + AudioFormat format2 = new AudioFormat( + format.getEncoding(), + format.getSampleRate(), + format.getSampleSizeInBits() + 8, + format.getChannels(), + format.getFrameSize() + (1 * format.getChannels()), + format.getFrameRate(), + format.isBigEndian()); + + AudioInputStream ais = new AudioInputStream(is, format2, + buffer.capacity() / format.getFrameSize()); + return AudioFloatInputStream.getInputStream(ais); + } + } + return AudioFloatInputStream.getInputStream(format, buffer.array(), + (int)buffer.arrayOffset(), (int)buffer.capacity()); + } + + public int getChannels() { + return getFormat().getChannels(); + } + + public ModelOscillatorStream open(float samplerate) { + // ModelWavetableOscillator doesn't support ModelOscillatorStream + return null; + } + + // attenuation is in cB + public float getAttenuation() { + return attenuation; + } + // attenuation is in cB + public void setAttenuation(float attenuation) { + this.attenuation = attenuation; + } + + public float getLoopLength() { + return loopLength; + } + + public void setLoopLength(float loopLength) { + this.loopLength = loopLength; + } + + public float getLoopStart() { + return loopStart; + } + + public void setLoopStart(float loopStart) { + this.loopStart = loopStart; + } + + public void setLoopType(int loopType) { + this.loopType = loopType; + } + + public int getLoopType() { + return loopType; + } + + public float getPitchcorrection() { + return pitchcorrection; + } + + public void setPitchcorrection(float pitchcorrection) { + this.pitchcorrection = pitchcorrection; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelChannelMixer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelChannelMixer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.MidiChannel; + +/** + * ModelChannelMixer is used to process channel voice mix output before going + * to master output.
+ * It can be used to:
+ *

    + *
  • Implement non-voice oriented instruments.
  • + *
  • Add insert effect to instruments; for example distortion effect.
  • + * + *

    + * Warning! Classes that implements ModelChannelMixer must be thread-safe. + * + * @author Karl Helgason + */ +public interface ModelChannelMixer extends MidiChannel { + + // Used to process input audio from voices mix. + public boolean process(float[][] buffer, int offset, int len); + + // Is used to trigger that this mixer is not be used + // and it should fade out. + public void stop(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelConnectionBlock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelConnectionBlock.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,135 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Connection blocks are used to connect source variable + * to a destination variable. + * For example Note On velocity can be connected to output gain. + * In DLS this is called articulator and in SoundFonts (SF2) a modulator. + * + * @author Karl Helgason + */ +public class ModelConnectionBlock { + + // + // source1 * source2 * scale -> destination + // + private final static ModelSource[] no_sources = new ModelSource[0]; + private ModelSource[] sources = no_sources; + private double scale = 1; + private ModelDestination destination; + + public ModelConnectionBlock() { + } + + public ModelConnectionBlock(double scale, ModelDestination destination) { + this.scale = scale; + this.destination = destination; + } + + public ModelConnectionBlock(ModelSource source, + ModelDestination destination) { + if (source != null) { + this.sources = new ModelSource[1]; + this.sources[0] = source; + } + this.destination = destination; + } + + public ModelConnectionBlock(ModelSource source, double scale, + ModelDestination destination) { + if (source != null) { + this.sources = new ModelSource[1]; + this.sources[0] = source; + } + this.scale = scale; + this.destination = destination; + } + + public ModelConnectionBlock(ModelSource source, ModelSource control, + ModelDestination destination) { + if (source != null) { + if (control == null) { + this.sources = new ModelSource[1]; + this.sources[0] = source; + } else { + this.sources = new ModelSource[2]; + this.sources[0] = source; + this.sources[1] = control; + } + } + this.destination = destination; + } + + public ModelConnectionBlock(ModelSource source, ModelSource control, + double scale, ModelDestination destination) { + if (source != null) { + if (control == null) { + this.sources = new ModelSource[1]; + this.sources[0] = source; + } else { + this.sources = new ModelSource[2]; + this.sources[0] = source; + this.sources[1] = control; + } + } + this.scale = scale; + this.destination = destination; + } + + public ModelDestination getDestination() { + return destination; + } + + public void setDestination(ModelDestination destination) { + this.destination = destination; + } + + public double getScale() { + return scale; + } + + public void setScale(double scale) { + this.scale = scale; + } + + public ModelSource[] getSources() { + return sources; + } + + public void setSources(ModelSource[] source) { + this.sources = source; + } + + public void addSource(ModelSource source) { + ModelSource[] oldsources = sources; + sources = new ModelSource[oldsources.length + 1]; + for (int i = 0; i < oldsources.length; i++) { + sources[i] = oldsources[i]; + } + sources[sources.length - 1] = source; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelDestination.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelDestination.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,117 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class is used to identify destinations in connection blocks, + * see ModelConnectionBlock. + * + * @author Karl Helgason + */ +public class ModelDestination { + + public static final ModelIdentifier DESTINATION_NONE = null; + public static final ModelIdentifier DESTINATION_KEYNUMBER + = new ModelIdentifier("noteon", "keynumber"); + public static final ModelIdentifier DESTINATION_VELOCITY + = new ModelIdentifier("noteon", "velocity"); + public static final ModelIdentifier DESTINATION_PITCH + = new ModelIdentifier("osc", "pitch"); // cent + public static final ModelIdentifier DESTINATION_GAIN + = new ModelIdentifier("mixer", "gain"); // cB + public static final ModelIdentifier DESTINATION_PAN + = new ModelIdentifier("mixer", "pan"); // 0.1 % + public static final ModelIdentifier DESTINATION_REVERB + = new ModelIdentifier("mixer", "reverb"); // 0.1 % + public static final ModelIdentifier DESTINATION_CHORUS + = new ModelIdentifier("mixer", "chorus"); // 0.1 % + public static final ModelIdentifier DESTINATION_LFO1_DELAY + = new ModelIdentifier("lfo", "delay", 0); // timecent + public static final ModelIdentifier DESTINATION_LFO1_FREQ + = new ModelIdentifier("lfo", "freq", 0); // cent + public static final ModelIdentifier DESTINATION_LFO2_DELAY + = new ModelIdentifier("lfo", "delay", 1); // timecent + public static final ModelIdentifier DESTINATION_LFO2_FREQ + = new ModelIdentifier("lfo", "freq", 1); // cent + public static final ModelIdentifier DESTINATION_EG1_DELAY + = new ModelIdentifier("eg", "delay", 0); // timecent + public static final ModelIdentifier DESTINATION_EG1_ATTACK + = new ModelIdentifier("eg", "attack", 0); // timecent + public static final ModelIdentifier DESTINATION_EG1_HOLD + = new ModelIdentifier("eg", "hold", 0); // timecent + public static final ModelIdentifier DESTINATION_EG1_DECAY + = new ModelIdentifier("eg", "decay", 0); // timecent + public static final ModelIdentifier DESTINATION_EG1_SUSTAIN + = new ModelIdentifier("eg", "sustain", 0); + // 0.1 % (I want this to be value not %) + public static final ModelIdentifier DESTINATION_EG1_RELEASE + = new ModelIdentifier("eg", "release", 0); // timecent + public static final ModelIdentifier DESTINATION_EG1_SHUTDOWN + = new ModelIdentifier("eg", "shutdown", 0); // timecent + public static final ModelIdentifier DESTINATION_EG2_DELAY + = new ModelIdentifier("eg", "delay", 1); // timecent + public static final ModelIdentifier DESTINATION_EG2_ATTACK + = new ModelIdentifier("eg", "attack", 1); // timecent + public static final ModelIdentifier DESTINATION_EG2_HOLD + = new ModelIdentifier("eg", "hold", 1); // 0.1 % + public static final ModelIdentifier DESTINATION_EG2_DECAY + = new ModelIdentifier("eg", "decay", 1); // timecent + public static final ModelIdentifier DESTINATION_EG2_SUSTAIN + = new ModelIdentifier("eg", "sustain", 1); + // 0.1 % ( I want this to be value not %) + public static final ModelIdentifier DESTINATION_EG2_RELEASE + = new ModelIdentifier("eg", "release", 1); // timecent + public static final ModelIdentifier DESTINATION_EG2_SHUTDOWN + = new ModelIdentifier("eg", "shutdown", 1); // timecent + public static final ModelIdentifier DESTINATION_FILTER_FREQ + = new ModelIdentifier("filter", "freq", 0); // cent + public static final ModelIdentifier DESTINATION_FILTER_Q + = new ModelIdentifier("filter", "q", 0); // cB + private ModelIdentifier destination = DESTINATION_NONE; + private ModelTransform transform = new ModelStandardTransform(); + + public ModelDestination() { + } + + public ModelDestination(ModelIdentifier id) { + destination = id; + } + + public ModelIdentifier getIdentifier() { + return destination; + } + + public void setIdentifier(ModelIdentifier destination) { + this.destination = destination; + } + + public ModelTransform getTransform() { + return transform; + } + + public void setTransform(ModelTransform transform) { + this.transform = transform; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelDirectedPlayer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelDirectedPlayer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * ModelDirectedPlayer is the one who is directed by ModelDirector + * to play ModelPerformer objects. + * + * @author Karl Helgason + */ +public interface ModelDirectedPlayer { + + public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelDirector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelDirector.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A director chooses what performers should be played for each note on + * and note off events. + * + * ModelInstrument can implement custom performer who chooses what performers + * to play for example by sustain pedal is off or on. + * + * The default director (ModelStandardDirector) chooses performers + * by there keyfrom,keyto,velfrom,velto properties. + * + * @author Karl Helgason + */ +public interface ModelDirector { + + public void noteOn(int noteNumber, int velocity); + + public void noteOff(int noteNumber, int velocity); + + public void close(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelIdentifier.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,162 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class stores the identity of source and destinations in connection + * blocks, see ModelConnectionBlock. + * + * @author Karl Helgason + */ +public class ModelIdentifier { + + /* + * Object Variable + * ------ -------- + * + * // INPUT parameters + * noteon keynumber 7 bit midi value + * velocity 7 bit midi vale + * on 1 or 0 + * + * midi pitch 14 bit midi value + * channel_pressure 7 bit midi value + * poly_pressure 7 bit midi value + * + * midi_cc 0 (midi control #0 7 bit midi value + * 1 (midi control #1 7 bit midi value + * ... + * 127 (midi control #127 7 bit midi value + * + * midi_rpn 0 (midi rpn control #0) 14 bit midi value + * 1 (midi rpn control #1) 14 bit midi value + * .... + * + * // DAHDSR envelope generator + * eg (null) + * delay timecent + * attack timecent + * hold timecent + * decay timecent + * sustain 0.1 % + * release timecent + * + * // Low frequency oscillirator (sine wave) + * lfo (null) + * delay timcent + * freq cent + * + * // Resonance LowPass Filter 6dB slope + * filter (null) (output/input) + * freq cent + * q cB + * + * // The oscillator with preloaded wavetable data + * osc (null) + * pitch cent + * + * // Output mixer pins + * mixer gain cB + * pan 0.1 % + * reverb 0.1 % + * chorus 0.1 % + * + */ + private String object = null; + private String variable = null; + private int instance = 0; + + public ModelIdentifier(String object) { + this.object = object; + } + + public ModelIdentifier(String object, int instance) { + this.object = object; + this.instance = instance; + } + + public ModelIdentifier(String object, String variable) { + this.object = object; + this.variable = variable; + + } + + public ModelIdentifier(String object, String variable, int instance) { + this.object = object; + this.variable = variable; + this.instance = instance; + + } + + public int getInstance() { + return instance; + } + + public void setInstance(int instance) { + this.instance = instance; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getVariable() { + return variable; + } + + public void setVariable(String variable) { + this.variable = variable; + } + + public boolean equals(Object obj) { + if (!(obj instanceof ModelIdentifier)) + return false; + + ModelIdentifier mobj = (ModelIdentifier)obj; + if ((object == null) != (mobj.object == null)) + return false; + if ((variable == null) != (mobj.variable == null)) + return false; + if (mobj.getInstance() != getInstance()) + return false; + if (!(object == null || object.equals(mobj.object))) + return false; + if (!(variable == null || variable.equals(mobj.variable))) + return false; + return true; + } + + public String toString() { + if (variable == null) { + return object + "[" + instance + "]"; + } else { + return object + "[" + instance + "]" + "." + variable; + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.AudioFormat; + +/** + * The model instrument class. + * + *

    The main methods to override are:
    + * getPerformer, getDirector, getChannelMixer. + * + *

    Performers are used to define what voices which will + * playback when using the instrument.
    + * + * ChannelMixer is used to add channel-wide processing + * on voices output or to define non-voice oriented instruments.
    + * + * Director is used to change how the synthesizer + * chooses what performers to play on midi events. + * + * @author Karl Helgason + */ +public abstract class ModelInstrument extends Instrument { + + protected ModelInstrument(Soundbank soundbank, Patch patch, String name, + Class dataClass) { + super(soundbank, patch, name, dataClass); + } + + public ModelDirector getDirector(ModelPerformer[] performers, + MidiChannel channel, ModelDirectedPlayer player) { + return new ModelStandardDirector(performers, player); + } + + public ModelPerformer[] getPerformers() { + return new ModelPerformer[0]; + } + + public ModelChannelMixer getChannelMixer(MidiChannel channel, + AudioFormat format) { + return null; + } + + // Get General MIDI 2 Alias patch for this instrument. + public Patch getPatchAlias() { + Patch patch = getPatch(); + int program = patch.getProgram(); + int bank = patch.getBank(); + if (bank != 0) + return patch; + boolean percussion = false; + if (getPatch() instanceof ModelPatch) + percussion = ((ModelPatch)getPatch()).isPercussion(); + if (percussion) + return new Patch(0x78 << 7, program); + else + return new Patch(0x79 << 7, program); + } + + // Return name of all the keys. + // This information is generated from ModelPerformer.getName() + // returned from getPerformers(). + public String[] getKeys() { + String[] keys = new String[127]; + for (ModelPerformer performer : getPerformers()) { + for (int k = performer.getKeyFrom(); k <= performer.getKeyTo(); k++) { + if (keys[k] == null) { + String name = performer.getName(); + if (name == null) + name = "untitled"; + keys[k] = name; + } + } + } + return keys; + } + + // Return what channels this instrument will probably response + // on General MIDI synthesizer. + public boolean[] getChannels() { + boolean percussion = false; + if (getPatch() instanceof ModelPatch) + percussion = ((ModelPatch)getPatch()).isPercussion(); + + // Check if instrument is percussion. + if (percussion) { + boolean[] ch = new boolean[16]; + for (int i = 0; i < ch.length; i++) + ch[i] = false; + ch[9] = true; + return ch; + } + + // Check if instrument uses General MIDI 2 default banks. + int bank = getPatch().getBank(); + if (bank >> 7 == 0x78 || bank >> 7 == 0x79) { + boolean[] ch = new boolean[16]; + for (int i = 0; i < ch.length; i++) + ch[i] = true; + return ch; + } + + boolean[] ch = new boolean[16]; + for (int i = 0; i < ch.length; i++) + ch[i] = true; + ch[9] = false; + return ch; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelInstrumentComparator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelInstrumentComparator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.Comparator; +import javax.sound.midi.Instrument; +import javax.sound.midi.Patch; + +/** + * Instrument comparator class. + * Used to order instrument by program, bank, percussion. + * + * @author Karl Helgason + */ +public class ModelInstrumentComparator implements Comparator { + + public int compare(Instrument arg0, Instrument arg1) { + Patch p0 = arg0.getPatch(); + Patch p1 = arg1.getPatch(); + int a = p0.getBank() * 128 + p0.getProgram(); + int b = p1.getBank() * 128 + p1.getProgram(); + if (p0 instanceof ModelPatch) { + a += ((ModelPatch)p0).isPercussion() ? 2097152 : 0; + } + if (p1 instanceof ModelPatch) { + b += ((ModelPatch)p1).isPercussion() ? 2097152 : 0; + } + return a - b; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelMappedInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelMappedInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.MidiChannel; +import javax.sound.midi.Patch; +import javax.sound.sampled.AudioFormat; + +/** + * This class is used to map instrument to another patch. + * + * @author Karl Helgason + */ +public class ModelMappedInstrument extends ModelInstrument { + + private ModelInstrument ins; + + public ModelMappedInstrument(ModelInstrument ins, Patch patch) { + super(ins.getSoundbank(), patch, ins.getName(), ins.getDataClass()); + this.ins = ins; + } + + public Object getData() { + return ins.getData(); + } + + public ModelPerformer[] getPerformers() { + return ins.getPerformers(); + } + + public ModelDirector getDirector(ModelPerformer[] performers, + MidiChannel channel, ModelDirectedPlayer player) { + return ins.getDirector(performers, channel, player); + } + + public ModelChannelMixer getChannelMixer(MidiChannel channel, + AudioFormat format) { + return ins.getChannelMixer(channel, format); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelOscillator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelOscillator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This interface is used for oscillators. + * See example in ModelDefaultOscillator which is a wavetable oscillator. + * + * @author Karl Helgason + */ +public interface ModelOscillator { + + public int getChannels(); + + /** + * Attenuation is in cB. + * @return + */ + public float getAttenuation(); + + public ModelOscillatorStream open(float samplerate); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelOscillatorStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelOscillatorStream.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.VoiceStatus; + +/** + * This interface is used for audio streams from ModelOscillator. + * + * @author Karl Helgason + */ +public interface ModelOscillatorStream { + + public void setPitch(float pitch); // Pitch is in cents! + + public void noteOn(MidiChannel channel, VoiceStatus voice, int noteNumber, + int velocity); + + public void noteOff(int velocity); + + public int read(float[][] buffer, int offset, int len) throws IOException; + + public void close() throws IOException; +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelPatch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelPatch.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.Patch; + +/** + * A extended patch object that has isPercussion function. + * Which is necessary to identify percussion instruments + * from melodic instruments. + * + * @author Karl Helgason + */ +public class ModelPatch extends Patch { + + private boolean percussion = false; + + public ModelPatch(int bank, int program) { + super(bank, program); + } + + public ModelPatch(int bank, int program, boolean percussion) { + super(bank, program); + this.percussion = percussion; + } + + public boolean isPercussion() { + return percussion; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelPerformer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelPerformer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class is used to define how to synthesize audio in universal maner + * for both SF2 and DLS instruments. + * + * @author Karl Helgason + */ +public class ModelPerformer { + + private List oscillators = new ArrayList(); + private List connectionBlocks + = new ArrayList(); + private int keyFrom = 0; + private int keyTo = 127; + private int velFrom = 0; + private int velTo = 127; + private int exclusiveClass = 0; + private boolean releaseTrigger = false; + private boolean selfNonExclusive = false; + private Object userObject = null; + private boolean addDefaultConnections = true; + private String name = null; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getConnectionBlocks() { + return connectionBlocks; + } + + public void setConnectionBlocks(List connectionBlocks) { + this.connectionBlocks = connectionBlocks; + } + + public List getOscillators() { + return oscillators; + } + + public int getExclusiveClass() { + return exclusiveClass; + } + + public void setExclusiveClass(int exclusiveClass) { + this.exclusiveClass = exclusiveClass; + } + + public boolean isSelfNonExclusive() { + return selfNonExclusive; + } + + public void setSelfNonExclusive(boolean selfNonExclusive) { + this.selfNonExclusive = selfNonExclusive; + } + + public int getKeyFrom() { + return keyFrom; + } + + public void setKeyFrom(int keyFrom) { + this.keyFrom = keyFrom; + } + + public int getKeyTo() { + return keyTo; + } + + public void setKeyTo(int keyTo) { + this.keyTo = keyTo; + } + + public int getVelFrom() { + return velFrom; + } + + public void setVelFrom(int velFrom) { + this.velFrom = velFrom; + } + + public int getVelTo() { + return velTo; + } + + public void setVelTo(int velTo) { + this.velTo = velTo; + } + + public boolean isReleaseTriggered() { + return releaseTrigger; + } + + public void setReleaseTriggered(boolean value) { + this.releaseTrigger = value; + } + + public Object getUserObject() { + return userObject; + } + + public void setUserObject(Object object) { + userObject = object; + } + + public boolean isDefaultConnectionsEnabled() { + return addDefaultConnections; + } + + public void setDefaultConnectionsEnabled(boolean addDefaultConnections) { + this.addDefaultConnections = addDefaultConnections; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelSource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelSource.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This class is used to identify sources in connection blocks, + * see ModelConnectionBlock. + * + * @author Karl Helgason + */ +public class ModelSource { + + public static final ModelIdentifier SOURCE_NONE = null; + public static final ModelIdentifier SOURCE_NOTEON_KEYNUMBER = + new ModelIdentifier("noteon", "keynumber"); // midi keynumber + public static final ModelIdentifier SOURCE_NOTEON_VELOCITY = + new ModelIdentifier("noteon", "velocity"); // midi velocity + public static final ModelIdentifier SOURCE_EG1 = + new ModelIdentifier("eg", null, 0); + public static final ModelIdentifier SOURCE_EG2 = + new ModelIdentifier("eg", null, 1); + public static final ModelIdentifier SOURCE_LFO1 = + new ModelIdentifier("lfo", null, 0); + public static final ModelIdentifier SOURCE_LFO2 = + new ModelIdentifier("lfo", null, 1); + public static final ModelIdentifier SOURCE_MIDI_PITCH = + new ModelIdentifier("midi", "pitch", 0); // (0..16383) + public static final ModelIdentifier SOURCE_MIDI_CHANNEL_PRESSURE = + new ModelIdentifier("midi", "channel_pressure", 0); // (0..127) +// public static final ModelIdentifier SOURCE_MIDI_MONO_PRESSURE = +// new ModelIdentifier("midi","mono_pressure",0); // (0..127) + public static final ModelIdentifier SOURCE_MIDI_POLY_PRESSURE = + new ModelIdentifier("midi", "poly_pressure", 0); // (0..127) + public static final ModelIdentifier SOURCE_MIDI_CC_0 = + new ModelIdentifier("midi_cc", "0", 0); // (0..127) + public static final ModelIdentifier SOURCE_MIDI_RPN_0 = + new ModelIdentifier("midi_rpn", "0", 0); // (0..16383) + private ModelIdentifier source = SOURCE_NONE; + private ModelTransform transform; + + public ModelSource() { + this.transform = new ModelStandardTransform(); + } + + public ModelSource(ModelIdentifier id) { + source = id; + this.transform = new ModelStandardTransform(); + } + + public ModelSource(ModelIdentifier id, boolean direction) { + source = id; + this.transform = new ModelStandardTransform(direction); + } + + public ModelSource(ModelIdentifier id, boolean direction, boolean polarity) { + source = id; + this.transform = new ModelStandardTransform(direction, polarity); + } + + public ModelSource(ModelIdentifier id, boolean direction, boolean polarity, + int transform) { + source = id; + this.transform = + new ModelStandardTransform(direction, polarity, transform); + } + + public ModelSource(ModelIdentifier id, ModelTransform transform) { + source = id; + this.transform = transform; + } + + public ModelIdentifier getIdentifier() { + return source; + } + + public void setIdentifier(ModelIdentifier source) { + this.source = source; + } + + public ModelTransform getTransform() { + return transform; + } + + public void setTransform(ModelTransform transform) { + this.transform = transform; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelStandardDirector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelStandardDirector.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A standard director who chooses performers + * by there keyfrom,keyto,velfrom,velto properties. + * + * @author Karl Helgason + */ +public class ModelStandardDirector implements ModelDirector { + + ModelPerformer[] performers; + ModelDirectedPlayer player; + boolean noteOnUsed = false; + boolean noteOffUsed = false; + + public ModelStandardDirector(ModelPerformer[] performers, + ModelDirectedPlayer player) { + this.performers = performers; + this.player = player; + for (int i = 0; i < performers.length; i++) { + ModelPerformer p = performers[i]; + if (p.isReleaseTriggered()) { + noteOffUsed = true; + } else { + noteOnUsed = true; + } + } + } + + public void close() { + } + + public void noteOff(int noteNumber, int velocity) { + if (!noteOffUsed) + return; + for (int i = 0; i < performers.length; i++) { + ModelPerformer p = performers[i]; + if (p.getKeyFrom() <= noteNumber && p.getKeyTo() >= noteNumber) { + if (p.getVelFrom() <= velocity && p.getVelTo() >= velocity) { + if (p.isReleaseTriggered()) { + player.play(i, null); + } + } + } + } + } + + public void noteOn(int noteNumber, int velocity) { + if (!noteOnUsed) + return; + for (int i = 0; i < performers.length; i++) { + ModelPerformer p = performers[i]; + if (p.getKeyFrom() <= noteNumber && p.getKeyTo() >= noteNumber) { + if (p.getVelFrom() <= velocity && p.getVelTo() >= velocity) { + if (!p.isReleaseTriggered()) { + player.play(i, null); + } + } + } + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelStandardTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelStandardTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,139 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A standard transformer used in connection blocks. + * It expects input values to be between 0 and 1. + * + * The result of the transform is + * between 0 and 1 if polarity = unipolar and + * between -1 and 1 if polarity = bipolar. + * + * These constraints only applies to Concave, Convex and Switch transforms. + * + * @author Karl Helgason + */ +public class ModelStandardTransform implements ModelTransform { + + public static final boolean DIRECTION_MIN2MAX = false; + public static final boolean DIRECTION_MAX2MIN = true; + public static final boolean POLARITY_UNIPOLAR = false; + public static final boolean POLARITY_BIPOLAR = true; + public static final int TRANSFORM_LINEAR = 0; + // concave: output = (20*log10(127^2/value^2)) / 96 + public static final int TRANSFORM_CONCAVE = 1; + // convex: same as concave except that start and end point are reversed. + public static final int TRANSFORM_CONVEX = 2; + // switch: if value > avg(max,min) then max else min + public static final int TRANSFORM_SWITCH = 3; + public static final int TRANSFORM_ABSOLUTE = 4; + private boolean direction = DIRECTION_MIN2MAX; + private boolean polarity = POLARITY_UNIPOLAR; + private int transform = TRANSFORM_LINEAR; + + public ModelStandardTransform() { + } + + public ModelStandardTransform(boolean direction) { + this.direction = direction; + } + + public ModelStandardTransform(boolean direction, boolean polarity) { + this.direction = direction; + this.polarity = polarity; + } + + public ModelStandardTransform(boolean direction, boolean polarity, + int transform) { + this.direction = direction; + this.polarity = polarity; + this.transform = transform; + } + + public double transform(double value) { + double s; + double a; + if (direction == DIRECTION_MAX2MIN) + value = 1.0 - value; + if (polarity == POLARITY_BIPOLAR) + value = value * 2.0 - 1.0; + switch (transform) { + case TRANSFORM_CONCAVE: + s = Math.signum(value); + a = Math.abs(value); + a = -((5.0 / 12.0) / Math.log(10)) * Math.log(1.0 - a); + if (a < 0) + a = 0; + else if (a > 1) + a = 1; + return s * a; + case TRANSFORM_CONVEX: + s = Math.signum(value); + a = Math.abs(value); + a = 1.0 + ((5.0 / 12.0) / Math.log(10)) * Math.log(a); + if (a < 0) + a = 0; + else if (a > 1) + a = 1; + return s * a; + case TRANSFORM_SWITCH: + if (polarity == POLARITY_BIPOLAR) + return (value > 0) ? 1 : -1; + else + return (value > 0.5) ? 1 : 0; + case TRANSFORM_ABSOLUTE: + return Math.abs(value); + default: + break; + } + + return value; + } + + public boolean getDirection() { + return direction; + } + + public void setDirection(boolean direction) { + this.direction = direction; + } + + public boolean getPolarity() { + return polarity; + } + + public void setPolarity(boolean polarity) { + this.polarity = polarity; + } + + public int getTransform() { + return transform; + } + + public void setTransform(int transform) { + this.transform = transform; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Model transform interface. + * + * @author Karl Helgason + */ +public interface ModelTransform { + + abstract public double transform(double value); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/ModelWavetable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/ModelWavetable.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This is a wavetable oscillator interface. + * + * @author Karl Helgason + */ +public interface ModelWavetable extends ModelOscillator { + + public static final int LOOP_TYPE_OFF = 0; + public static final int LOOP_TYPE_FORWARD = 1; + public static final int LOOP_TYPE_RELEASE = 2; + public static final int LOOP_TYPE_PINGPONG = 4; + public static final int LOOP_TYPE_REVERSE = 8; + + public AudioFloatInputStream openStream(); + + public float getLoopLength(); + + public float getLoopStart(); + + public int getLoopType(); + + public float getPitchcorrection(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/Platform.java --- a/jdk/src/share/classes/com/sun/media/sound/Platform.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/Platform.java Fri May 30 00:00:00 2008 +0200 @@ -42,8 +42,6 @@ // native library we need to load private static final String libNameMain = "jsound"; - private static final String libNameMain2 = "jsoundhs"; - private static final String libNameALSA = "jsoundalsa"; private static final String libNameDSound = "jsoundds"; @@ -162,16 +160,9 @@ JSSecurityManager.loadLibrary(libNameMain); // just for the heck of it... loadedLibs |= LIB_MAIN; - // load "closed" library - JSSecurityManager.loadLibrary(libNameMain2); } catch (SecurityException e) { if(Printer.err)Printer.err("Security exception loading main native library. JavaSound requires access to these resources."); throw(e); - } catch (UnsatisfiedLinkError e) { - // libNameMain2 may be absent! - if ((loadedLibs & LIB_MAIN) != LIB_MAIN) { - throw(e); - } } // now try to load extra libs. They are defined at compile time in the Makefile diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/RIFFInvalidDataException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/RIFFInvalidDataException.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This exception is used when a RIFF file contains illegal or unexpected data. + * + * @author Karl Helgason + */ +public class RIFFInvalidDataException extends InvalidDataException { + + private static final long serialVersionUID = 1L; + + public RIFFInvalidDataException() { + super("Invalid Data!"); + } + + public RIFFInvalidDataException(String s) { + super(s); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/RIFFInvalidFormatException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/RIFFInvalidFormatException.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * This exception is used when a reader is used to read RIFF file of a format it + * doesn't unterstand or support. + * + * @author Karl Helgason + */ +public class RIFFInvalidFormatException extends InvalidFormatException { + + private static final long serialVersionUID = 1L; + + public RIFFInvalidFormatException() { + super("Invalid format!"); + } + + public RIFFInvalidFormatException(String s) { + super(s); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/RIFFReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/RIFFReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,302 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Resource Interchange File Format (RIFF) stream decoder. + * + * @author Karl Helgason + */ +public class RIFFReader extends InputStream { + + private RIFFReader root; + private long filepointer = 0; + private String fourcc; + private String riff_type = null; + private long ckSize = 0; + private InputStream stream; + private long avail; + private RIFFReader lastiterator = null; + + public RIFFReader(InputStream stream) throws IOException { + + if (stream instanceof RIFFReader) + root = ((RIFFReader)stream).root; + else + root = this; + + this.stream = stream; + avail = stream.available(); + ckSize = stream.available(); + + // Check for RIFF null paddings, + int b; + while (true) { + b = read(); + if (b == -1) { + fourcc = ""; // don't put null value into fourcc, + // because it is expected to + // always contain a string value + riff_type = null; + avail = 0; + return; + } + if (b != 0) + break; + } + + byte[] fourcc = new byte[4]; + fourcc[0] = (byte) b; + read(fourcc, 1, 3); + this.fourcc = new String(fourcc, "ascii"); + ckSize = readUnsignedInt(); + + avail = this.ckSize; + + if (getFormat().equals("RIFF") || getFormat().equals("LIST")) { + byte[] format = new byte[4]; + read(format); + this.riff_type = new String(format, "ascii"); + } + } + + public long getFilePointer() throws IOException { + return root.filepointer; + } + + public boolean hasNextChunk() throws IOException { + if (lastiterator != null) + lastiterator.finish(); + return avail != 0; + } + + public RIFFReader nextChunk() throws IOException { + if (lastiterator != null) + lastiterator.finish(); + if (avail == 0) + return null; + lastiterator = new RIFFReader(this); + return lastiterator; + } + + public String getFormat() { + return fourcc; + } + + public String getType() { + return riff_type; + } + + public long getSize() { + return ckSize; + } + + public int read() throws IOException { + if (avail == 0) + return -1; + int b = stream.read(); + if (b == -1) + return -1; + avail--; + filepointer++; + return b; + } + + public int read(byte[] b, int offset, int len) throws IOException { + if (avail == 0) + return -1; + if (len > avail) { + int rlen = stream.read(b, offset, (int)avail); + if (rlen != -1) + filepointer += rlen; + avail = 0; + return rlen; + } else { + avail -= len; + int ret = stream.read(b, offset, len); + if (ret == -1) + return -1; + filepointer += ret; + return ret; + } + } + + public long skip(long n) throws IOException { + if (avail == 0) + return -1; + if (n > avail) { + long len = stream.skip(avail); + if (len != -1) + filepointer += len; + avail = 0; + return len; + } else { + avail -= n; + long ret = stream.skip(n); + if (ret == -1) + return -1; + filepointer += ret; + return ret; + } + } + + public int available() { + return (int)avail; + } + + public void finish() throws IOException { + if (avail != 0) { + long ret = stream.skip(avail); + if (ret != -1) + filepointer += ret; + avail = 0; + } + } + + // Read ASCII chars from stream + public String readString(int len) throws IOException { + byte[] buff = new byte[len]; + read(buff); + for (int i = 0; i < buff.length; i++) { + if (buff[i] == 0) { + return new String(buff, 0, i, "ascii"); + } + } + return new String(buff, "ascii"); + } + + // Read 8 bit signed integer from stream + public byte readByte() throws IOException { + int ch = read(); + if (ch < 0) + throw new EOFException(); + return (byte) ch; + } + + // Read 16 bit signed integer from stream + public short readShort() throws IOException { + int ch1 = read(); + int ch2 = read(); + if (ch1 < 0) + throw new EOFException(); + if (ch2 < 0) + throw new EOFException(); + return (short)(ch1 | (ch2 << 8)); + } + + // Read 32 bit signed integer from stream + public int readInt() throws IOException { + int ch1 = read(); + int ch2 = read(); + int ch3 = read(); + int ch4 = read(); + if (ch1 < 0) + throw new EOFException(); + if (ch2 < 0) + throw new EOFException(); + if (ch3 < 0) + throw new EOFException(); + if (ch4 < 0) + throw new EOFException(); + return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24); + } + + // Read 64 bit signed integer from stream + public long readLong() throws IOException { + long ch1 = read(); + long ch2 = read(); + long ch3 = read(); + long ch4 = read(); + long ch5 = read(); + long ch6 = read(); + long ch7 = read(); + long ch8 = read(); + if (ch1 < 0) + throw new EOFException(); + if (ch2 < 0) + throw new EOFException(); + if (ch3 < 0) + throw new EOFException(); + if (ch4 < 0) + throw new EOFException(); + if (ch5 < 0) + throw new EOFException(); + if (ch6 < 0) + throw new EOFException(); + if (ch7 < 0) + throw new EOFException(); + if (ch8 < 0) + throw new EOFException(); + return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24) + | (ch5 << 32) | (ch6 << 40) | (ch7 << 48) | (ch8 << 56); + } + + // Read 8 bit unsigned integer from stream + public int readUnsignedByte() throws IOException { + int ch = read(); + if (ch < 0) + throw new EOFException(); + return ch; + } + + // Read 16 bit unsigned integer from stream + public int readUnsignedShort() throws IOException { + int ch1 = read(); + int ch2 = read(); + if (ch1 < 0) + throw new EOFException(); + if (ch2 < 0) + throw new EOFException(); + return ch1 | (ch2 << 8); + } + + // Read 32 bit unsigned integer from stream + public long readUnsignedInt() throws IOException { + long ch1 = read(); + long ch2 = read(); + long ch3 = read(); + long ch4 = read(); + if (ch1 < 0) + throw new EOFException(); + if (ch2 < 0) + throw new EOFException(); + if (ch3 < 0) + throw new EOFException(); + if (ch4 < 0) + throw new EOFException(); + return ch1 + (ch2 << 8) | (ch3 << 16) | (ch4 << 24); + } + + public void close() throws IOException { + finish(); + if (this == root) + stream.close(); + stream = null; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/RIFFWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/RIFFWriter.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,365 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.io.RandomAccessFile; + +/** + * Resource Interchange File Format (RIFF) stream encoder. + * + * @author Karl Helgason + */ +public class RIFFWriter extends OutputStream { + + private interface RandomAccessWriter { + + public void seek(long chunksizepointer) throws IOException; + + public long getPointer() throws IOException; + + public void close() throws IOException; + + public void write(int b) throws IOException; + + public void write(byte[] b, int off, int len) throws IOException; + + public void write(byte[] bytes) throws IOException; + + public long length() throws IOException; + + public void setLength(long i) throws IOException; + } + + private static class RandomAccessFileWriter implements RandomAccessWriter { + + RandomAccessFile raf; + + public RandomAccessFileWriter(File file) throws FileNotFoundException { + this.raf = new RandomAccessFile(file, "rw"); + } + + public RandomAccessFileWriter(String name) throws FileNotFoundException { + this.raf = new RandomAccessFile(name, "rw"); + } + + public void seek(long chunksizepointer) throws IOException { + raf.seek(chunksizepointer); + } + + public long getPointer() throws IOException { + return raf.getFilePointer(); + } + + public void close() throws IOException { + raf.close(); + } + + public void write(int b) throws IOException { + raf.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException { + raf.write(b, off, len); + } + + public void write(byte[] bytes) throws IOException { + raf.write(bytes); + } + + public long length() throws IOException { + return raf.length(); + } + + public void setLength(long i) throws IOException { + raf.setLength(i); + } + } + + private static class RandomAccessByteWriter implements RandomAccessWriter { + + byte[] buff = new byte[32]; + int length = 0; + int pos = 0; + byte[] s; + OutputStream stream; + + public RandomAccessByteWriter(OutputStream stream) { + this.stream = stream; + } + + public void seek(long chunksizepointer) throws IOException { + pos = (int) chunksizepointer; + } + + public long getPointer() throws IOException { + return pos; + } + + public void close() throws IOException { + stream.write(buff, 0, length); + stream.close(); + } + + public void write(int b) throws IOException { + if (s == null) + s = new byte[1]; + s[0] = (byte)b; + write(s, 0, 1); + } + + public void write(byte[] b, int off, int len) throws IOException { + int newsize = pos + len; + if (newsize > length) + setLength(newsize); + int end = off + len; + for (int i = off; i < end; i++) { + buff[pos++] = b[i]; + } + } + + public void write(byte[] bytes) throws IOException { + write(bytes, 0, bytes.length); + } + + public long length() throws IOException { + return length; + } + + public void setLength(long i) throws IOException { + length = (int) i; + if (length > buff.length) { + int newlen = Math.max(buff.length << 1, length); + byte[] newbuff = new byte[newlen]; + System.arraycopy(buff, 0, newbuff, 0, buff.length); + buff = newbuff; + } + } + } + private int chunktype = 0; // 0=RIFF, 1=LIST; 2=CHUNK + private RandomAccessWriter raf; + private long chunksizepointer; + private long startpointer; + private RIFFWriter childchunk = null; + private boolean open = true; + private boolean writeoverride = false; + + public RIFFWriter(String name, String format) throws IOException { + this(new RandomAccessFileWriter(name), format, 0); + } + + public RIFFWriter(File file, String format) throws IOException { + this(new RandomAccessFileWriter(file), format, 0); + } + + public RIFFWriter(OutputStream stream, String format) throws IOException { + this(new RandomAccessByteWriter(stream), format, 0); + } + + private RIFFWriter(RandomAccessWriter raf, String format, int chunktype) + throws IOException { + if (chunktype == 0) + if (raf.length() != 0) + raf.setLength(0); + this.raf = raf; + if (raf.getPointer() % 2 != 0) + raf.write(0); + + if (chunktype == 0) + raf.write("RIFF".getBytes("ascii")); + else if (chunktype == 1) + raf.write("LIST".getBytes("ascii")); + else + raf.write((format + " ").substring(0, 4).getBytes("ascii")); + + chunksizepointer = raf.getPointer(); + this.chunktype = 2; + writeUnsignedInt(0); + this.chunktype = chunktype; + startpointer = raf.getPointer(); + if (chunktype != 2) + raf.write((format + " ").substring(0, 4).getBytes("ascii")); + + } + + public void seek(long pos) throws IOException { + raf.seek(pos); + } + + public long getFilePointer() throws IOException { + return raf.getPointer(); + } + + public void setWriteOverride(boolean writeoverride) { + this.writeoverride = writeoverride; + } + + public boolean getWriteOverride() { + return writeoverride; + } + + public void close() throws IOException { + if (!open) + return; + if (childchunk != null) { + childchunk.close(); + childchunk = null; + } + + int bakchunktype = chunktype; + long fpointer = raf.getPointer(); + raf.seek(chunksizepointer); + chunktype = 2; + writeUnsignedInt(fpointer - startpointer); + + if (bakchunktype == 0) + raf.close(); + else + raf.seek(fpointer); + open = false; + raf = null; + } + + public void write(int b) throws IOException { + if (!writeoverride) { + if (chunktype != 2) { + throw new IllegalArgumentException( + "Only chunks can write bytes!"); + } + if (childchunk != null) { + childchunk.close(); + childchunk = null; + } + } + raf.write(b); + } + + public void write(byte b[], int off, int len) throws IOException { + if (!writeoverride) { + if (chunktype != 2) { + throw new IllegalArgumentException( + "Only chunks can write bytes!"); + } + if (childchunk != null) { + childchunk.close(); + childchunk = null; + } + } + raf.write(b, off, len); + } + + public RIFFWriter writeList(String format) throws IOException { + if (chunktype == 2) { + throw new IllegalArgumentException( + "Only LIST and RIFF can write lists!"); + } + if (childchunk != null) { + childchunk.close(); + childchunk = null; + } + childchunk = new RIFFWriter(this.raf, format, 1); + return childchunk; + } + + public RIFFWriter writeChunk(String format) throws IOException { + if (chunktype == 2) { + throw new IllegalArgumentException( + "Only LIST and RIFF can write chunks!"); + } + if (childchunk != null) { + childchunk.close(); + childchunk = null; + } + childchunk = new RIFFWriter(this.raf, format, 2); + return childchunk; + } + + // Write ASCII chars to stream + public void writeString(String string) throws IOException { + byte[] buff = string.getBytes(); + write(buff); + } + + // Write ASCII chars to stream + public void writeString(String string, int len) throws IOException { + byte[] buff = string.getBytes(); + if (buff.length > len) + write(buff, 0, len); + else { + write(buff); + for (int i = buff.length; i < len; i++) + write(0); + } + } + + // Write 8 bit signed integer to stream + public void writeByte(int b) throws IOException { + write(b); + } + + // Write 16 bit signed integer to stream + public void writeShort(short b) throws IOException { + write((b >>> 0) & 0xFF); + write((b >>> 8) & 0xFF); + } + + // Write 32 bit signed integer to stream + public void writeInt(int b) throws IOException { + write((b >>> 0) & 0xFF); + write((b >>> 8) & 0xFF); + write((b >>> 16) & 0xFF); + write((b >>> 24) & 0xFF); + } + + // Write 64 bit signed integer to stream + public void writeLong(long b) throws IOException { + write((int) (b >>> 0) & 0xFF); + write((int) (b >>> 8) & 0xFF); + write((int) (b >>> 16) & 0xFF); + write((int) (b >>> 24) & 0xFF); + write((int) (b >>> 32) & 0xFF); + write((int) (b >>> 40) & 0xFF); + write((int) (b >>> 48) & 0xFF); + write((int) (b >>> 56) & 0xFF); + } + + // Write 8 bit unsigned integer to stream + public void writeUnsignedByte(int b) throws IOException { + writeByte((byte) b); + } + + // Write 16 bit unsigned integer to stream + public void writeUnsignedShort(int b) throws IOException { + writeShort((short) b); + } + + // Write 32 bit unsigned integer to stream + public void writeUnsignedInt(long b) throws IOException { + writeInt((int) b); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java --- a/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/RealTimeSequencer.java Fri May 30 00:00:00 2008 +0200 @@ -54,10 +54,6 @@ private final static boolean DEBUG_PUMP = false; private final static boolean DEBUG_PUMP_ALL = false; - - /** if true, we bridge RMF files over to the old MixerSequencer */ - private final static boolean RMF = true; - /** * Event Dispatcher thread. Should be using a shared event * dispatcher instance with a factory in EventDispatcher @@ -145,9 +141,6 @@ private ArrayList controllerEventListeners = new ArrayList(); - /** for RMF media we need the RMF sequencer */ - private Sequencer seqBridge = null; - /** automatic connection support */ private boolean autoConnect = false; @@ -220,21 +213,6 @@ playThread.setSequence(sequence); } } - if (RMF) { - if (seqBridge != null) { - seqBridge.close(); - seqBridge = null; - } - // if previous file was an RMF, but this file is not RMF, - // then need to call implOpen again! - if (isOpen() && sequence != null && playThread == null) { - try { - implOpen(); - } catch (MidiUnavailableException mue) { - if (Printer.err) mue.printStackTrace(); - } - } - } if (Printer.trace) Printer.trace("<< RealTimeSequencer: setSequence(" + sequence +") completed"); } @@ -249,57 +227,6 @@ return; } - // need to be able to detect RMF - if (RMF) { - MidiFileFormat fileFormat = MidiSystem.getMidiFileFormat(stream); // can throw IOException, InvalidMidiDataException - int type = fileFormat.getType(); - int resolution = fileFormat.getResolution(); - if (Printer.debug) Printer.debug("Got file with type="+type+" and resolution="+resolution); - if (resolution == MidiFileFormat.UNKNOWN_LENGTH) { - // seems to be RMF - if (seqBridge == null) { - try { - try { - Class cls = Class.forName("com.sun.media.sound.MixerSequencer"); - seqBridge = (Sequencer)cls.newInstance(); - } catch (Exception ex) { - throw new InvalidMidiDataException(); - } - if (isOpen()) { - seqBridge.open(); - } - } catch (MidiUnavailableException mue) { - // uhum, strange situation. Need to cast to InvalidMidiDataException - throw new InvalidMidiDataException(mue.getMessage()); - } - } - seqBridge.setSequence(stream); - // propagate state - seqBridge.setTempoFactor(getTempoFactor()); - - // propagate listeners - synchronized(metaEventListeners) { - for (int i = 0 ; i < metaEventListeners.size(); i++) { - seqBridge.addMetaEventListener((MetaEventListener) (metaEventListeners.get(i))); - } - } - synchronized(controllerEventListeners) { - for (int i = 0 ; i < controllerEventListeners.size(); i++) { - ControllerListElement cve = (ControllerListElement) (controllerEventListeners.get(i)); - seqBridge.addControllerEventListener(cve.listener, cve.controllers); - } - } - // disable the current sequence of RealTimeSequencer - //setSequence((Sequence) null); -> will remove bridge again! - this.sequence = null; - return; - } - if (seqBridge != null) { - seqBridge.close(); - seqBridge = null; - } - } - Sequence seq = MidiSystem.getSequence(stream); // can throw IOException, InvalidMidiDataException setSequence(seq); @@ -310,22 +237,11 @@ public Sequence getSequence() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getSequence(); - } - } return sequence; } public synchronized void start() { - if (RMF) { - if (seqBridge != null) { - seqBridge.start(); - return; - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: start()"); // sequencer not open: throw an exception @@ -351,12 +267,6 @@ public synchronized void stop() { - if (RMF) { - if (seqBridge != null) { - seqBridge.stop(); - return; - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: stop()"); if (!isOpen()) { @@ -378,23 +288,11 @@ public boolean isRunning() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.isRunning(); - } - } return running; } public void startRecording() { - if (RMF) { - if (seqBridge != null) { - seqBridge.startRecording(); - return; - } - } - if (!isOpen()) { throw new IllegalStateException("Sequencer not open"); } @@ -405,13 +303,6 @@ public void stopRecording() { - if (RMF) { - if (seqBridge != null) { - seqBridge.stopRecording(); - return; - } - } - if (!isOpen()) { throw new IllegalStateException("Sequencer not open"); } @@ -420,23 +311,11 @@ public boolean isRecording() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.isRecording(); - } - } return recording; } public void recordEnable(Track track, int channel) { - if (RMF) { - if (seqBridge != null) { - seqBridge.recordEnable(track, channel); - return; - } - } - if (!findTrack(track)) { throw new IllegalArgumentException("Track does not exist in the current sequence"); } @@ -454,13 +333,6 @@ public void recordDisable(Track track) { - if (RMF) { - if (seqBridge != null) { - seqBridge.recordDisable(track); - return; - } - } - synchronized(recordingTracks) { RecordingTrack rc = RecordingTrack.get(recordingTracks, track); if (rc != null) { @@ -487,11 +359,6 @@ public float getTempoInBPM() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTempoInBPM(); - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInBPM() "); return (float) MidiUtils.convertTempo(getTempoInMPQ()); @@ -499,12 +366,6 @@ public void setTempoInBPM(float bpm) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTempoInBPM(bpm); - return; - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: setTempoInBPM() "); if (bpm <= 0) { // should throw IllegalArgumentException @@ -516,12 +377,6 @@ public float getTempoInMPQ() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTempoInMPQ(); - } - } - if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoInMPQ() "); if (needCaching()) { @@ -542,12 +397,6 @@ public void setTempoInMPQ(float mpq) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTempoInMPQ(mpq); - return; - } - } if (mpq <= 0) { // should throw IllegalArgumentException mpq = 1.0f; @@ -569,12 +418,6 @@ public void setTempoFactor(float factor) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTempoFactor(factor); - return; - } - } if (factor <= 0) { // should throw IllegalArgumentException return; @@ -593,11 +436,6 @@ public float getTempoFactor() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTempoFactor(); - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTempoFactor() "); if (needCaching()) { @@ -611,11 +449,6 @@ public long getTickLength() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTickLength(); - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickLength() "); if (sequence == null) { @@ -627,11 +460,6 @@ public synchronized long getTickPosition() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTickPosition(); - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: getTickPosition() "); if (getDataPump() == null || sequence == null) { @@ -643,12 +471,6 @@ public synchronized void setTickPosition(long tick) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTickPosition(tick); - return; - } - } if (tick < 0) { // should throw IllegalArgumentException return; @@ -672,12 +494,6 @@ public long getMicrosecondLength() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getMicrosecondLength(); - } - } - if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondLength() "); if (sequence == null) { @@ -689,12 +505,6 @@ public long getMicrosecondPosition() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getMicrosecondPosition(); - } - } - if (Printer.trace) Printer.trace(">> RealTimeSequencer: getMicrosecondPosition() "); if (getDataPump() == null || sequence == null) { @@ -707,13 +517,6 @@ public void setMicrosecondPosition(long microseconds) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setMicrosecondPosition(microseconds); - return; - } - } - if (microseconds < 0) { // should throw IllegalArgumentException return; @@ -739,33 +542,16 @@ public void setMasterSyncMode(Sequencer.SyncMode sync) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setMasterSyncMode(sync); - return; - } - } // not supported } public Sequencer.SyncMode getMasterSyncMode() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getMasterSyncMode(); - } - } return masterSyncMode; } public Sequencer.SyncMode[] getMasterSyncModes() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getMasterSyncModes(); - } - } - Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[masterSyncModes.length]; System.arraycopy(masterSyncModes, 0, returnedModes, 0, masterSyncModes.length); return returnedModes; @@ -773,33 +559,16 @@ public void setSlaveSyncMode(Sequencer.SyncMode sync) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setSlaveSyncMode(sync); - return; - } - } // not supported } public Sequencer.SyncMode getSlaveSyncMode() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getSlaveSyncMode(); - } - } return slaveSyncMode; } public Sequencer.SyncMode[] getSlaveSyncModes() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getSlaveSyncModes(); - } - } - Sequencer.SyncMode[] returnedModes = new Sequencer.SyncMode[slaveSyncModes.length]; System.arraycopy(slaveSyncModes, 0, returnedModes, 0, slaveSyncModes.length); return returnedModes; @@ -817,12 +586,6 @@ public synchronized void setTrackMute(int track, boolean mute) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTrackMute(track, mute); - return; - } - } int trackCount = getTrackCount(); if (track < 0 || track >= getTrackCount()) return; trackMuted = ensureBoolArraySize(trackMuted, trackCount); @@ -834,11 +597,6 @@ public synchronized boolean getTrackMute(int track) { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTrackMute(track); - } - } if (track < 0 || track >= getTrackCount()) return false; if (trackMuted == null || trackMuted.length <= track) return false; return trackMuted[track]; @@ -846,12 +604,6 @@ public synchronized void setTrackSolo(int track, boolean solo) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setTrackSolo(track, solo); - return; - } - } int trackCount = getTrackCount(); if (track < 0 || track >= getTrackCount()) return; trackSolo = ensureBoolArraySize(trackSolo, trackCount); @@ -863,11 +615,6 @@ public synchronized boolean getTrackSolo(int track) { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getTrackSolo(track); - } - } if (track < 0 || track >= getTrackCount()) return false; if (trackSolo == null || trackSolo.length <= track) return false; return trackSolo[track]; @@ -875,12 +622,6 @@ public boolean addMetaEventListener(MetaEventListener listener) { - if (RMF) { - if (seqBridge != null) { - seqBridge.addMetaEventListener(listener); - // do not return here! - } - } synchronized(metaEventListeners) { if (! metaEventListeners.contains(listener)) { @@ -892,12 +633,6 @@ public void removeMetaEventListener(MetaEventListener listener) { - if (RMF) { - if (seqBridge != null) { - seqBridge.removeMetaEventListener(listener); - // do not return here! - } - } synchronized(metaEventListeners) { int index = metaEventListeners.indexOf(listener); if (index >= 0) { @@ -908,13 +643,6 @@ public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) { - if (RMF) { - if (seqBridge != null) { - seqBridge.addControllerEventListener(listener, controllers); - // do not return here! - } - } - synchronized(controllerEventListeners) { // first find the listener. if we have one, add the controllers @@ -943,12 +671,6 @@ public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) { - if (RMF) { - if (seqBridge != null) { - seqBridge.removeControllerEventListener(listener, controllers); - // do not return here! - } - } synchronized(controllerEventListeners) { ControllerListElement cve = null; boolean flag = false; @@ -978,12 +700,6 @@ ////////////////// LOOPING (added in 1.5) /////////////////////// public void setLoopStartPoint(long tick) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setLoopStartPoint(tick); - return; - } - } if ((tick > getTickLength()) || ((loopEnd != -1) && (tick > loopEnd)) || (tick < 0)) { @@ -993,21 +709,10 @@ } public long getLoopStartPoint() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getLoopStartPoint(); - } - } return loopStart; } public void setLoopEndPoint(long tick) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setLoopEndPoint(tick); - return; - } - } if ((tick > getTickLength()) || ((loopStart > tick) && (tick != -1)) || (tick < -1)) { @@ -1017,21 +722,10 @@ } public long getLoopEndPoint() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getLoopEndPoint(); - } - } return loopEnd; } public void setLoopCount(int count) { - if (RMF) { - if (seqBridge != null) { - seqBridge.setLoopCount(count); - return; - } - } if (count != LOOP_CONTINUOUSLY && count < 0) { throw new IllegalArgumentException("illegal value for loop count: "+count); @@ -1043,11 +737,6 @@ } public int getLoopCount() { - if (RMF) { - if (seqBridge != null) { - return seqBridge.getLoopCount(); - } - } return loopCount; } @@ -1058,13 +747,6 @@ */ protected void implOpen() throws MidiUnavailableException { if (Printer.trace) Printer.trace(">> RealTimeSequencer: implOpen()"); - if (RMF) { - if (seqBridge != null) { - seqBridge.open(); - if (Printer.trace) Printer.trace("<< RealTimeSequencer: -> called seqBridge.open"); - return; - } - } //openInternalSynth(); @@ -1100,12 +782,6 @@ synth.open(); if (synth instanceof ReferenceCountingDevice) { rec = ((ReferenceCountingDevice) synth).getReceiverReferenceCounting(); - if (synth.getClass().toString().contains("com.sun.media.sound.MixerSynth") - && (synth.getDefaultSoundbank() == null)) { - // don't use this receiver if no soundbank available - rec = null; - synth.close(); - } } else { rec = synth.getReceiver(); } @@ -1152,12 +828,6 @@ protected synchronized void implClose() { - if (RMF) { - if (seqBridge != null) { - seqBridge.close(); - // don't return here! - } - } if (Printer.trace) Printer.trace(">> RealTimeSequencer: implClose() "); if (playThread == null) { @@ -1307,12 +977,6 @@ // OVERRIDES OF ABSTRACT MIDI DEVICE METHODS protected boolean hasReceivers() { - if (RMF) { - if (seqBridge != null) { - //RMF does not allow recording - return false; - } - } return true; } @@ -1323,12 +987,6 @@ protected boolean hasTransmitters() { - if (RMF) { - if (seqBridge != null) { - //RMF does never allow setting own receivers - return false; - } - } return true; } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2GlobalRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2GlobalRegion.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Soundfont global region. + * + * @author Karl Helgason + */ +public class SF2GlobalRegion extends SF2Region { +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Instrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Instrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,911 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sound.midi.Patch; + +/** + * Soundfont instrument. + * + * @author Karl Helgason + */ +public class SF2Instrument extends ModelInstrument { + + protected String name = ""; + protected int preset = 0; + protected int bank = 0; + protected long library = 0; + protected long genre = 0; + protected long morphology = 0; + protected SF2GlobalRegion globalregion = null; + protected List regions + = new ArrayList(); + + public SF2Instrument() { + super(null, null, null, null); + } + + public SF2Instrument(SF2Soundbank soundbank) { + super(soundbank, null, null, null); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Patch getPatch() { + if (bank == 128) + return new ModelPatch(0, preset, true); + else + return new ModelPatch(bank << 7, preset, false); + } + + public void setPatch(Patch patch) { + if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) { + bank = 128; + preset = patch.getProgram(); + } else { + bank = patch.getBank() >> 7; + preset = patch.getProgram(); + } + } + + public Object getData() { + return null; + } + + public long getGenre() { + return genre; + } + + public void setGenre(long genre) { + this.genre = genre; + } + + public long getLibrary() { + return library; + } + + public void setLibrary(long library) { + this.library = library; + } + + public long getMorphology() { + return morphology; + } + + public void setMorphology(long morphology) { + this.morphology = morphology; + } + + public List getRegions() { + return regions; + } + + public SF2GlobalRegion getGlobalRegion() { + return globalregion; + } + + public void setGlobalZone(SF2GlobalRegion zone) { + globalregion = zone; + } + + public String toString() { + if (bank == 128) + return "Drumkit: " + name + " preset #" + preset; + else + return "Instrument: " + name + " bank #" + bank + + " preset #" + preset; + } + + public ModelPerformer[] getPerformers() { + int performercount = 0; + for (SF2InstrumentRegion presetzone : regions) + performercount += presetzone.getLayer().getRegions().size(); + ModelPerformer[] performers = new ModelPerformer[performercount]; + int pi = 0; + + SF2GlobalRegion presetglobal = globalregion; + for (SF2InstrumentRegion presetzone : regions) { + Map pgenerators = new HashMap(); + pgenerators.putAll(presetzone.getGenerators()); + if (presetglobal != null) + pgenerators.putAll(presetglobal.getGenerators()); + + SF2Layer layer = presetzone.getLayer(); + SF2GlobalRegion layerglobal = layer.getGlobalRegion(); + for (SF2LayerRegion layerzone : layer.getRegions()) { + ModelPerformer performer = new ModelPerformer(); + if (layerzone.getSample() != null) + performer.setName(layerzone.getSample().getName()); + else + performer.setName(layer.getName()); + + performers[pi++] = performer; + + int keyfrom = 0; + int keyto = 127; + int velfrom = 0; + int velto = 127; + + if (layerzone.contains(SF2Region.GENERATOR_EXCLUSIVECLASS)) { + performer.setExclusiveClass(layerzone.getInteger( + SF2Region.GENERATOR_EXCLUSIVECLASS)); + } + if (layerzone.contains(SF2Region.GENERATOR_KEYRANGE)) { + byte[] bytes = layerzone.getBytes( + SF2Region.GENERATOR_KEYRANGE); + if (bytes[0] >= 0) + if (bytes[0] > keyfrom) + keyfrom = bytes[0]; + if (bytes[1] >= 0) + if (bytes[1] < keyto) + keyto = bytes[1]; + } + if (layerzone.contains(SF2Region.GENERATOR_VELRANGE)) { + byte[] bytes = layerzone.getBytes( + SF2Region.GENERATOR_VELRANGE); + if (bytes[0] >= 0) + if (bytes[0] > velfrom) + velfrom = bytes[0]; + if (bytes[1] >= 0) + if (bytes[1] < velto) + velto = bytes[1]; + } + if (presetzone.contains(SF2Region.GENERATOR_KEYRANGE)) { + byte[] bytes = presetzone.getBytes( + SF2Region.GENERATOR_KEYRANGE); + if (bytes[0] > keyfrom) + keyfrom = bytes[0]; + if (bytes[1] < keyto) + keyto = bytes[1]; + } + if (presetzone.contains(SF2Region.GENERATOR_VELRANGE)) { + byte[] bytes = presetzone.getBytes( + SF2Region.GENERATOR_VELRANGE); + if (bytes[0] > velfrom) + velfrom = bytes[0]; + if (bytes[1] < velto) + velto = bytes[1]; + } + performer.setKeyFrom(keyfrom); + performer.setKeyTo(keyto); + performer.setVelFrom(velfrom); + performer.setVelTo(velto); + + int startAddrsOffset = layerzone.getShort( + SF2Region.GENERATOR_STARTADDRSOFFSET); + int endAddrsOffset = layerzone.getShort( + SF2Region.GENERATOR_ENDADDRSOFFSET); + int startloopAddrsOffset = layerzone.getShort( + SF2Region.GENERATOR_STARTLOOPADDRSOFFSET); + int endloopAddrsOffset = layerzone.getShort( + SF2Region.GENERATOR_ENDLOOPADDRSOFFSET); + + startAddrsOffset += layerzone.getShort( + SF2Region.GENERATOR_STARTADDRSCOARSEOFFSET) * 32768; + endAddrsOffset += layerzone.getShort( + SF2Region.GENERATOR_ENDADDRSCOARSEOFFSET) * 32768; + startloopAddrsOffset += layerzone.getShort( + SF2Region.GENERATOR_STARTLOOPADDRSCOARSEOFFSET) * 32768; + endloopAddrsOffset += layerzone.getShort( + SF2Region.GENERATOR_ENDLOOPADDRSCOARSEOFFSET) * 32768; + startloopAddrsOffset -= startAddrsOffset; + endloopAddrsOffset -= startAddrsOffset; + + SF2Sample sample = layerzone.getSample(); + int rootkey = sample.originalPitch; + if (layerzone.getShort(SF2Region.GENERATOR_OVERRIDINGROOTKEY) != -1) { + rootkey = layerzone.getShort( + SF2Region.GENERATOR_OVERRIDINGROOTKEY); + } + float pitchcorrection = (-rootkey * 100) + sample.pitchCorrection; + ModelByteBuffer buff = sample.getDataBuffer(); + ModelByteBuffer buff24 = sample.getData24Buffer(); + + if (startAddrsOffset != 0 || endAddrsOffset != 0) { + buff = buff.subbuffer(startAddrsOffset * 2, + buff.capacity() + endAddrsOffset * 2); + if (buff24 != null) { + buff24 = buff24.subbuffer(startAddrsOffset, + buff24.capacity() + endAddrsOffset); + } + + /* + if (startAddrsOffset < 0) + startAddrsOffset = 0; + if (endAddrsOffset > (buff.capacity()/2-startAddrsOffset)) + startAddrsOffset = (int)buff.capacity()/2-startAddrsOffset; + byte[] data = buff.array(); + int off = (int)buff.arrayOffset() + startAddrsOffset*2; + int len = (int)buff.capacity() + endAddrsOffset*2; + if (off+len > data.length) + len = data.length - off; + buff = new ModelByteBuffer(data, off, len); + if(buff24 != null) { + data = buff.array(); + off = (int)buff.arrayOffset() + startAddrsOffset; + len = (int)buff.capacity() + endAddrsOffset; + buff24 = new ModelByteBuffer(data, off, len); + } + */ + } + + ModelByteBufferWavetable osc = new ModelByteBufferWavetable( + buff, sample.getFormat(), pitchcorrection); + if (buff24 != null) + osc.set8BitExtensionBuffer(buff24); + + Map generators = new HashMap(); + if (layerglobal != null) + generators.putAll(layerglobal.getGenerators()); + generators.putAll(layerzone.getGenerators()); + for (Map.Entry gen : pgenerators.entrySet()) { + short val; + if (!generators.containsKey(gen.getKey())) + val = layerzone.getShort(gen.getKey()); + else + val = generators.get(gen.getKey()); + val += gen.getValue(); + generators.put(gen.getKey(), val); + } + + // SampleMode: + // 0 indicates a sound reproduced with no loop + // 1 indicates a sound which loops continuously + // 2 is unused but should be interpreted as indicating no loop + // 3 indicates a sound which loops for the duration of key + // depression then proceeds to play the remainder of the sample. + int sampleMode = getGeneratorValue(generators, + SF2Region.GENERATOR_SAMPLEMODES); + if ((sampleMode == 1) || (sampleMode == 3)) { + if (sample.startLoop >= 0 && sample.endLoop > 0) { + osc.setLoopStart((int)(sample.startLoop + + startloopAddrsOffset)); + osc.setLoopLength((int)(sample.endLoop - sample.startLoop + + endloopAddrsOffset - startloopAddrsOffset)); + if (sampleMode == 1) + osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD); + if (sampleMode == 3) + osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE); + } + } + performer.getOscillators().add(osc); + + + short volDelay = getGeneratorValue(generators, + SF2Region.GENERATOR_DELAYVOLENV); + short volAttack = getGeneratorValue(generators, + SF2Region.GENERATOR_ATTACKVOLENV); + short volHold = getGeneratorValue(generators, + SF2Region.GENERATOR_HOLDVOLENV); + short volDecay = getGeneratorValue(generators, + SF2Region.GENERATOR_DECAYVOLENV); + short volSustain = getGeneratorValue(generators, + SF2Region.GENERATOR_SUSTAINVOLENV); + short volRelease = getGeneratorValue(generators, + SF2Region.GENERATOR_RELEASEVOLENV); + + if (volHold != -12000) { + short volKeyNumToHold = getGeneratorValue(generators, + SF2Region.GENERATOR_KEYNUMTOVOLENVHOLD); + volHold += 60 * volKeyNumToHold; + float fvalue = -volKeyNumToHold * 128; + ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER; + ModelIdentifier dest = ModelDestination.DESTINATION_EG1_HOLD; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), fvalue, + new ModelDestination(dest))); + } + if (volDecay != -12000) { + short volKeyNumToDecay = getGeneratorValue(generators, + SF2Region.GENERATOR_KEYNUMTOVOLENVDECAY); + volDecay += 60 * volKeyNumToDecay; + float fvalue = -volKeyNumToDecay * 128; + ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER; + ModelIdentifier dest = ModelDestination.DESTINATION_EG1_DECAY; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), fvalue, + new ModelDestination(dest))); + } + + addTimecentValue(performer, + ModelDestination.DESTINATION_EG1_DELAY, volDelay); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG1_ATTACK, volAttack); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG1_HOLD, volHold); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG1_DECAY, volDecay); + //float fvolsustain = (960-volSustain)*(1000.0f/960.0f); + + volSustain = (short)(1000 - volSustain); + if (volSustain < 0) + volSustain = 0; + if (volSustain > 1000) + volSustain = 1000; + + addValue(performer, + ModelDestination.DESTINATION_EG1_SUSTAIN, volSustain); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG1_RELEASE, volRelease); + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOFILTERFC) != 0 + || getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOPITCH) != 0) { + short modDelay = getGeneratorValue(generators, + SF2Region.GENERATOR_DELAYMODENV); + short modAttack = getGeneratorValue(generators, + SF2Region.GENERATOR_ATTACKMODENV); + short modHold = getGeneratorValue(generators, + SF2Region.GENERATOR_HOLDMODENV); + short modDecay = getGeneratorValue(generators, + SF2Region.GENERATOR_DECAYMODENV); + short modSustain = getGeneratorValue(generators, + SF2Region.GENERATOR_SUSTAINMODENV); + short modRelease = getGeneratorValue(generators, + SF2Region.GENERATOR_RELEASEMODENV); + + + if (modHold != -12000) { + short modKeyNumToHold = getGeneratorValue(generators, + SF2Region.GENERATOR_KEYNUMTOMODENVHOLD); + modHold += 60 * modKeyNumToHold; + float fvalue = -modKeyNumToHold * 128; + ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER; + ModelIdentifier dest = ModelDestination.DESTINATION_EG2_HOLD; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), + fvalue, new ModelDestination(dest))); + } + if (modDecay != -12000) { + short modKeyNumToDecay = getGeneratorValue(generators, + SF2Region.GENERATOR_KEYNUMTOMODENVDECAY); + modDecay += 60 * modKeyNumToDecay; + float fvalue = -modKeyNumToDecay * 128; + ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER; + ModelIdentifier dest = ModelDestination.DESTINATION_EG2_DECAY; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), + fvalue, new ModelDestination(dest))); + } + + addTimecentValue(performer, + ModelDestination.DESTINATION_EG2_DELAY, modDelay); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG2_ATTACK, modAttack); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG2_HOLD, modHold); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG2_DECAY, modDecay); + if (modSustain < 0) + modSustain = 0; + if (modSustain > 1000) + modSustain = 1000; + addValue(performer, ModelDestination.DESTINATION_EG2_SUSTAIN, + 1000 - modSustain); + addTimecentValue(performer, + ModelDestination.DESTINATION_EG2_RELEASE, modRelease); + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOFILTERFC) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOFILTERFC); + ModelIdentifier src = ModelSource.SOURCE_EG2; + ModelIdentifier dest + = ModelDestination.DESTINATION_FILTER_FREQ; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), + fvalue, new ModelDestination(dest))); + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOPITCH) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_MODENVTOPITCH); + ModelIdentifier src = ModelSource.SOURCE_EG2; + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), + fvalue, new ModelDestination(dest))); + } + + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0 + || getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOPITCH) != 0 + || getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) { + short lfo_freq = getGeneratorValue(generators, + SF2Region.GENERATOR_FREQMODLFO); + short lfo_delay = getGeneratorValue(generators, + SF2Region.GENERATOR_DELAYMODLFO); + addTimecentValue(performer, + ModelDestination.DESTINATION_LFO1_DELAY, lfo_delay); + addValue(performer, + ModelDestination.DESTINATION_LFO1_FREQ, lfo_freq); + } + + short vib_freq = getGeneratorValue(generators, + SF2Region.GENERATOR_FREQVIBLFO); + short vib_delay = getGeneratorValue(generators, + SF2Region.GENERATOR_DELAYVIBLFO); + addTimecentValue(performer, + ModelDestination.DESTINATION_LFO2_DELAY, vib_delay); + addValue(performer, + ModelDestination.DESTINATION_LFO2_FREQ, vib_freq); + + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_VIBLFOTOPITCH) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_VIBLFOTOPITCH); + ModelIdentifier src = ModelSource.SOURCE_LFO2; + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(src, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR), + fvalue, new ModelDestination(dest))); + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOFILTERFC); + ModelIdentifier src = ModelSource.SOURCE_LFO1; + ModelIdentifier dest = ModelDestination.DESTINATION_FILTER_FREQ; + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(src, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR), + fvalue, new ModelDestination(dest))); + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOPITCH) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOPITCH); + ModelIdentifier src = ModelSource.SOURCE_LFO1; + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(src, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR), + fvalue, new ModelDestination(dest))); + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) { + double fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_MODLFOTOVOLUME); + ModelIdentifier src = ModelSource.SOURCE_LFO1; + ModelIdentifier dest = ModelDestination.DESTINATION_GAIN; + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(src, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR), + fvalue, new ModelDestination(dest))); + } + + if (layerzone.getShort(SF2Region.GENERATOR_KEYNUM) != -1) { + double val = layerzone.getShort(SF2Region.GENERATOR_KEYNUM)/128.0; + addValue(performer, ModelDestination.DESTINATION_KEYNUMBER, val); + } + + if (layerzone.getShort(SF2Region.GENERATOR_VELOCITY) != -1) { + double val = layerzone.getShort(SF2Region.GENERATOR_VELOCITY) + / 128.0; + addValue(performer, ModelDestination.DESTINATION_VELOCITY, val); + } + + if (getGeneratorValue(generators, + SF2Region.GENERATOR_INITIALFILTERFC) < 13500) { + short filter_freq = getGeneratorValue(generators, + SF2Region.GENERATOR_INITIALFILTERFC); + short filter_q = getGeneratorValue(generators, + SF2Region.GENERATOR_INITIALFILTERQ); + addValue(performer, + ModelDestination.DESTINATION_FILTER_FREQ, filter_freq); + addValue(performer, + ModelDestination.DESTINATION_FILTER_Q, filter_q); + } + + int tune = 100 * getGeneratorValue(generators, + SF2Region.GENERATOR_COARSETUNE); + tune += getGeneratorValue(generators, + SF2Region.GENERATOR_FINETUNE); + if (tune != 0) { + addValue(performer, + ModelDestination.DESTINATION_PITCH, (short) tune); + } + if (getGeneratorValue(generators, SF2Region.GENERATOR_PAN) != 0) { + short val = getGeneratorValue(generators, + SF2Region.GENERATOR_PAN); + addValue(performer, ModelDestination.DESTINATION_PAN, val); + } + if (getGeneratorValue(generators, SF2Region.GENERATOR_INITIALATTENUATION) != 0) { + short val = getGeneratorValue(generators, + SF2Region.GENERATOR_INITIALATTENUATION); + addValue(performer, + ModelDestination.DESTINATION_GAIN, -0.376287f * val); + } + if (getGeneratorValue(generators, + SF2Region.GENERATOR_CHORUSEFFECTSSEND) != 0) { + short val = getGeneratorValue(generators, + SF2Region.GENERATOR_CHORUSEFFECTSSEND); + addValue(performer, ModelDestination.DESTINATION_CHORUS, val); + } + if (getGeneratorValue(generators, + SF2Region.GENERATOR_REVERBEFFECTSSEND) != 0) { + short val = getGeneratorValue(generators, + SF2Region.GENERATOR_REVERBEFFECTSSEND); + addValue(performer, ModelDestination.DESTINATION_REVERB, val); + } + if (getGeneratorValue(generators, + SF2Region.GENERATOR_SCALETUNING) != 100) { + short fvalue = getGeneratorValue(generators, + SF2Region.GENERATOR_SCALETUNING); + if (fvalue == 0) { + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(null, rootkey * 100, + new ModelDestination(dest))); + } else { + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(null, rootkey * (100 - fvalue), + new ModelDestination(dest))); + } + + ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER; + ModelIdentifier dest = ModelDestination.DESTINATION_PITCH; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(new ModelSource(src), + 128 * fvalue, new ModelDestination(dest))); + + } + + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY, + new ModelTransform() { + public double transform(double value) { + if (value < 0.5) + return 1 - value * 2; + else + return 0; + } + }), + -2400, + new ModelDestination( + ModelDestination.DESTINATION_FILTER_FREQ))); + + + performer.getConnectionBlocks().add( + new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_LFO2, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(new ModelIdentifier("midi_cc", "1", 0), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 50, new ModelDestination( + ModelDestination.DESTINATION_PITCH))); + + if (layer.getGlobalRegion() != null) { + for (SF2Modulator modulator + : layer.getGlobalRegion().getModulators()) { + convertModulator(performer, modulator); + } + } + for (SF2Modulator modulator : layerzone.getModulators()) + convertModulator(performer, modulator); + + if (presetglobal != null) { + for (SF2Modulator modulator : presetglobal.getModulators()) + convertModulator(performer, modulator); + } + for (SF2Modulator modulator : presetzone.getModulators()) + convertModulator(performer, modulator); + + } + } + return performers; + } + + private void convertModulator(ModelPerformer performer, + SF2Modulator modulator) { + ModelSource src1 = convertSource(modulator.getSourceOperator()); + ModelSource src2 = convertSource(modulator.getAmountSourceOperator()); + if (src1 == null && modulator.getSourceOperator() != 0) + return; + if (src2 == null && modulator.getAmountSourceOperator() != 0) + return; + double amount = modulator.getAmount(); + double[] amountcorrection = new double[1]; + ModelSource[] extrasrc = new ModelSource[1]; + amountcorrection[0] = 1; + ModelDestination dst = convertDestination( + modulator.getDestinationOperator(), amountcorrection, extrasrc); + amount *= amountcorrection[0]; + if (dst == null) + return; + if (modulator.getTransportOperator() == SF2Modulator.TRANSFORM_ABSOLUTE) { + ((ModelStandardTransform)dst.getTransform()).setTransform( + ModelStandardTransform.TRANSFORM_ABSOLUTE); + } + ModelConnectionBlock conn = new ModelConnectionBlock(src1, src2, amount, dst); + if (extrasrc[0] != null) + conn.addSource(extrasrc[0]); + performer.getConnectionBlocks().add(conn); + + } + + private static ModelSource convertSource(int src) { + if (src == 0) + return null; + ModelIdentifier id = null; + int idsrc = src & 0x7F; + if ((src & SF2Modulator.SOURCE_MIDI_CONTROL) != 0) { + id = new ModelIdentifier("midi_cc", Integer.toString(idsrc)); + } else { + if (idsrc == SF2Modulator.SOURCE_NOTE_ON_VELOCITY) + id = ModelSource.SOURCE_NOTEON_VELOCITY; + if (idsrc == SF2Modulator.SOURCE_NOTE_ON_KEYNUMBER) + id = ModelSource.SOURCE_NOTEON_KEYNUMBER; + if (idsrc == SF2Modulator.SOURCE_POLY_PRESSURE) + id = ModelSource.SOURCE_MIDI_POLY_PRESSURE; + if (idsrc == SF2Modulator.SOURCE_CHANNEL_PRESSURE) + id = ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE; + if (idsrc == SF2Modulator.SOURCE_PITCH_WHEEL) + id = ModelSource.SOURCE_MIDI_PITCH; + if (idsrc == SF2Modulator.SOURCE_PITCH_SENSITIVITY) + id = new ModelIdentifier("midi_rpn", "0"); + } + if (id == null) + return null; + + ModelSource msrc = new ModelSource(id); + ModelStandardTransform transform + = (ModelStandardTransform) msrc.getTransform(); + + if ((SF2Modulator.SOURCE_DIRECTION_MAX_MIN & src) != 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + + if ((SF2Modulator.SOURCE_POLARITY_BIPOLAR & src) != 0) + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + + if ((SF2Modulator.SOURCE_TYPE_CONCAVE & src) != 0) + transform.setTransform(ModelStandardTransform.TRANSFORM_CONCAVE); + if ((SF2Modulator.SOURCE_TYPE_CONVEX & src) != 0) + transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX); + if ((SF2Modulator.SOURCE_TYPE_SWITCH & src) != 0) + transform.setTransform(ModelStandardTransform.TRANSFORM_SWITCH); + + return msrc; + } + + protected static ModelDestination convertDestination(int dst, + double[] amountcorrection, ModelSource[] extrasrc) { + ModelIdentifier id = null; + switch (dst) { + case SF2Region.GENERATOR_INITIALFILTERFC: + id = ModelDestination.DESTINATION_FILTER_FREQ; + break; + case SF2Region.GENERATOR_INITIALFILTERQ: + id = ModelDestination.DESTINATION_FILTER_Q; + break; + case SF2Region.GENERATOR_CHORUSEFFECTSSEND: + id = ModelDestination.DESTINATION_CHORUS; + break; + case SF2Region.GENERATOR_REVERBEFFECTSSEND: + id = ModelDestination.DESTINATION_REVERB; + break; + case SF2Region.GENERATOR_PAN: + id = ModelDestination.DESTINATION_PAN; + break; + case SF2Region.GENERATOR_DELAYMODLFO: + id = ModelDestination.DESTINATION_LFO1_DELAY; + break; + case SF2Region.GENERATOR_FREQMODLFO: + id = ModelDestination.DESTINATION_LFO1_FREQ; + break; + case SF2Region.GENERATOR_DELAYVIBLFO: + id = ModelDestination.DESTINATION_LFO2_DELAY; + break; + case SF2Region.GENERATOR_FREQVIBLFO: + id = ModelDestination.DESTINATION_LFO2_FREQ; + break; + + case SF2Region.GENERATOR_DELAYMODENV: + id = ModelDestination.DESTINATION_EG2_DELAY; + break; + case SF2Region.GENERATOR_ATTACKMODENV: + id = ModelDestination.DESTINATION_EG2_ATTACK; + break; + case SF2Region.GENERATOR_HOLDMODENV: + id = ModelDestination.DESTINATION_EG2_HOLD; + break; + case SF2Region.GENERATOR_DECAYMODENV: + id = ModelDestination.DESTINATION_EG2_DECAY; + break; + case SF2Region.GENERATOR_SUSTAINMODENV: + id = ModelDestination.DESTINATION_EG2_SUSTAIN; + amountcorrection[0] = -1; + break; + case SF2Region.GENERATOR_RELEASEMODENV: + id = ModelDestination.DESTINATION_EG2_RELEASE; + break; + case SF2Region.GENERATOR_DELAYVOLENV: + id = ModelDestination.DESTINATION_EG1_DELAY; + break; + case SF2Region.GENERATOR_ATTACKVOLENV: + id = ModelDestination.DESTINATION_EG1_ATTACK; + break; + case SF2Region.GENERATOR_HOLDVOLENV: + id = ModelDestination.DESTINATION_EG1_HOLD; + break; + case SF2Region.GENERATOR_DECAYVOLENV: + id = ModelDestination.DESTINATION_EG1_DECAY; + break; + case SF2Region.GENERATOR_SUSTAINVOLENV: + id = ModelDestination.DESTINATION_EG1_SUSTAIN; + amountcorrection[0] = -1; + break; + case SF2Region.GENERATOR_RELEASEVOLENV: + id = ModelDestination.DESTINATION_EG1_RELEASE; + break; + case SF2Region.GENERATOR_KEYNUM: + id = ModelDestination.DESTINATION_KEYNUMBER; + break; + case SF2Region.GENERATOR_VELOCITY: + id = ModelDestination.DESTINATION_VELOCITY; + break; + + case SF2Region.GENERATOR_COARSETUNE: + amountcorrection[0] = 100; + id = ModelDestination.DESTINATION_PITCH; + break; + + case SF2Region.GENERATOR_FINETUNE: + id = ModelDestination.DESTINATION_PITCH; + break; + + case SF2Region.GENERATOR_INITIALATTENUATION: + id = ModelDestination.DESTINATION_GAIN; + amountcorrection[0] = -0.376287f; + break; + + case SF2Region.GENERATOR_VIBLFOTOPITCH: + id = ModelDestination.DESTINATION_PITCH; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_LFO2, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + case SF2Region.GENERATOR_MODLFOTOPITCH: + id = ModelDestination.DESTINATION_PITCH; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + case SF2Region.GENERATOR_MODLFOTOFILTERFC: + id = ModelDestination.DESTINATION_FILTER_FREQ; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + case SF2Region.GENERATOR_MODLFOTOVOLUME: + id = ModelDestination.DESTINATION_GAIN; + amountcorrection[0] = -0.376287f; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + case SF2Region.GENERATOR_MODENVTOPITCH: + id = ModelDestination.DESTINATION_PITCH; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_EG2, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + case SF2Region.GENERATOR_MODENVTOFILTERFC: + id = ModelDestination.DESTINATION_FILTER_FREQ; + extrasrc[0] = new ModelSource( + ModelSource.SOURCE_EG2, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR); + break; + + default: + break; + } + if (id != null) + return new ModelDestination(id); + return null; + } + + private void addTimecentValue(ModelPerformer performer, + ModelIdentifier dest, short value) { + double fvalue; + if (value == -12000) + fvalue = Double.NEGATIVE_INFINITY; + else + fvalue = value; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(fvalue, new ModelDestination(dest))); + } + + private void addValue(ModelPerformer performer, + ModelIdentifier dest, short value) { + double fvalue = value; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(fvalue, new ModelDestination(dest))); + } + + private void addValue(ModelPerformer performer, + ModelIdentifier dest, double value) { + double fvalue = value; + performer.getConnectionBlocks().add( + new ModelConnectionBlock(fvalue, new ModelDestination(dest))); + } + + private short getGeneratorValue(Map generators, int gen) { + if (generators.containsKey(gen)) + return generators.get(gen); + return SF2Region.getDefaultValue(gen); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2InstrumentRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2InstrumentRegion.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Soundfont instrument region. + * + * @author Karl Helgason + */ +public class SF2InstrumentRegion extends SF2Region { + + protected SF2Layer layer; + + public SF2Layer getLayer() { + return layer; + } + + public void setLayer(SF2Layer layer) { + this.layer = layer; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Layer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Layer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.List; + +import javax.sound.midi.SoundbankResource; + +/** + * Soundfont layer. + * + * @author Karl Helgason + */ +public class SF2Layer extends SoundbankResource { + + protected String name = ""; + protected SF2GlobalRegion globalregion = null; + protected List regions = new ArrayList(); + + public SF2Layer(SF2Soundbank soundBank) { + super(soundBank, null, null); + } + + public SF2Layer() { + super(null, null, null); + } + + public Object getData() { + return null; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getRegions() { + return regions; + } + + public SF2GlobalRegion getGlobalRegion() { + return globalregion; + } + + public void setGlobalZone(SF2GlobalRegion zone) { + globalregion = zone; + } + + public String toString() { + return "Layer: " + name; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2LayerRegion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2LayerRegion.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Soundfont layer region. + * + * @author Karl Helgason + */ +public class SF2LayerRegion extends SF2Region { + + protected SF2Sample sample; + + public SF2Sample getSample() { + return sample; + } + + public void setSample(SF2Sample sample) { + this.sample = sample; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Modulator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Modulator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Soundfont modulator container. + * + * @author Karl Helgason + */ +public class SF2Modulator { + + public final static int SOURCE_NONE = 0; + public final static int SOURCE_NOTE_ON_VELOCITY = 2; + public final static int SOURCE_NOTE_ON_KEYNUMBER = 3; + public final static int SOURCE_POLY_PRESSURE = 10; + public final static int SOURCE_CHANNEL_PRESSURE = 13; + public final static int SOURCE_PITCH_WHEEL = 14; + public final static int SOURCE_PITCH_SENSITIVITY = 16; + public final static int SOURCE_MIDI_CONTROL = 128 * 1; + public final static int SOURCE_DIRECTION_MIN_MAX = 256 * 0; + public final static int SOURCE_DIRECTION_MAX_MIN = 256 * 1; + public final static int SOURCE_POLARITY_UNIPOLAR = 512 * 0; + public final static int SOURCE_POLARITY_BIPOLAR = 512 * 1; + public final static int SOURCE_TYPE_LINEAR = 1024 * 0; + public final static int SOURCE_TYPE_CONCAVE = 1024 * 1; + public final static int SOURCE_TYPE_CONVEX = 1024 * 2; + public final static int SOURCE_TYPE_SWITCH = 1024 * 3; + public final static int TRANSFORM_LINEAR = 0; + public final static int TRANSFORM_ABSOLUTE = 2; + protected int sourceOperator; + protected int destinationOperator; + protected short amount; + protected int amountSourceOperator; + protected int transportOperator; + + public short getAmount() { + return amount; + } + + public void setAmount(short amount) { + this.amount = amount; + } + + public int getAmountSourceOperator() { + return amountSourceOperator; + } + + public void setAmountSourceOperator(int amountSourceOperator) { + this.amountSourceOperator = amountSourceOperator; + } + + public int getTransportOperator() { + return transportOperator; + } + + public void setTransportOperator(int transportOperator) { + this.transportOperator = transportOperator; + } + + public int getDestinationOperator() { + return destinationOperator; + } + + public void setDestinationOperator(int destinationOperator) { + this.destinationOperator = destinationOperator; + } + + public int getSourceOperator() { + return sourceOperator; + } + + public void setSourceOperator(int sourceOperator) { + this.sourceOperator = sourceOperator; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Region.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Region.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,167 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Soundfont general region. + * + * @author Karl Helgason + */ +public class SF2Region { + + public final static int GENERATOR_STARTADDRSOFFSET = 0; + public final static int GENERATOR_ENDADDRSOFFSET = 1; + public final static int GENERATOR_STARTLOOPADDRSOFFSET = 2; + public final static int GENERATOR_ENDLOOPADDRSOFFSET = 3; + public final static int GENERATOR_STARTADDRSCOARSEOFFSET = 4; + public final static int GENERATOR_MODLFOTOPITCH = 5; + public final static int GENERATOR_VIBLFOTOPITCH = 6; + public final static int GENERATOR_MODENVTOPITCH = 7; + public final static int GENERATOR_INITIALFILTERFC = 8; + public final static int GENERATOR_INITIALFILTERQ = 9; + public final static int GENERATOR_MODLFOTOFILTERFC = 10; + public final static int GENERATOR_MODENVTOFILTERFC = 11; + public final static int GENERATOR_ENDADDRSCOARSEOFFSET = 12; + public final static int GENERATOR_MODLFOTOVOLUME = 13; + public final static int GENERATOR_UNUSED1 = 14; + public final static int GENERATOR_CHORUSEFFECTSSEND = 15; + public final static int GENERATOR_REVERBEFFECTSSEND = 16; + public final static int GENERATOR_PAN = 17; + public final static int GENERATOR_UNUSED2 = 18; + public final static int GENERATOR_UNUSED3 = 19; + public final static int GENERATOR_UNUSED4 = 20; + public final static int GENERATOR_DELAYMODLFO = 21; + public final static int GENERATOR_FREQMODLFO = 22; + public final static int GENERATOR_DELAYVIBLFO = 23; + public final static int GENERATOR_FREQVIBLFO = 24; + public final static int GENERATOR_DELAYMODENV = 25; + public final static int GENERATOR_ATTACKMODENV = 26; + public final static int GENERATOR_HOLDMODENV = 27; + public final static int GENERATOR_DECAYMODENV = 28; + public final static int GENERATOR_SUSTAINMODENV = 29; + public final static int GENERATOR_RELEASEMODENV = 30; + public final static int GENERATOR_KEYNUMTOMODENVHOLD = 31; + public final static int GENERATOR_KEYNUMTOMODENVDECAY = 32; + public final static int GENERATOR_DELAYVOLENV = 33; + public final static int GENERATOR_ATTACKVOLENV = 34; + public final static int GENERATOR_HOLDVOLENV = 35; + public final static int GENERATOR_DECAYVOLENV = 36; + public final static int GENERATOR_SUSTAINVOLENV = 37; + public final static int GENERATOR_RELEASEVOLENV = 38; + public final static int GENERATOR_KEYNUMTOVOLENVHOLD = 39; + public final static int GENERATOR_KEYNUMTOVOLENVDECAY = 40; + public final static int GENERATOR_INSTRUMENT = 41; + public final static int GENERATOR_RESERVED1 = 42; + public final static int GENERATOR_KEYRANGE = 43; + public final static int GENERATOR_VELRANGE = 44; + public final static int GENERATOR_STARTLOOPADDRSCOARSEOFFSET = 45; + public final static int GENERATOR_KEYNUM = 46; + public final static int GENERATOR_VELOCITY = 47; + public final static int GENERATOR_INITIALATTENUATION = 48; + public final static int GENERATOR_RESERVED2 = 49; + public final static int GENERATOR_ENDLOOPADDRSCOARSEOFFSET = 50; + public final static int GENERATOR_COARSETUNE = 51; + public final static int GENERATOR_FINETUNE = 52; + public final static int GENERATOR_SAMPLEID = 53; + public final static int GENERATOR_SAMPLEMODES = 54; + public final static int GENERATOR_RESERVED3 = 55; + public final static int GENERATOR_SCALETUNING = 56; + public final static int GENERATOR_EXCLUSIVECLASS = 57; + public final static int GENERATOR_OVERRIDINGROOTKEY = 58; + public final static int GENERATOR_UNUSED5 = 59; + public final static int GENERATOR_ENDOPR = 60; + protected Map generators = new HashMap(); + protected List modulators = new ArrayList(); + + public Map getGenerators() { + return generators; + } + + public boolean contains(int generator) { + return generators.containsKey(generator); + } + + static public short getDefaultValue(int generator) { + if (generator == 8) return (short)13500; + if (generator == 21) return (short)-12000; + if (generator == 23) return (short)-12000; + if (generator == 25) return (short)-12000; + if (generator == 26) return (short)-12000; + if (generator == 27) return (short)-12000; + if (generator == 28) return (short)-12000; + if (generator == 30) return (short)-12000; + if (generator == 33) return (short)-12000; + if (generator == 34) return (short)-12000; + if (generator == 35) return (short)-12000; + if (generator == 36) return (short)-12000; + if (generator == 38) return (short)-12000; + if (generator == 43) return (short)0x7F00; + if (generator == 44) return (short)0x7F00; + if (generator == 46) return (short)-1; + if (generator == 47) return (short)-1; + if (generator == 56) return (short)100; + if (generator == 58) return (short)-1; + return 0; + } + + public short getShort(int generator) { + if (!contains(generator)) + return getDefaultValue(generator); + return generators.get(generator); + } + + public void putShort(int generator, short value) { + generators.put(generator, value); + } + + public byte[] getBytes(int generator) { + int val = getInteger(generator); + byte[] bytes = new byte[2]; + bytes[0] = (byte) (0xFF & val); + bytes[1] = (byte) ((0xFF00 & val) >> 8); + return bytes; + } + + public void putBytes(int generator, byte[] bytes) { + generators.put(generator, (short) (bytes[0] + (bytes[1] << 8))); + } + + public int getInteger(int generator) { + return 0xFFFF & getShort(generator); + } + + public void putInteger(int generator, int value) { + generators.put(generator, (short) value); + } + + public List getModulators() { + return modulators; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Sample.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Sample.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,216 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.InputStream; + +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +/** + * Soundfont sample storage. + * + * @author Karl Helgason + */ +public class SF2Sample extends SoundbankResource { + + protected String name = ""; + protected long startLoop = 0; + protected long endLoop = 0; + protected long sampleRate = 44100; + protected int originalPitch = 60; + protected byte pitchCorrection = 0; + protected int sampleLink = 0; + protected int sampleType = 0; + protected ModelByteBuffer data; + protected ModelByteBuffer data24; + + public SF2Sample(Soundbank soundBank) { + super(soundBank, null, AudioInputStream.class); + } + + public SF2Sample() { + super(null, null, AudioInputStream.class); + } + + public Object getData() { + + AudioFormat format = getFormat(); + /* + if (sampleFile != null) { + FileInputStream fis; + try { + fis = new FileInputStream(sampleFile); + RIFFReader riff = new RIFFReader(fis); + if (!riff.getFormat().equals("RIFF")) { + throw new RIFFInvalidDataException( + "Input stream is not a valid RIFF stream!"); + } + if (!riff.getType().equals("sfbk")) { + throw new RIFFInvalidDataException( + "Input stream is not a valid SoundFont!"); + } + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("LIST")) { + if (chunk.getType().equals("sdta")) { + while(chunk.hasNextChunk()) { + RIFFReader chunkchunk = chunk.nextChunk(); + if(chunkchunk.getFormat().equals("smpl")) { + chunkchunk.skip(sampleOffset); + return new AudioInputStream(chunkchunk, + format, sampleLen); + } + } + } + } + } + return null; + } catch (Exception e) { + return new Throwable(e.toString()); + } + } + */ + InputStream is = data.getInputStream(); + if (is == null) + return null; + return new AudioInputStream(is, format, data.capacity()); + } + + public ModelByteBuffer getDataBuffer() { + return data; + } + + public ModelByteBuffer getData24Buffer() { + return data24; + } + + public AudioFormat getFormat() { + return new AudioFormat(sampleRate, 16, 1, true, false); + } + + public void setData(ModelByteBuffer data) { + this.data = data; + } + + public void setData(byte[] data) { + this.data = new ModelByteBuffer(data); + } + + public void setData(byte[] data, int offset, int length) { + this.data = new ModelByteBuffer(data, offset, length); + } + + public void setData24(ModelByteBuffer data24) { + this.data24 = data24; + } + + public void setData24(byte[] data24) { + this.data24 = new ModelByteBuffer(data24); + } + + public void setData24(byte[] data24, int offset, int length) { + this.data24 = new ModelByteBuffer(data24, offset, length); + } + + /* + public void setData(File file, int offset, int length) { + this.data = null; + this.sampleFile = file; + this.sampleOffset = offset; + this.sampleLen = length; + } + */ + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getEndLoop() { + return endLoop; + } + + public void setEndLoop(long endLoop) { + this.endLoop = endLoop; + } + + public int getOriginalPitch() { + return originalPitch; + } + + public void setOriginalPitch(int originalPitch) { + this.originalPitch = originalPitch; + } + + public byte getPitchCorrection() { + return pitchCorrection; + } + + public void setPitchCorrection(byte pitchCorrection) { + this.pitchCorrection = pitchCorrection; + } + + public int getSampleLink() { + return sampleLink; + } + + public void setSampleLink(int sampleLink) { + this.sampleLink = sampleLink; + } + + public long getSampleRate() { + return sampleRate; + } + + public void setSampleRate(long sampleRate) { + this.sampleRate = sampleRate; + } + + public int getSampleType() { + return sampleType; + } + + public void setSampleType(int sampleType) { + this.sampleType = sampleType; + } + + public long getStartLoop() { + return startLoop; + } + + public void setStartLoop(long startLoop) { + this.startLoop = startLoop; + } + + public String toString() { + return "Sample: " + name; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2Soundbank.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,973 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.sound.midi.Instrument; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; + +/** + * A SoundFont 2.04 soundbank reader. + * + * Based on SoundFont 2.04 specification from: + *

    http://developer.creative.com
    + * http://www.soundfont.com/ ; + * + * @author Karl Helgason + */ +public class SF2Soundbank implements Soundbank { + + // version of the Sound Font RIFF file + protected int major = 2; + protected int minor = 1; + // target Sound Engine + protected String targetEngine = "EMU8000"; + // Sound Font Bank Name + protected String name = "untitled"; + // Sound ROM Name + protected String romName = null; + // Sound ROM Version + protected int romVersionMajor = -1; + protected int romVersionMinor = -1; + // Date of Creation of the Bank + protected String creationDate = null; + // Sound Designers and Engineers for the Bank + protected String engineers = null; + // Product for which the Bank was intended + protected String product = null; + // Copyright message + protected String copyright = null; + // Comments + protected String comments = null; + // The SoundFont tools used to create and alter the bank + protected String tools = null; + // The Sample Data loaded from the SoundFont + private ModelByteBuffer sampleData = null; + private ModelByteBuffer sampleData24 = null; + private File sampleFile = null; + private boolean largeFormat = false; + private List instruments = new ArrayList(); + private List layers = new ArrayList(); + private List samples = new ArrayList(); + + public SF2Soundbank() { + } + + public SF2Soundbank(URL url) throws IOException { + + InputStream is = url.openStream(); + try { + readSoundbank(is); + } finally { + is.close(); + } + } + + public SF2Soundbank(File file) throws IOException { + largeFormat = true; + sampleFile = file; + InputStream is = new FileInputStream(file); + try { + readSoundbank(is); + } finally { + is.close(); + } + } + + public SF2Soundbank(InputStream inputstream) throws IOException { + readSoundbank(inputstream); + } + + private void readSoundbank(InputStream inputstream) throws IOException { + RIFFReader riff = new RIFFReader(inputstream); + if (!riff.getFormat().equals("RIFF")) { + throw new RIFFInvalidFormatException( + "Input stream is not a valid RIFF stream!"); + } + if (!riff.getType().equals("sfbk")) { + throw new RIFFInvalidFormatException( + "Input stream is not a valid SoundFont!"); + } + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("LIST")) { + if (chunk.getType().equals("INFO")) + readInfoChunk(chunk); + if (chunk.getType().equals("sdta")) + readSdtaChunk(chunk); + if (chunk.getType().equals("pdta")) + readPdtaChunk(chunk); + } + } + } + + private void readInfoChunk(RIFFReader riff) throws IOException { + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("ifil")) { + major = chunk.readUnsignedShort(); + minor = chunk.readUnsignedShort(); + } else if (format.equals("isng")) { + this.targetEngine = chunk.readString(chunk.available()); + } else if (format.equals("INAM")) { + this.name = chunk.readString(chunk.available()); + } else if (format.equals("irom")) { + this.romName = chunk.readString(chunk.available()); + } else if (format.equals("iver")) { + romVersionMajor = chunk.readUnsignedShort(); + romVersionMinor = chunk.readUnsignedShort(); + } else if (format.equals("ICRD")) { + this.creationDate = chunk.readString(chunk.available()); + } else if (format.equals("IENG")) { + this.engineers = chunk.readString(chunk.available()); + } else if (format.equals("IPRD")) { + this.product = chunk.readString(chunk.available()); + } else if (format.equals("ICOP")) { + this.copyright = chunk.readString(chunk.available()); + } else if (format.equals("ICMT")) { + this.comments = chunk.readString(chunk.available()); + } else if (format.equals("ISFT")) { + this.tools = chunk.readString(chunk.available()); + } + + } + } + + private void readSdtaChunk(RIFFReader riff) throws IOException { + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + if (chunk.getFormat().equals("smpl")) { + if (!largeFormat) { + byte[] sampleData = new byte[chunk.available()]; + + int read = 0; + int avail = chunk.available(); + while (read != avail) { + if (avail - read > 65536) { + chunk.read(sampleData, read, 65536); + read += 65536; + } else { + chunk.read(sampleData, read, avail - read); + read = avail; + } + + } + this.sampleData = new ModelByteBuffer(sampleData); + //chunk.read(sampleData); + } else { + this.sampleData = new ModelByteBuffer(sampleFile, + chunk.getFilePointer(), chunk.available()); + } + } + if (chunk.getFormat().equals("sm24")) { + if (!largeFormat) { + byte[] sampleData24 = new byte[chunk.available()]; + //chunk.read(sampleData24); + + int read = 0; + int avail = chunk.available(); + while (read != avail) { + if (avail - read > 65536) { + chunk.read(sampleData24, read, 65536); + read += 65536; + } else { + chunk.read(sampleData24, read, avail - read); + read = avail; + } + + } + this.sampleData24 = new ModelByteBuffer(sampleData24); + } else { + this.sampleData24 = new ModelByteBuffer(sampleFile, + chunk.getFilePointer(), chunk.available()); + } + + } + } + } + + private void readPdtaChunk(RIFFReader riff) throws IOException { + + List presets = new ArrayList(); + List presets_bagNdx = new ArrayList(); + List presets_splits_gen + = new ArrayList(); + List presets_splits_mod + = new ArrayList(); + + List instruments = new ArrayList(); + List instruments_bagNdx = new ArrayList(); + List instruments_splits_gen + = new ArrayList(); + List instruments_splits_mod + = new ArrayList(); + + while (riff.hasNextChunk()) { + RIFFReader chunk = riff.nextChunk(); + String format = chunk.getFormat(); + if (format.equals("phdr")) { + // Preset Header / Instrument + if (chunk.available() % 38 != 0) + throw new RIFFInvalidDataException(); + int count = chunk.available() / 38; + for (int i = 0; i < count; i++) { + SF2Instrument preset = new SF2Instrument(this); + preset.name = chunk.readString(20); + preset.preset = chunk.readUnsignedShort(); + preset.bank = chunk.readUnsignedShort(); + presets_bagNdx.add(chunk.readUnsignedShort()); + preset.library = chunk.readUnsignedInt(); + preset.genre = chunk.readUnsignedInt(); + preset.morphology = chunk.readUnsignedInt(); + presets.add(preset); + if (i != count - 1) + this.instruments.add(preset); + } + } else if (format.equals("pbag")) { + // Preset Zones / Instruments splits + if (chunk.available() % 4 != 0) + throw new RIFFInvalidDataException(); + int count = chunk.available() / 4; + + // Skip first record + { + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + while (presets_splits_gen.size() < gencount) + presets_splits_gen.add(null); + while (presets_splits_mod.size() < modcount) + presets_splits_mod.add(null); + count--; + } + + int offset = presets_bagNdx.get(0); + // Offset should be 0 (but just case) + for (int i = 0; i < offset; i++) { + if (count == 0) + throw new RIFFInvalidDataException(); + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + while (presets_splits_gen.size() < gencount) + presets_splits_gen.add(null); + while (presets_splits_mod.size() < modcount) + presets_splits_mod.add(null); + count--; + } + + for (int i = 0; i < presets_bagNdx.size() - 1; i++) { + int zone_count = presets_bagNdx.get(i + 1) + - presets_bagNdx.get(i); + SF2Instrument preset = presets.get(i); + for (int ii = 0; ii < zone_count; ii++) { + if (count == 0) + throw new RIFFInvalidDataException(); + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + SF2InstrumentRegion split = new SF2InstrumentRegion(); + preset.regions.add(split); + while (presets_splits_gen.size() < gencount) + presets_splits_gen.add(split); + while (presets_splits_mod.size() < modcount) + presets_splits_mod.add(split); + count--; + } + } + } else if (format.equals("pmod")) { + // Preset Modulators / Split Modulators + for (int i = 0; i < presets_splits_mod.size(); i++) { + SF2Modulator modulator = new SF2Modulator(); + modulator.sourceOperator = chunk.readUnsignedShort(); + modulator.destinationOperator = chunk.readUnsignedShort(); + modulator.amount = chunk.readShort(); + modulator.amountSourceOperator = chunk.readUnsignedShort(); + modulator.transportOperator = chunk.readUnsignedShort(); + SF2InstrumentRegion split = presets_splits_mod.get(i); + if (split != null) + split.modulators.add(modulator); + } + } else if (format.equals("pgen")) { + // Preset Generators / Split Generators + for (int i = 0; i < presets_splits_gen.size(); i++) { + int operator = chunk.readUnsignedShort(); + short amount = chunk.readShort(); + SF2InstrumentRegion split = presets_splits_gen.get(i); + if (split != null) + split.generators.put(operator, amount); + } + } else if (format.equals("inst")) { + // Instrument Header / Layers + if (chunk.available() % 22 != 0) + throw new RIFFInvalidDataException(); + int count = chunk.available() / 22; + for (int i = 0; i < count; i++) { + SF2Layer layer = new SF2Layer(this); + layer.name = chunk.readString(20); + instruments_bagNdx.add(chunk.readUnsignedShort()); + instruments.add(layer); + if (i != count - 1) + this.layers.add(layer); + } + } else if (format.equals("ibag")) { + // Instrument Zones / Layer splits + if (chunk.available() % 4 != 0) + throw new RIFFInvalidDataException(); + int count = chunk.available() / 4; + + // Skip first record + { + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + while (instruments_splits_gen.size() < gencount) + instruments_splits_gen.add(null); + while (instruments_splits_mod.size() < modcount) + instruments_splits_mod.add(null); + count--; + } + + int offset = instruments_bagNdx.get(0); + // Offset should be 0 (but just case) + for (int i = 0; i < offset; i++) { + if (count == 0) + throw new RIFFInvalidDataException(); + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + while (instruments_splits_gen.size() < gencount) + instruments_splits_gen.add(null); + while (instruments_splits_mod.size() < modcount) + instruments_splits_mod.add(null); + count--; + } + + for (int i = 0; i < instruments_bagNdx.size() - 1; i++) { + int zone_count = instruments_bagNdx.get(i + 1) - instruments_bagNdx.get(i); + SF2Layer layer = layers.get(i); + for (int ii = 0; ii < zone_count; ii++) { + if (count == 0) + throw new RIFFInvalidDataException(); + int gencount = chunk.readUnsignedShort(); + int modcount = chunk.readUnsignedShort(); + SF2LayerRegion split = new SF2LayerRegion(); + layer.regions.add(split); + while (instruments_splits_gen.size() < gencount) + instruments_splits_gen.add(split); + while (instruments_splits_mod.size() < modcount) + instruments_splits_mod.add(split); + count--; + } + } + + } else if (format.equals("imod")) { + // Instrument Modulators / Split Modulators + for (int i = 0; i < instruments_splits_mod.size(); i++) { + SF2Modulator modulator = new SF2Modulator(); + modulator.sourceOperator = chunk.readUnsignedShort(); + modulator.destinationOperator = chunk.readUnsignedShort(); + modulator.amount = chunk.readShort(); + modulator.amountSourceOperator = chunk.readUnsignedShort(); + modulator.transportOperator = chunk.readUnsignedShort(); + SF2LayerRegion split = instruments_splits_gen.get(i); + if (split != null) + split.modulators.add(modulator); + } + } else if (format.equals("igen")) { + // Instrument Generators / Split Generators + for (int i = 0; i < instruments_splits_gen.size(); i++) { + int operator = chunk.readUnsignedShort(); + short amount = chunk.readShort(); + SF2LayerRegion split = instruments_splits_gen.get(i); + if (split != null) + split.generators.put(operator, amount); + } + } else if (format.equals("shdr")) { + // Sample Headers + if (chunk.available() % 46 != 0) + throw new RIFFInvalidDataException(); + int count = chunk.available() / 46; + for (int i = 0; i < count; i++) { + SF2Sample sample = new SF2Sample(this); + sample.name = chunk.readString(20); + long start = chunk.readUnsignedInt(); + long end = chunk.readUnsignedInt(); + sample.data = sampleData.subbuffer(start * 2, end * 2, true); + if (sampleData24 != null) + sample.data24 = sampleData24.subbuffer(start, end, true); + /* + sample.data = new ModelByteBuffer(sampleData, (int)(start*2), + (int)((end - start)*2)); + if (sampleData24 != null) + sample.data24 = new ModelByteBuffer(sampleData24, + (int)start, (int)(end - start)); + */ + sample.startLoop = chunk.readUnsignedInt() - start; + sample.endLoop = chunk.readUnsignedInt() - start; + if (sample.startLoop < 0) + sample.startLoop = -1; + if (sample.endLoop < 0) + sample.endLoop = -1; + sample.sampleRate = chunk.readUnsignedInt(); + sample.originalPitch = chunk.readUnsignedByte(); + sample.pitchCorrection = chunk.readByte(); + sample.sampleLink = chunk.readUnsignedShort(); + sample.sampleType = chunk.readUnsignedShort(); + if (i != count - 1) + this.samples.add(sample); + } + } + } + + Iterator liter = this.layers.iterator(); + while (liter.hasNext()) { + SF2Layer layer = liter.next(); + Iterator siter = layer.regions.iterator(); + SF2Region globalsplit = null; + while (siter.hasNext()) { + SF2LayerRegion split = siter.next(); + if (split.generators.get(SF2LayerRegion.GENERATOR_SAMPLEID) != null) { + int sampleid = split.generators.get( + SF2LayerRegion.GENERATOR_SAMPLEID); + split.generators.remove(SF2LayerRegion.GENERATOR_SAMPLEID); + split.sample = samples.get(sampleid); + } else { + globalsplit = split; + } + } + if (globalsplit != null) { + layer.getRegions().remove(globalsplit); + SF2GlobalRegion gsplit = new SF2GlobalRegion(); + gsplit.generators = globalsplit.generators; + gsplit.modulators = globalsplit.modulators; + layer.setGlobalZone(gsplit); + } + } + + + Iterator iiter = this.instruments.iterator(); + while (iiter.hasNext()) { + SF2Instrument instrument = iiter.next(); + Iterator siter = instrument.regions.iterator(); + SF2Region globalsplit = null; + while (siter.hasNext()) { + SF2InstrumentRegion split = siter.next(); + if (split.generators.get(SF2LayerRegion.GENERATOR_INSTRUMENT) != null) { + int instrumentid = split.generators.get( + SF2InstrumentRegion.GENERATOR_INSTRUMENT); + split.generators.remove(SF2LayerRegion.GENERATOR_INSTRUMENT); + split.layer = layers.get(instrumentid); + } else { + globalsplit = split; + } + } + + if (globalsplit != null) { + instrument.getRegions().remove(globalsplit); + SF2GlobalRegion gsplit = new SF2GlobalRegion(); + gsplit.generators = globalsplit.generators; + gsplit.modulators = globalsplit.modulators; + instrument.setGlobalZone(gsplit); + } + } + + } + + public void save(String name) throws IOException { + writeSoundbank(new RIFFWriter(name, "sfbk")); + } + + public void save(File file) throws IOException { + writeSoundbank(new RIFFWriter(file, "sfbk")); + } + + public void save(OutputStream out) throws IOException { + writeSoundbank(new RIFFWriter(out, "sfbk")); + } + + private void writeSoundbank(RIFFWriter writer) throws IOException { + writeInfo(writer.writeList("INFO")); + writeSdtaChunk(writer.writeList("sdta")); + writePdtaChunk(writer.writeList("pdta")); + writer.close(); + } + + private void writeInfoStringChunk(RIFFWriter writer, String name, + String value) throws IOException { + if (value == null) + return; + RIFFWriter chunk = writer.writeChunk(name); + chunk.writeString(value); + int len = value.getBytes("ascii").length; + chunk.write(0); + len++; + if (len % 2 != 0) + chunk.write(0); + } + + private void writeInfo(RIFFWriter writer) throws IOException { + if (this.targetEngine == null) + this.targetEngine = "EMU8000"; + if (this.name == null) + this.name = ""; + + RIFFWriter ifil_chunk = writer.writeChunk("ifil"); + ifil_chunk.writeUnsignedShort(this.major); + ifil_chunk.writeUnsignedShort(this.minor); + writeInfoStringChunk(writer, "isng", this.targetEngine); + writeInfoStringChunk(writer, "INAM", this.name); + writeInfoStringChunk(writer, "irom", this.romName); + if (romVersionMajor != -1) { + RIFFWriter iver_chunk = writer.writeChunk("iver"); + iver_chunk.writeUnsignedShort(this.romVersionMajor); + iver_chunk.writeUnsignedShort(this.romVersionMinor); + } + writeInfoStringChunk(writer, "ICRD", this.creationDate); + writeInfoStringChunk(writer, "IENG", this.engineers); + writeInfoStringChunk(writer, "IPRD", this.product); + writeInfoStringChunk(writer, "ICOP", this.copyright); + writeInfoStringChunk(writer, "ICMT", this.comments); + writeInfoStringChunk(writer, "ISFT", this.tools); + + writer.close(); + } + + private void writeSdtaChunk(RIFFWriter writer) throws IOException { + + byte[] pad = new byte[32]; + + RIFFWriter smpl_chunk = writer.writeChunk("smpl"); + for (SF2Sample sample : samples) { + ModelByteBuffer data = sample.getDataBuffer(); + data.writeTo(smpl_chunk); + /* + smpl_chunk.write(data.array(), + data.arrayOffset(), + data.capacity()); + */ + smpl_chunk.write(pad); + smpl_chunk.write(pad); + } + if (major < 2) + return; + if (major == 2 && minor < 4) + return; + + + for (SF2Sample sample : samples) { + ModelByteBuffer data24 = sample.getData24Buffer(); + if (data24 == null) + return; + } + + RIFFWriter sm24_chunk = writer.writeChunk("sm24"); + for (SF2Sample sample : samples) { + ModelByteBuffer data = sample.getData24Buffer(); + data.writeTo(sm24_chunk); + /* + sm24_chunk.write(data.array(), + data.arrayOffset(), + data.capacity());*/ + smpl_chunk.write(pad); + } + } + + private void writeModulators(RIFFWriter writer, List modulators) + throws IOException { + for (SF2Modulator modulator : modulators) { + writer.writeUnsignedShort(modulator.sourceOperator); + writer.writeUnsignedShort(modulator.destinationOperator); + writer.writeShort(modulator.amount); + writer.writeUnsignedShort(modulator.amountSourceOperator); + writer.writeUnsignedShort(modulator.transportOperator); + } + } + + private void writeGenerators(RIFFWriter writer, Map generators) + throws IOException { + Short keyrange = (Short) generators.get(SF2Region.GENERATOR_KEYRANGE); + Short velrange = (Short) generators.get(SF2Region.GENERATOR_VELRANGE); + if (keyrange != null) { + writer.writeUnsignedShort(SF2Region.GENERATOR_KEYRANGE); + writer.writeShort(keyrange); + } + if (velrange != null) { + writer.writeUnsignedShort(SF2Region.GENERATOR_VELRANGE); + writer.writeShort(velrange); + } + for (Map.Entry generator : generators.entrySet()) { + if (generator.getKey() == SF2Region.GENERATOR_KEYRANGE) + continue; + if (generator.getKey() == SF2Region.GENERATOR_VELRANGE) + continue; + writer.writeUnsignedShort(generator.getKey()); + writer.writeShort(generator.getValue()); + } + } + + private void writePdtaChunk(RIFFWriter writer) throws IOException { + + RIFFWriter phdr_chunk = writer.writeChunk("phdr"); + int phdr_zone_count = 0; + for (SF2Instrument preset : this.instruments) { + phdr_chunk.writeString(preset.name, 20); + phdr_chunk.writeUnsignedShort(preset.preset); + phdr_chunk.writeUnsignedShort(preset.bank); + phdr_chunk.writeUnsignedShort(phdr_zone_count); + if (preset.getGlobalRegion() != null) + phdr_zone_count += 1; + phdr_zone_count += preset.getRegions().size(); + phdr_chunk.writeUnsignedInt(preset.library); + phdr_chunk.writeUnsignedInt(preset.genre); + phdr_chunk.writeUnsignedInt(preset.morphology); + } + phdr_chunk.writeString("EOP", 20); + phdr_chunk.writeUnsignedShort(0); + phdr_chunk.writeUnsignedShort(0); + phdr_chunk.writeUnsignedShort(phdr_zone_count); + phdr_chunk.writeUnsignedInt(0); + phdr_chunk.writeUnsignedInt(0); + phdr_chunk.writeUnsignedInt(0); + + + RIFFWriter pbag_chunk = writer.writeChunk("pbag"); + int pbag_gencount = 0; + int pbag_modcount = 0; + for (SF2Instrument preset : this.instruments) { + if (preset.getGlobalRegion() != null) { + pbag_chunk.writeUnsignedShort(pbag_gencount); + pbag_chunk.writeUnsignedShort(pbag_modcount); + pbag_gencount += preset.getGlobalRegion().getGenerators().size(); + pbag_modcount += preset.getGlobalRegion().getModulators().size(); + } + for (SF2InstrumentRegion region : preset.getRegions()) { + pbag_chunk.writeUnsignedShort(pbag_gencount); + pbag_chunk.writeUnsignedShort(pbag_modcount); + if (layers.indexOf(region.layer) != -1) { + // One generator is used to reference to instrument record + pbag_gencount += 1; + } + pbag_gencount += region.getGenerators().size(); + pbag_modcount += region.getModulators().size(); + + } + } + pbag_chunk.writeUnsignedShort(pbag_gencount); + pbag_chunk.writeUnsignedShort(pbag_modcount); + + RIFFWriter pmod_chunk = writer.writeChunk("pmod"); + for (SF2Instrument preset : this.instruments) { + if (preset.getGlobalRegion() != null) { + writeModulators(pmod_chunk, + preset.getGlobalRegion().getModulators()); + } + for (SF2InstrumentRegion region : preset.getRegions()) + writeModulators(pmod_chunk, region.getModulators()); + } + pmod_chunk.write(new byte[10]); + + RIFFWriter pgen_chunk = writer.writeChunk("pgen"); + for (SF2Instrument preset : this.instruments) { + if (preset.getGlobalRegion() != null) { + writeGenerators(pgen_chunk, + preset.getGlobalRegion().getGenerators()); + } + for (SF2InstrumentRegion region : preset.getRegions()) { + writeGenerators(pgen_chunk, region.getGenerators()); + int ix = (int) layers.indexOf(region.layer); + if (ix != -1) { + pgen_chunk.writeUnsignedShort(SF2Region.GENERATOR_INSTRUMENT); + pgen_chunk.writeShort((short) ix); + } + } + } + pgen_chunk.write(new byte[4]); + + RIFFWriter inst_chunk = writer.writeChunk("inst"); + int inst_zone_count = 0; + for (SF2Layer instrument : this.layers) { + inst_chunk.writeString(instrument.name, 20); + inst_chunk.writeUnsignedShort(inst_zone_count); + if (instrument.getGlobalRegion() != null) + inst_zone_count += 1; + inst_zone_count += instrument.getRegions().size(); + } + inst_chunk.writeString("EOI", 20); + inst_chunk.writeUnsignedShort(inst_zone_count); + + + RIFFWriter ibag_chunk = writer.writeChunk("ibag"); + int ibag_gencount = 0; + int ibag_modcount = 0; + for (SF2Layer instrument : this.layers) { + if (instrument.getGlobalRegion() != null) { + ibag_chunk.writeUnsignedShort(ibag_gencount); + ibag_chunk.writeUnsignedShort(ibag_modcount); + ibag_gencount + += instrument.getGlobalRegion().getGenerators().size(); + ibag_modcount + += instrument.getGlobalRegion().getModulators().size(); + } + for (SF2LayerRegion region : instrument.getRegions()) { + ibag_chunk.writeUnsignedShort(ibag_gencount); + ibag_chunk.writeUnsignedShort(ibag_modcount); + if (samples.indexOf(region.sample) != -1) { + // One generator is used to reference to instrument record + ibag_gencount += 1; + } + ibag_gencount += region.getGenerators().size(); + ibag_modcount += region.getModulators().size(); + + } + } + ibag_chunk.writeUnsignedShort(ibag_gencount); + ibag_chunk.writeUnsignedShort(ibag_modcount); + + + RIFFWriter imod_chunk = writer.writeChunk("imod"); + for (SF2Layer instrument : this.layers) { + if (instrument.getGlobalRegion() != null) { + writeModulators(imod_chunk, + instrument.getGlobalRegion().getModulators()); + } + for (SF2LayerRegion region : instrument.getRegions()) + writeModulators(imod_chunk, region.getModulators()); + } + imod_chunk.write(new byte[10]); + + RIFFWriter igen_chunk = writer.writeChunk("igen"); + for (SF2Layer instrument : this.layers) { + if (instrument.getGlobalRegion() != null) { + writeGenerators(igen_chunk, + instrument.getGlobalRegion().getGenerators()); + } + for (SF2LayerRegion region : instrument.getRegions()) { + writeGenerators(igen_chunk, region.getGenerators()); + int ix = samples.indexOf(region.sample); + if (ix != -1) { + igen_chunk.writeUnsignedShort(SF2Region.GENERATOR_SAMPLEID); + igen_chunk.writeShort((short) ix); + } + } + } + igen_chunk.write(new byte[4]); + + + RIFFWriter shdr_chunk = writer.writeChunk("shdr"); + long sample_pos = 0; + for (SF2Sample sample : samples) { + shdr_chunk.writeString(sample.name, 20); + long start = sample_pos; + sample_pos += sample.data.capacity() / 2; + long end = sample_pos; + long startLoop = sample.startLoop + start; + long endLoop = sample.endLoop + start; + if (startLoop < start) + startLoop = start; + if (endLoop > end) + endLoop = end; + shdr_chunk.writeUnsignedInt(start); + shdr_chunk.writeUnsignedInt(end); + shdr_chunk.writeUnsignedInt(startLoop); + shdr_chunk.writeUnsignedInt(endLoop); + shdr_chunk.writeUnsignedInt(sample.sampleRate); + shdr_chunk.writeUnsignedByte(sample.originalPitch); + shdr_chunk.writeByte(sample.pitchCorrection); + shdr_chunk.writeUnsignedShort(sample.sampleLink); + shdr_chunk.writeUnsignedShort(sample.sampleType); + sample_pos += 32; + } + shdr_chunk.writeString("EOS", 20); + shdr_chunk.write(new byte[26]); + + } + + public String getName() { + return name; + } + + public String getVersion() { + return major + "." + minor; + } + + public String getVendor() { + return engineers; + } + + public String getDescription() { + return comments; + } + + public void setName(String s) { + name = s; + } + + public void setVendor(String s) { + engineers = s; + } + + public void setDescription(String s) { + comments = s; + } + + public SoundbankResource[] getResources() { + SoundbankResource[] resources + = new SoundbankResource[layers.size() + samples.size()]; + int j = 0; + for (int i = 0; i < layers.size(); i++) + resources[j++] = layers.get(i); + for (int i = 0; i < samples.size(); i++) + resources[j++] = samples.get(i); + return resources; + } + + public SF2Instrument[] getInstruments() { + SF2Instrument[] inslist_array + = instruments.toArray(new SF2Instrument[instruments.size()]); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; + } + + public SF2Layer[] getLayers() { + return layers.toArray(new SF2Layer[layers.size()]); + } + + public SF2Sample[] getSamples() { + return samples.toArray(new SF2Sample[samples.size()]); + } + + public Instrument getInstrument(Patch patch) { + int program = patch.getProgram(); + int bank = patch.getBank(); + boolean percussion = false; + if (patch instanceof ModelPatch) + percussion = ((ModelPatch)patch).isPercussion(); + for (Instrument instrument : instruments) { + Patch patch2 = instrument.getPatch(); + int program2 = patch2.getProgram(); + int bank2 = patch2.getBank(); + if (program == program2 && bank == bank2) { + boolean percussion2 = false; + if (patch2 instanceof ModelPatch) + percussion2 = ((ModelPatch) patch2).isPercussion(); + if (percussion == percussion2) + return instrument; + } + } + return null; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getProduct() { + return product; + } + + public void setProduct(String product) { + this.product = product; + } + + public String getRomName() { + return romName; + } + + public void setRomName(String romName) { + this.romName = romName; + } + + public int getRomVersionMajor() { + return romVersionMajor; + } + + public void setRomVersionMajor(int romVersionMajor) { + this.romVersionMajor = romVersionMajor; + } + + public int getRomVersionMinor() { + return romVersionMinor; + } + + public void setRomVersionMinor(int romVersionMinor) { + this.romVersionMinor = romVersionMinor; + } + + public String getTargetEngine() { + return targetEngine; + } + + public void setTargetEngine(String targetEngine) { + this.targetEngine = targetEngine; + } + + public String getTools() { + return tools; + } + + public void setTools(String tools) { + this.tools = tools; + } + + public void addResource(SoundbankResource resource) { + if (resource instanceof SF2Instrument) + instruments.add((SF2Instrument)resource); + if (resource instanceof SF2Layer) + layers.add((SF2Layer)resource); + if (resource instanceof SF2Sample) + samples.add((SF2Sample)resource); + } + + public void removeResource(SoundbankResource resource) { + if (resource instanceof SF2Instrument) + instruments.remove((SF2Instrument)resource); + if (resource instanceof SF2Layer) + layers.remove((SF2Layer)resource); + if (resource instanceof SF2Sample) + samples.remove((SF2Sample)resource); + } + + public void addInstrument(SF2Instrument resource) { + instruments.add(resource); + } + + public void removeInstrument(SF2Instrument resource) { + instruments.remove(resource); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SF2SoundbankReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SF2SoundbankReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.Soundbank; +import javax.sound.midi.spi.SoundbankReader; + +/** + * This class is used to connect the SF2SoundBank class + * to the SoundbankReader SPI interface. + * + * @author Karl Helgason + */ +public class SF2SoundbankReader extends SoundbankReader { + + public Soundbank getSoundbank(URL url) + throws InvalidMidiDataException, IOException { + try { + return new SF2Soundbank(url); + } catch (RIFFInvalidFormatException e) { + return null; + } + } + + public Soundbank getSoundbank(InputStream stream) + throws InvalidMidiDataException, IOException { + try { + stream.mark(512); + return new SF2Soundbank(stream); + } catch (RIFFInvalidFormatException e) { + stream.reset(); + return null; + } + } + + public Soundbank getSoundbank(File file) + throws InvalidMidiDataException, IOException { + if (!file.getPath().toLowerCase().endsWith(".sf2")) + return null; + try { + return new SF2Soundbank(file); + } catch (RIFFInvalidFormatException e) { + return null; + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SimpleInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SimpleInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,196 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.List; +import javax.sound.midi.Patch; + +/** + * A simple instrument that is made of other ModelInstrument, ModelPerformer + * objects. + * + * @author Karl Helgason + */ +public class SimpleInstrument extends ModelInstrument { + + protected class SimpleInstrumentPart { + ModelPerformer[] performers; + int keyFrom; + int keyTo; + int velFrom; + int velTo; + int exclusiveClass; + } + protected int preset = 0; + protected int bank = 0; + protected boolean percussion = false; + protected String name = ""; + protected List parts + = new ArrayList(); + + public SimpleInstrument() { + super(null, null, null, null); + } + + public void clear() { + parts.clear(); + } + + public void add(ModelPerformer[] performers, int keyFrom, int keyTo, + int velFrom, int velTo, int exclusiveClass) { + SimpleInstrumentPart part = new SimpleInstrumentPart(); + part.performers = performers; + part.keyFrom = keyFrom; + part.keyTo = keyTo; + part.velFrom = velFrom; + part.velTo = velTo; + part.exclusiveClass = exclusiveClass; + parts.add(part); + } + + public void add(ModelPerformer[] performers, int keyFrom, int keyTo, + int velFrom, int velTo) { + add(performers, keyFrom, keyTo, velFrom, velTo, -1); + } + + public void add(ModelPerformer[] performers, int keyFrom, int keyTo) { + add(performers, keyFrom, keyTo, 0, 127, -1); + } + + public void add(ModelPerformer[] performers) { + add(performers, 0, 127, 0, 127, -1); + } + + public void add(ModelPerformer performer, int keyFrom, int keyTo, + int velFrom, int velTo, int exclusiveClass) { + add(new ModelPerformer[]{performer}, keyFrom, keyTo, velFrom, velTo, + exclusiveClass); + } + + public void add(ModelPerformer performer, int keyFrom, int keyTo, + int velFrom, int velTo) { + add(new ModelPerformer[]{performer}, keyFrom, keyTo, velFrom, velTo); + } + + public void add(ModelPerformer performer, int keyFrom, int keyTo) { + add(new ModelPerformer[]{performer}, keyFrom, keyTo); + } + + public void add(ModelPerformer performer) { + add(new ModelPerformer[]{performer}); + } + + public void add(ModelInstrument ins, int keyFrom, int keyTo, int velFrom, + int velTo, int exclusiveClass) { + add(ins.getPerformers(), keyFrom, keyTo, velFrom, velTo, exclusiveClass); + } + + public void add(ModelInstrument ins, int keyFrom, int keyTo, int velFrom, + int velTo) { + add(ins.getPerformers(), keyFrom, keyTo, velFrom, velTo); + } + + public void add(ModelInstrument ins, int keyFrom, int keyTo) { + add(ins.getPerformers(), keyFrom, keyTo); + } + + public void add(ModelInstrument ins) { + add(ins.getPerformers()); + } + + public ModelPerformer[] getPerformers() { + + int percount = 0; + for (SimpleInstrumentPart part : parts) + if (part.performers != null) + percount += part.performers.length; + + ModelPerformer[] performers = new ModelPerformer[percount]; + int px = 0; + for (SimpleInstrumentPart part : parts) { + if (part.performers != null) { + for (ModelPerformer mperfm : part.performers) { + ModelPerformer performer = new ModelPerformer(); + performer.setName(getName()); + performers[px++] = performer; + + performer.setDefaultConnectionsEnabled( + mperfm.isDefaultConnectionsEnabled()); + performer.setKeyFrom(mperfm.getKeyFrom()); + performer.setKeyTo(mperfm.getKeyTo()); + performer.setVelFrom(mperfm.getVelFrom()); + performer.setVelTo(mperfm.getVelTo()); + performer.setExclusiveClass(mperfm.getExclusiveClass()); + performer.setSelfNonExclusive(mperfm.isSelfNonExclusive()); + performer.setReleaseTriggered(mperfm.isReleaseTriggered()); + if (part.exclusiveClass != -1) + performer.setExclusiveClass(part.exclusiveClass); + if (part.keyFrom > performer.getKeyFrom()) + performer.setKeyFrom(part.keyFrom); + if (part.keyTo < performer.getKeyTo()) + performer.setKeyTo(part.keyTo); + if (part.velFrom > performer.getVelFrom()) + performer.setVelFrom(part.velFrom); + if (part.velTo < performer.getVelTo()) + performer.setVelTo(part.velTo); + performer.getOscillators().addAll(mperfm.getOscillators()); + performer.getConnectionBlocks().addAll( + mperfm.getConnectionBlocks()); + } + } + } + + return performers; + } + + public Object getData() { + return null; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public ModelPatch getPatch() { + return new ModelPatch(bank, preset, percussion); + } + + public void setPatch(Patch patch) { + if (patch instanceof ModelPatch && ((ModelPatch)patch).isPercussion()) { + percussion = true; + bank = patch.getBank(); + preset = patch.getProgram(); + } else { + percussion = false; + bank = patch.getBank(); + preset = patch.getProgram(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SimpleSoundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SimpleSoundbank.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,145 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.sound.midi.Instrument; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; + +/** + * A simple soundbank that contains instruments and soundbankresources. + * + * @author Karl Helgason + */ +public class SimpleSoundbank implements Soundbank { + + String name = ""; + String version = ""; + String vendor = ""; + String description = ""; + List resources = new ArrayList(); + List instruments = new ArrayList(); + + public String getName() { + return name; + } + + public String getVersion() { + return version; + } + + public String getVendor() { + return vendor; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setName(String name) { + this.name = name; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public void setVersion(String version) { + this.version = version; + } + + public SoundbankResource[] getResources() { + return resources.toArray(new SoundbankResource[resources.size()]); + } + + public Instrument[] getInstruments() { + Instrument[] inslist_array + = instruments.toArray(new Instrument[resources.size()]); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; + } + + public Instrument getInstrument(Patch patch) { + int program = patch.getProgram(); + int bank = patch.getBank(); + boolean percussion = false; + if (patch instanceof ModelPatch) + percussion = ((ModelPatch)patch).isPercussion(); + for (Instrument instrument : instruments) { + Patch patch2 = instrument.getPatch(); + int program2 = patch2.getProgram(); + int bank2 = patch2.getBank(); + if (program == program2 && bank == bank2) { + boolean percussion2 = false; + if (patch2 instanceof ModelPatch) + percussion2 = ((ModelPatch)patch2).isPercussion(); + if (percussion == percussion2) + return instrument; + } + } + return null; + } + + public void addResource(SoundbankResource resource) { + if (resource instanceof Instrument) + instruments.add((Instrument) resource); + else + resources.add(resource); + } + + public void removeResource(SoundbankResource resource) { + if (resource instanceof Instrument) + instruments.remove((Instrument) resource); + else + resources.remove(resource); + } + + public void addInstrument(Instrument resource) { + instruments.add(resource); + } + + public void removeInstrument(Instrument resource) { + instruments.remove(resource); + } + + public void addAllInstruments(Soundbank soundbank) { + for (Instrument ins : soundbank.getInstruments()) + addInstrument(ins); + } + + public void removeAllInstruments(Soundbank soundbank) { + for (Instrument ins : soundbank.getInstruments()) + removeInstrument(ins); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftAbstractResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftAbstractResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,393 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import java.util.Arrays; + +import javax.sound.midi.MidiChannel; +import javax.sound.midi.VoiceStatus; + +/** + * Abstract resampler class. + * + * @author Karl Helgason + */ +public abstract class SoftAbstractResampler implements SoftResampler { + + private class ModelAbstractResamplerStream implements SoftResamplerStreamer { + + AudioFloatInputStream stream; + boolean stream_eof = false; + int loopmode; + boolean loopdirection = true; // true = forward + float loopstart; + float looplen; + float target_pitch; + float[] current_pitch = new float[1]; + boolean started; + boolean eof; + boolean loopreadevent = false; + int sector_pos = 0; + int sector_size = 400; + int sector_loopstart = -1; + boolean markset = false; + int marklimit = 0; + int streampos = 0; + int nrofchannels = 2; + boolean noteOff_flag = false; + float[][] ibuffer; + boolean ibuffer_order = true; + float[] sbuffer; + int pad; + int pad2; + float[] ix = new float[1]; + int[] ox = new int[1]; + float samplerateconv = 1; + float pitchcorrection = 0; + boolean streammarked = true; + + public ModelAbstractResamplerStream() { + pad = getPadding(); + pad2 = getPadding() * 2; + ibuffer = new float[2][sector_size + pad2]; + ibuffer_order = true; + } + + public void noteOn(MidiChannel channel, VoiceStatus voice, + int noteNumber, int velocity) { + } + + public void noteOff(int velocity) { + noteOff_flag = true; + } + + public void open(ModelWavetable osc, float outputsamplerate) + throws IOException { + + eof = false; + nrofchannels = osc.getChannels(); + if (ibuffer.length < nrofchannels) { + ibuffer = new float[nrofchannels][sector_size + pad2]; + } + + stream = osc.openStream(); + streampos = 0; + stream_eof = false; + pitchcorrection = osc.getPitchcorrection(); + samplerateconv + = stream.getFormat().getSampleRate() / outputsamplerate; + looplen = osc.getLoopLength(); + loopstart = osc.getLoopStart(); + sector_loopstart = (int) (loopstart / sector_size); + sector_loopstart = sector_loopstart - 1; + + sector_pos = 0; + + if (sector_loopstart < 0) + sector_loopstart = 0; + started = false; + loopmode = osc.getLoopType(); + + if (loopmode != 0) { + markset = false; + marklimit = nrofchannels * (int) (looplen + pad2 + 1); + } else + markset = true; + // loopmode = 0; + + target_pitch = samplerateconv; + current_pitch[0] = samplerateconv; + + ibuffer_order = true; + loopdirection = true; + noteOff_flag = false; + + for (int i = 0; i < nrofchannels; i++) + Arrays.fill(ibuffer[i], sector_size, sector_size + pad2, 0); + ix[0] = pad; + eof = false; + loopreadevent = false; + + ix[0] = sector_size + pad; + sector_pos = -1; + streampos = -sector_size; + + nextBuffer(); + } + + public void setPitch(float pitch) { + /* + this.pitch = (float) Math.pow(2f, + (pitchcorrection + pitch) / 1200.0f) + * samplerateconv; + */ + this.target_pitch = (float)Math.exp( + (pitchcorrection + pitch) * (Math.log(2.0) / 1200.0)) + * samplerateconv; + + if (!started) + current_pitch[0] = this.target_pitch; + } + + public void nextBuffer() throws IOException { + if (ix[0] < pad) { + if (markset) { + // reset to target sector + stream.reset(); + ix[0] += streampos - (sector_loopstart * sector_size); + sector_pos = sector_loopstart; + streampos = sector_pos * sector_size; + + // and go one sector backward + ix[0] += sector_size; + sector_pos -= 1; + streampos -= sector_size; + stream_eof = false; + } + } + + if (ix[0] >= sector_size + pad) { + if (stream_eof) { + eof = true; + return; + } + } + + if (ix[0] >= sector_size * 4 + pad) { + int skips = (int)((ix[0] - sector_size * 4 + pad) / sector_size); + ix[0] -= sector_size * skips; + sector_pos += skips; + streampos += sector_size * skips; + stream.skip(sector_size * skips); + } + + while (ix[0] >= sector_size + pad) { + if (!markset) { + if (sector_pos + 1 == sector_loopstart) { + stream.mark(marklimit); + markset = true; + } + } + ix[0] -= sector_size; + sector_pos++; + streampos += sector_size; + + for (int c = 0; c < nrofchannels; c++) { + float[] cbuffer = ibuffer[c]; + for (int i = 0; i < pad2; i++) + cbuffer[i] = cbuffer[i + sector_size]; + } + + int ret; + if (nrofchannels == 1) + ret = stream.read(ibuffer[0], pad2, sector_size); + else { + int slen = sector_size * nrofchannels; + if (sbuffer == null || sbuffer.length < slen) + sbuffer = new float[slen]; + int sret = stream.read(sbuffer, 0, slen); + if (sret == -1) + ret = -1; + else { + ret = sret / nrofchannels; + for (int i = 0; i < nrofchannels; i++) { + float[] buff = ibuffer[i]; + int ix = i; + int ix_step = nrofchannels; + int ox = pad2; + for (int j = 0; j < ret; j++, ix += ix_step, ox++) + buff[ox] = sbuffer[ix]; + } + } + + } + + if (ret == -1) { + ret = 0; + stream_eof = true; + for (int i = 0; i < nrofchannels; i++) + Arrays.fill(ibuffer[i], pad2, pad2 + sector_size, 0f); + return; + } + if (ret != sector_size) { + for (int i = 0; i < nrofchannels; i++) + Arrays.fill(ibuffer[i], pad2 + ret, pad2 + sector_size, 0f); + } + + ibuffer_order = true; + + } + + } + + public void reverseBuffers() { + ibuffer_order = !ibuffer_order; + for (int c = 0; c < nrofchannels; c++) { + float[] cbuff = ibuffer[c]; + int len = cbuff.length - 1; + int len2 = cbuff.length / 2; + for (int i = 0; i < len2; i++) { + float x = cbuff[i]; + cbuff[i] = cbuff[len - i]; + cbuff[len - i] = x; + } + } + } + + public int read(float[][] buffer, int offset, int len) + throws IOException { + + if (eof) + return -1; + + if (noteOff_flag) + if ((loopmode & 2) != 0) + if (loopdirection) + loopmode = 0; + + + float pitchstep = (target_pitch - current_pitch[0]) / len; + float[] current_pitch = this.current_pitch; + started = true; + + int[] ox = this.ox; + ox[0] = offset; + int ox_end = len + offset; + + float ixend = sector_size + pad; + if (!loopdirection) + ixend = pad; + while (ox[0] != ox_end) { + nextBuffer(); + if (!loopdirection) { + // If we are in backward playing part of pingpong + // or reverse loop + + if (streampos < (loopstart + pad)) { + ixend = loopstart - streampos + pad2; + if (ix[0] <= ixend) { + if ((loopmode & 4) != 0) { + // Ping pong loop, change loopdirection + loopdirection = true; + ixend = sector_size + pad; + continue; + } + + ix[0] += looplen; + ixend = pad; + continue; + } + } + + if (ibuffer_order != loopdirection) + reverseBuffers(); + + ix[0] = (sector_size + pad2) - ix[0]; + ixend = (sector_size + pad2) - ixend; + ixend++; + + float bak_ix = ix[0]; + int bak_ox = ox[0]; + float bak_pitch = current_pitch[0]; + for (int i = 0; i < nrofchannels; i++) { + if (buffer[i] != null) { + ix[0] = bak_ix; + ox[0] = bak_ox; + current_pitch[0] = bak_pitch; + interpolate(ibuffer[i], ix, ixend, current_pitch, + pitchstep, buffer[i], ox, ox_end); + } + } + + ix[0] = (sector_size + pad2) - ix[0]; + ixend--; + ixend = (sector_size + pad2) - ixend; + + if (eof) { + current_pitch[0] = this.target_pitch; + return ox[0] - offset; + } + + continue; + } + if (loopmode != 0) { + if (streampos + sector_size > (looplen + loopstart + pad)) { + ixend = loopstart + looplen - streampos + pad2; + if (ix[0] >= ixend) { + if ((loopmode & 4) != 0 || (loopmode & 8) != 0) { + // Ping pong or revese loop, change loopdirection + loopdirection = false; + ixend = pad; + continue; + } + ixend = sector_size + pad; + ix[0] -= looplen; + continue; + } + } + } + + if (ibuffer_order != loopdirection) + reverseBuffers(); + + float bak_ix = ix[0]; + int bak_ox = ox[0]; + float bak_pitch = current_pitch[0]; + for (int i = 0; i < nrofchannels; i++) { + if (buffer[i] != null) { + ix[0] = bak_ix; + ox[0] = bak_ox; + current_pitch[0] = bak_pitch; + interpolate(ibuffer[i], ix, ixend, current_pitch, + pitchstep, buffer[i], ox, ox_end); + } + } + + if (eof) { + current_pitch[0] = this.target_pitch; + return ox[0] - offset; + } + } + + current_pitch[0] = this.target_pitch; + return len; + } + + public void close() throws IOException { + stream.close(); + } + } + + public abstract int getPadding(); + + public abstract void interpolate(float[] in, float[] in_offset, + float in_end, float[] pitch, float pitchstep, float[] out, + int[] out_offset, int out_end); + + public SoftResamplerStreamer openStreamer() { + return new ModelAbstractResamplerStream(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftAudioBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.Arrays; + +import javax.sound.sampled.AudioFormat; + +/** + * This class is used to store audio buffer. + * + * @author Karl Helgason + */ +public class SoftAudioBuffer { + + private int size; + private float[] buffer; + private boolean empty = true; + private AudioFormat format; + private AudioFloatConverter converter; + private byte[] converter_buffer; + + public SoftAudioBuffer(int size, AudioFormat format) { + this.size = size; + this.format = format; + converter = AudioFloatConverter.getConverter(format); + } + + public AudioFormat getFormat() { + return format; + } + + public int getSize() { + return size; + } + + public void clear() { + if (!empty) { + Arrays.fill(buffer, 0); + empty = true; + } + } + + public boolean isSilent() { + return empty; + } + + public float[] array() { + empty = false; + if (buffer == null) + buffer = new float[size]; + return buffer; + } + + public void get(byte[] buffer, int channel) { + + int framesize_pc = (format.getFrameSize() / format.getChannels()); + int c_len = size * framesize_pc; + if (converter_buffer == null || converter_buffer.length < c_len) + converter_buffer = new byte[c_len]; + + if (format.getChannels() == 1) { + converter.toByteArray(array(), size, buffer); + } else { + converter.toByteArray(array(), size, converter_buffer); + if (channel >= format.getChannels()) + return; + int z_stepover = format.getChannels() * framesize_pc; + int k_stepover = framesize_pc; + for (int j = 0; j < framesize_pc; j++) { + int k = j; + int z = channel * framesize_pc + j; + for (int i = 0; i < size; i++) { + buffer[z] = converter_buffer[k]; + z += z_stepover; + k += k_stepover; + } + } + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftAudioProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioProcessor.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Audio processor interface. + * + * @author Karl Helgason + */ +public interface SoftAudioProcessor { + + public void globalParameterControlChange(int[] slothpath, long param, + long value); + + public void init(SoftSynthesizer synthesizer); + + public void setInput(int pin, SoftAudioBuffer input); + + public void setOutput(int pin, SoftAudioBuffer output); + + public void setMixMode(boolean mix); + + public void processAudio(); + + public void processControlLogic(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftAudioPusher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftAudioPusher.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.SourceDataLine; + +/** + * This is a processor object that writes into SourceDataLine + * + * @author Karl Helgason + */ +public class SoftAudioPusher implements Runnable { + + private volatile boolean active = false; + private SourceDataLine sourceDataLine = null; + private Thread audiothread; + private AudioInputStream ais; + private byte[] buffer; + + public SoftAudioPusher(SourceDataLine sourceDataLine, AudioInputStream ais, + int workbuffersizer) { + this.ais = ais; + this.buffer = new byte[workbuffersizer]; + this.sourceDataLine = sourceDataLine; + } + + public synchronized void start() { + if (active) + return; + active = true; + audiothread = new Thread(this); + audiothread.setPriority(Thread.MAX_PRIORITY); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + //e.printStackTrace(); + } + audiothread.start(); + } + + public synchronized void stop() { + if (!active) + return; + active = false; + try { + audiothread.join(); + } catch (InterruptedException e) { + //e.printStackTrace(); + } + } + + public void run() { + byte[] buffer = SoftAudioPusher.this.buffer; + AudioInputStream ais = SoftAudioPusher.this.ais; + SourceDataLine sourceDataLine = SoftAudioPusher.this.sourceDataLine; + + try { + while (active) { + // Read from audio source + ais.read(buffer); + // Write byte buffer to source output + sourceDataLine.write(buffer, 0, buffer.length); + } + } catch (IOException e) { + active = false; + //e.printStackTrace(); + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftChannel.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,1517 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.sound.midi.MidiChannel; +import javax.sound.midi.Patch; + +/** + * Software Synthesizer MIDI channel class. + * + * @author Karl Helgason + */ +public class SoftChannel implements MidiChannel, ModelDirectedPlayer { + + private static boolean[] dontResetControls = new boolean[128]; + static { + for (int i = 0; i < dontResetControls.length; i++) + dontResetControls[i] = false; + + dontResetControls[0] = true; // Bank Select (MSB) + dontResetControls[32] = true; // Bank Select (LSB) + dontResetControls[7] = true; // Channel Volume (MSB) + dontResetControls[8] = true; // Balance (MSB) + dontResetControls[10] = true; // Pan (MSB) + dontResetControls[11] = true; // Expression (MSB) + dontResetControls[91] = true; // Effects 1 Depth (default: Reverb Send) + dontResetControls[92] = true; // Effects 2 Depth (default: Tremolo Depth) + dontResetControls[93] = true; // Effects 3 Depth (default: Chorus Send) + dontResetControls[94] = true; // Effects 4 Depth (default: Celeste [Detune] Depth) + dontResetControls[95] = true; // Effects 5 Depth (default: Phaser Depth) + dontResetControls[70] = true; // Sound Controller 1 (default: Sound Variation) + dontResetControls[71] = true; // Sound Controller 2 (default: Timbre / Harmonic Quality) + dontResetControls[72] = true; // Sound Controller 3 (default: Release Time) + dontResetControls[73] = true; // Sound Controller 4 (default: Attack Time) + dontResetControls[74] = true; // Sound Controller 5 (default: Brightness) + dontResetControls[75] = true; // Sound Controller 6 (GM2 default: Decay Time) + dontResetControls[76] = true; // Sound Controller 7 (GM2 default: Vibrato Rate) + dontResetControls[77] = true; // Sound Controller 8 (GM2 default: Vibrato Depth) + dontResetControls[78] = true; // Sound Controller 9 (GM2 default: Vibrato Delay) + dontResetControls[79] = true; // Sound Controller 10 (GM2 default: Undefined) + dontResetControls[120] = true; // All Sound Off + dontResetControls[121] = true; // Reset All Controllers + dontResetControls[122] = true; // Local Control On/Off + dontResetControls[123] = true; // All Notes Off + dontResetControls[124] = true; // Omni Mode Off + dontResetControls[125] = true; // Omni Mode On + dontResetControls[126] = true; // Poly Mode Off + dontResetControls[127] = true; // Poly Mode On + + dontResetControls[6] = true; // Data Entry (MSB) + dontResetControls[38] = true; // Data Entry (LSB) + dontResetControls[96] = true; // Data Increment + dontResetControls[97] = true; // Data Decrement + dontResetControls[98] = true; // Non-Registered Parameter Number (LSB) + dontResetControls[99] = true; // Non-Registered Parameter Number(MSB) + dontResetControls[100] = true; // RPN = Null + dontResetControls[101] = true; // RPN = Null + + } + + private static final int RPN_NULL_VALUE = (127 << 7) + 127; + private int rpn_control = RPN_NULL_VALUE; + private int nrpn_control = RPN_NULL_VALUE; + protected double portamento_time = 1; // keyschanges per control buffer time + protected int[] portamento_lastnote = new int[128]; + protected int portamento_lastnote_ix = 0; + private int portamento_control_note = -1; + private boolean portamento = false; + private boolean mono = false; + private boolean mute = false; + private boolean solo = false; + private boolean solomute = false; + private Object control_mutex; + private int channel; + private SoftVoice[] voices; + private int bank; + private int program; + private SoftSynthesizer synthesizer; + private SoftMainMixer mainmixer; + private int[] polypressure = new int[128]; + private int channelpressure = 0; + private int[] controller = new int[128]; + private int pitchbend; + private double[] co_midi_pitch = new double[1]; + private double[] co_midi_channel_pressure = new double[1]; + protected SoftTuning tuning = new SoftTuning(); + protected int tuning_bank = 0; + protected int tuning_program = 0; + protected SoftInstrument current_instrument = null; + protected ModelChannelMixer current_mixer = null; + private ModelDirector current_director = null; + + // Controller Destination Settings + protected int cds_control_number = -1; + protected ModelConnectionBlock[] cds_control_connections = null; + protected ModelConnectionBlock[] cds_channelpressure_connections = null; + protected ModelConnectionBlock[] cds_polypressure_connections = null; + protected boolean sustain = false; + protected boolean[][] keybasedcontroller_active = null; + protected double[][] keybasedcontroller_value = null; + + private class MidiControlObject implements SoftControl { + double[] pitch = co_midi_pitch; + double[] channel_pressure = co_midi_channel_pressure; + double[] poly_pressure = new double[1]; + + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("pitch")) + return pitch; + if (name.equals("channel_pressure")) + return channel_pressure; + if (name.equals("poly_pressure")) + return poly_pressure; + return null; + } + } + + private SoftControl[] co_midi = new SoftControl[128]; + { + for (int i = 0; i < co_midi.length; i++) { + co_midi[i] = new MidiControlObject(); + } + } + + private double[][] co_midi_cc_cc = new double[128][1]; + private SoftControl co_midi_cc = new SoftControl() { + double[][] cc = co_midi_cc_cc; + public double[] get(int instance, String name) { + if (name == null) + return null; + return cc[Integer.parseInt(name)]; + } + }; + Map co_midi_rpn_rpn_i = new HashMap(); + Map co_midi_rpn_rpn = new HashMap(); + private SoftControl co_midi_rpn = new SoftControl() { + Map rpn = co_midi_rpn_rpn; + public double[] get(int instance, String name) { + if (name == null) + return null; + int iname = Integer.parseInt(name); + double[] v = rpn.get(iname); + if (v == null) { + v = new double[1]; + rpn.put(iname, v); + } + return v; + } + }; + Map co_midi_nrpn_nrpn_i = new HashMap(); + Map co_midi_nrpn_nrpn = new HashMap(); + private SoftControl co_midi_nrpn = new SoftControl() { + Map nrpn = co_midi_nrpn_nrpn; + public double[] get(int instance, String name) { + if (name == null) + return null; + int iname = Integer.parseInt(name); + double[] v = nrpn.get(iname); + if (v == null) { + v = new double[1]; + nrpn.put(iname, v); + } + return v; + } + }; + + public SoftChannel(SoftSynthesizer synth, int channel) { + this.channel = channel; + this.voices = synth.getVoices(); + this.synthesizer = synth; + this.mainmixer = synth.getMainMixer(); + control_mutex = synth.control_mutex; + resetAllControllers(true); + } + + private int findFreeVoice(int x) { + for (int i = x; i < voices.length; i++) + if (!voices[i].active) + return i; + + // No free voice was found, we must steal one + + int vmode = synthesizer.getVoiceAllocationMode(); + if (vmode == 1) { + // DLS Static Voice Allocation + + // * priority ( 10, 1-9, 11-16) + // Search for channel to steal from + int steal_channel = channel; + for (int j = 0; j < voices.length; j++) { + if (voices[j].stealer_channel == null) { + if (steal_channel == 9) { + steal_channel = voices[j].channel; + } else { + if (voices[j].channel != 9) { + if (voices[j].channel > steal_channel) + steal_channel = voices[j].channel; + } + } + } + } + + int voiceNo = -1; + + SoftVoice v = null; + // Search for oldest voice in off state on steal_channel + for (int j = 0; j < voices.length; j++) { + if (voices[j].channel == steal_channel) { + if (voices[j].stealer_channel == null && !voices[j].on) { + if (v == null) { + v = voices[j]; + voiceNo = j; + } + if (voices[j].voiceID < v.voiceID) { + v = voices[j]; + voiceNo = j; + } + } + } + } + // Search for oldest voice in on state on steal_channel + if (voiceNo == -1) { + for (int j = 0; j < voices.length; j++) { + if (voices[j].channel == steal_channel) { + if (voices[j].stealer_channel == null) { + if (v == null) { + v = voices[j]; + voiceNo = j; + } + if (voices[j].voiceID < v.voiceID) { + v = voices[j]; + voiceNo = j; + } + } + } + } + } + + return voiceNo; + + } else { + // Default Voice Allocation + // * Find voice that is on + // and Find voice which has lowest voiceID ( oldest voice) + // * Or find voice that is off + // and Find voice which has lowest voiceID ( oldest voice) + + int voiceNo = -1; + + SoftVoice v = null; + // Search for oldest voice in off state + for (int j = 0; j < voices.length; j++) { + if (voices[j].stealer_channel == null && !voices[j].on) { + if (v == null) { + v = voices[j]; + voiceNo = j; + } + if (voices[j].voiceID < v.voiceID) { + v = voices[j]; + voiceNo = j; + } + } + } + // Search for oldest voice in on state + if (voiceNo == -1) { + + for (int j = 0; j < voices.length; j++) { + if (voices[j].stealer_channel == null) { + if (v == null) { + v = voices[j]; + voiceNo = j; + } + if (voices[j].voiceID < v.voiceID) { + v = voices[j]; + voiceNo = j; + } + } + } + } + + return voiceNo; + } + + } + + protected void initVoice(SoftVoice voice, SoftPerformer p, int voiceID, + int noteNumber, int velocity, ModelConnectionBlock[] connectionBlocks, + ModelChannelMixer channelmixer, boolean releaseTriggered) { + if (voice.active) { + // Voice is active , we must steal the voice + voice.stealer_channel = this; + voice.stealer_performer = p; + voice.stealer_voiceID = voiceID; + voice.stealer_noteNumber = noteNumber; + voice.stealer_velocity = velocity; + voice.stealer_extendedConnectionBlocks = connectionBlocks; + voice.stealer_channelmixer = channelmixer; + voice.stealer_releaseTriggered = releaseTriggered; + for (int i = 0; i < voices.length; i++) + if (voices[i].active && voices[i].voiceID == voice.voiceID) + voices[i].soundOff(); + return; + } + + voice.extendedConnectionBlocks = connectionBlocks; + voice.channelmixer = channelmixer; + voice.releaseTriggered = releaseTriggered; + voice.voiceID = voiceID; + voice.tuning = tuning; + voice.exclusiveClass = p.exclusiveClass; + voice.softchannel = this; + voice.channel = channel; + voice.bank = bank; + voice.program = program; + voice.instrument = current_instrument; + voice.performer = p; + voice.objects.clear(); + voice.objects.put("midi", co_midi[noteNumber]); + voice.objects.put("midi_cc", co_midi_cc); + voice.objects.put("midi_rpn", co_midi_rpn); + voice.objects.put("midi_nrpn", co_midi_nrpn); + voice.noteOn(noteNumber, velocity); + voice.setMute(mute); + voice.setSoloMute(solomute); + if (releaseTriggered) + return; + if (portamento_control_note != -1) { + voice.co_noteon_keynumber[0] + = (tuning.getTuning(portamento_control_note) / 100.0) + * (1f / 128f); + voice.portamento = true; + portamento_control_note = -1; + } else if (portamento) { + if (mono) { + if (portamento_lastnote[0] != -1) { + voice.co_noteon_keynumber[0] + = (tuning.getTuning(portamento_lastnote[0]) / 100.0) + * (1f / 128f); + voice.portamento = true; + portamento_control_note = -1; + } + portamento_lastnote[0] = noteNumber; + } else { + if (portamento_lastnote_ix != 0) { + portamento_lastnote_ix--; + voice.co_noteon_keynumber[0] + = (tuning.getTuning( + portamento_lastnote[portamento_lastnote_ix]) + / 100.0) + * (1f / 128f); + voice.portamento = true; + } + } + } + } + + public void noteOn(int noteNumber, int velocity) { + + noteOn_internal(noteNumber, velocity); + if (current_mixer != null) + current_mixer.noteOn(noteNumber, velocity); + } + + private void noteOn_internal(int noteNumber, int velocity) { + + if (velocity == 0) { + noteOff_internal(noteNumber, 64); + return; + } + + synchronized (control_mutex) { + if (sustain) { + sustain = false; + for (int i = 0; i < voices.length; i++) { + if ((voices[i].sustain || voices[i].on) + && voices[i].channel == channel && voices[i].active + && voices[i].note == noteNumber) { + voices[i].sustain = false; + voices[i].on = true; + voices[i].noteOff(0); + } + } + sustain = true; + } + + mainmixer.msec_last_activity = mainmixer.msec_pos; + + if (mono) { + if (portamento) { + boolean n_found = false; + for (int i = 0; i < voices.length; i++) { + if (voices[i].on && voices[i].channel == channel + && voices[i].active + && voices[i].releaseTriggered == false) { + voices[i].portamento = true; + voices[i].setNote(noteNumber); + n_found = true; + } + } + if (n_found) { + portamento_lastnote[0] = noteNumber; + return; + } + } + + if (portamento_control_note != -1) { + boolean n_found = false; + for (int i = 0; i < voices.length; i++) { + if (voices[i].on && voices[i].channel == channel + && voices[i].active + && voices[i].note == portamento_control_note + && voices[i].releaseTriggered == false) { + voices[i].portamento = true; + voices[i].setNote(noteNumber); + n_found = true; + } + } + portamento_control_note = -1; + if (n_found) + return; + } + } + + if (mono) + allNotesOff(); + + if (current_instrument == null) { + current_instrument + = synthesizer.findInstrument(program, bank, channel); + if (current_instrument == null) + return; + if (current_mixer != null) + mainmixer.stopMixer(current_mixer); + current_mixer = current_instrument.getSourceInstrument() + .getChannelMixer(this, synthesizer.getFormat()); + if (current_mixer != null) + mainmixer.registerMixer(current_mixer); + current_director = current_instrument.getDirector(this, this); + applyInstrumentCustomization(); + } + prevVoiceID = synthesizer.voiceIDCounter++; + firstVoice = true; + voiceNo = 0; + + int tunedKey = (int)(Math.round(tuning.getTuning()[noteNumber]/100.0)); + play_noteNumber = noteNumber; + play_velocity = velocity; + play_releasetriggered = false; + lastVelocity[noteNumber] = velocity; + current_director.noteOn(tunedKey, velocity); + + /* + SoftPerformer[] performers = current_instrument.getPerformers(); + for (int i = 0; i < performers.length; i++) { + SoftPerformer p = performers[i]; + if (p.keyFrom <= tunedKey && p.keyTo >= tunedKey) { + if (p.velFrom <= velocity && p.velTo >= velocity) { + if (firstVoice) { + firstVoice = false; + if (p.exclusiveClass != 0) { + int x = p.exclusiveClass; + for (int j = 0; j < voices.length; j++) { + if (voices[j].active + && voices[j].channel == channel + && voices[j].exclusiveClass == x) { + if (!(p.selfNonExclusive + && voices[j].note == noteNumber)) + voices[j].shutdown(); + } + } + } + } + voiceNo = findFreeVoice(voiceNo); + if (voiceNo == -1) + return; + initVoice(voices[voiceNo], p, prevVoiceID, noteNumber, + velocity); + } + } + } + */ + } + } + + public void noteOff(int noteNumber, int velocity) { + noteOff_internal(noteNumber, velocity); + + if (current_mixer != null) + current_mixer.noteOff(noteNumber, velocity); + } + + private void noteOff_internal(int noteNumber, int velocity) { + synchronized (control_mutex) { + + if (!mono) { + if (portamento) { + if (portamento_lastnote_ix != 127) { + portamento_lastnote[portamento_lastnote_ix] = noteNumber; + portamento_lastnote_ix++; + } + } + } + + mainmixer.msec_last_activity = mainmixer.msec_pos; + for (int i = 0; i < voices.length; i++) { + if (voices[i].on && voices[i].channel == channel + && voices[i].note == noteNumber + && voices[i].releaseTriggered == false) { + voices[i].noteOff(velocity); + } + } + + // Try play back note-off triggered voices, + + if (current_instrument == null) { + current_instrument + = synthesizer.findInstrument(program, bank, channel); + if (current_instrument == null) + return; + if (current_mixer != null) + mainmixer.stopMixer(current_mixer); + current_mixer = current_instrument.getSourceInstrument() + .getChannelMixer(this, synthesizer.getFormat()); + if (current_mixer != null) + mainmixer.registerMixer(current_mixer); + current_director = current_instrument.getDirector(this, this); + applyInstrumentCustomization(); + + } + prevVoiceID = synthesizer.voiceIDCounter++; + firstVoice = true; + voiceNo = 0; + + int tunedKey = (int)(Math.round(tuning.getTuning()[noteNumber]/100.0)); + play_noteNumber = noteNumber; + play_velocity = lastVelocity[noteNumber]; + play_releasetriggered = true; + current_director.noteOff(tunedKey, velocity); + + } + } + private int[] lastVelocity = new int[128]; + private int prevVoiceID; + private boolean firstVoice = true; + private int voiceNo = 0; + private int play_noteNumber = 0; + private int play_velocity = 0; + private boolean play_releasetriggered = false; + + public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks) { + + int noteNumber = play_noteNumber; + int velocity = play_velocity; + boolean releasetriggered = play_releasetriggered; + + SoftPerformer p = current_instrument.getPerformers()[performerIndex]; + + if (firstVoice) { + firstVoice = false; + if (p.exclusiveClass != 0) { + int x = p.exclusiveClass; + for (int j = 0; j < voices.length; j++) { + if (voices[j].active && voices[j].channel == channel + && voices[j].exclusiveClass == x) { + if (!(p.selfNonExclusive && voices[j].note == noteNumber)) + voices[j].shutdown(); + } + } + } + } + + voiceNo = findFreeVoice(voiceNo); + + if (voiceNo == -1) + return; + + initVoice(voices[voiceNo], p, prevVoiceID, noteNumber, velocity, + connectionBlocks, current_mixer, releasetriggered); + } + + public void noteOff(int noteNumber) { + noteOff_internal(noteNumber, 64); + } + + public void setPolyPressure(int noteNumber, int pressure) { + if (current_mixer != null) + current_mixer.setPolyPressure(noteNumber, pressure); + + synchronized (control_mutex) { + mainmixer.msec_last_activity = mainmixer.msec_pos; + co_midi[noteNumber].get(0, "poly_pressure")[0] = pressure*(1.0/128.0); + polypressure[noteNumber] = pressure; + for (int i = 0; i < voices.length; i++) { + if (voices[i].active && voices[i].note == noteNumber) + voices[i].setPolyPressure(pressure); + } + } + } + + public int getPolyPressure(int noteNumber) { + synchronized (control_mutex) { + return polypressure[noteNumber]; + } + } + + public void setChannelPressure(int pressure) { + if (current_mixer != null) + current_mixer.setChannelPressure(pressure); + synchronized (control_mutex) { + mainmixer.msec_last_activity = mainmixer.msec_pos; + co_midi_channel_pressure[0] = pressure * (1.0 / 128.0); + channelpressure = pressure; + for (int i = 0; i < voices.length; i++) { + if (voices[i].active) + voices[i].setChannelPressure(pressure); + } + } + } + + public int getChannelPressure() { + synchronized (control_mutex) { + return channelpressure; + } + } + + protected void applyInstrumentCustomization() { + if (cds_control_connections == null + && cds_channelpressure_connections == null + && cds_polypressure_connections == null) { + return; + } + + ModelInstrument src_instrument = current_instrument.getSourceInstrument(); + ModelPerformer[] performers = src_instrument.getPerformers(); + ModelPerformer[] new_performers = new ModelPerformer[performers.length]; + for (int i = 0; i < new_performers.length; i++) { + ModelPerformer performer = performers[i]; + ModelPerformer new_performer = new ModelPerformer(); + new_performer.setName(performer.getName()); + new_performer.setExclusiveClass(performer.getExclusiveClass()); + new_performer.setKeyFrom(performer.getKeyFrom()); + new_performer.setKeyTo(performer.getKeyTo()); + new_performer.setVelFrom(performer.getVelFrom()); + new_performer.setVelTo(performer.getVelTo()); + new_performer.getOscillators().addAll(performer.getOscillators()); + new_performer.getConnectionBlocks().addAll( + performer.getConnectionBlocks()); + new_performers[i] = new_performer; + + List connblocks = + new_performer.getConnectionBlocks(); + + if (cds_control_connections != null) { + String cc = Integer.toString(cds_control_number); + Iterator iter = connblocks.iterator(); + while (iter.hasNext()) { + ModelConnectionBlock conn = iter.next(); + ModelSource[] sources = conn.getSources(); + boolean removeok = false; + if (sources != null) { + for (int j = 0; j < sources.length; j++) { + ModelSource src = sources[j]; + if ("midi_cc".equals(src.getIdentifier().getObject()) + && cc.equals(src.getIdentifier().getVariable())) { + removeok = true; + } + } + } + if (removeok) + iter.remove(); + } + for (int j = 0; j < cds_control_connections.length; j++) + connblocks.add(cds_control_connections[j]); + } + + if (cds_polypressure_connections != null) { + Iterator iter = connblocks.iterator(); + while (iter.hasNext()) { + ModelConnectionBlock conn = iter.next(); + ModelSource[] sources = conn.getSources(); + boolean removeok = false; + if (sources != null) { + for (int j = 0; j < sources.length; j++) { + ModelSource src = sources[j]; + if ("midi".equals(src.getIdentifier().getObject()) + && "poly_pressure".equals( + src.getIdentifier().getVariable())) { + removeok = true; + } + } + } + if (removeok) + iter.remove(); + } + for (int j = 0; j < cds_polypressure_connections.length; j++) + connblocks.add(cds_polypressure_connections[j]); + } + + + if (cds_channelpressure_connections != null) { + Iterator iter = connblocks.iterator(); + while (iter.hasNext()) { + ModelConnectionBlock conn = iter.next(); + ModelSource[] sources = conn.getSources(); + boolean removeok = false; + if (sources != null) { + for (int j = 0; j < sources.length; j++) { + ModelIdentifier srcid = sources[j].getIdentifier(); + if ("midi".equals(srcid.getObject()) && + "channel_pressure".equals(srcid.getVariable())) { + removeok = true; + } + } + } + if (removeok) + iter.remove(); + } + for (int j = 0; j < cds_channelpressure_connections.length; j++) + connblocks.add(cds_channelpressure_connections[j]); + } + + } + + current_instrument = new SoftInstrument(src_instrument, new_performers); + + } + + private ModelConnectionBlock[] createModelConnections(ModelIdentifier sid, + int[] destination, int[] range) { + + /* + controlled parameter (pp)|range (rr)| Description |Default + -------------------------|----------|-------------------------|------- + 00 Pitch Control | 28H..58H | -24..+24 semitones | 40H + 01 Filter Cutoff Control | 00H..7FH | -9600..+9450 cents | 40H + 02 Amplitude Control | 00H..7FH | 0..(127/64)*100 percent | 40H + 03 LFO Pitch Depth | 00H..7FH | 0..600 cents | 0 + 04 LFO Filter Depth | 00H..7FH | 0..2400 cents | 0 + 05 LFO Amplitude Depth | 00H..7FH | 0..100 percent | 0 + */ + + List conns = new ArrayList(); + + for (int i = 0; i < destination.length; i++) { + int d = destination[i]; + int r = range[i]; + if (d == 0) { + double scale = (r - 64) * 100; + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(sid, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + scale, + new ModelDestination( + new ModelIdentifier("osc", "pitch"))); + conns.add(conn); + + } + if (d == 1) { + double scale = (r / 64.0 - 1.0) * 9600.0; + ModelConnectionBlock conn; + if (scale > 0) { + conn = new ModelConnectionBlock( + new ModelSource(sid, + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + -scale, + new ModelDestination( + ModelDestination.DESTINATION_FILTER_FREQ)); + } else { + conn = new ModelConnectionBlock( + new ModelSource(sid, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + scale, + new ModelDestination( + ModelDestination.DESTINATION_FILTER_FREQ)); + } + conns.add(conn); + } + if (d == 2) { + final double scale = (r / 64.0); + ModelTransform mt = new ModelTransform() { + double s = scale; + public double transform(double value) { + if (s < 1) + value = s + (value * (1.0 - s)); + else if (s > 1) + value = 1 + (value * (s - 1.0)); + else + return 0; + return -((5.0 / 12.0) / Math.log(10)) * Math.log(value); + } + }; + + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(sid, mt), -960, + new ModelDestination(ModelDestination.DESTINATION_GAIN)); + conns.add(conn); + + } + if (d == 3) { + double scale = (r / 64.0 - 1.0) * 9600.0; + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(sid, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + scale, + new ModelDestination( + ModelDestination.DESTINATION_PITCH)); + conns.add(conn); + } + if (d == 4) { + double scale = (r / 128.0) * 2400.0; + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(sid, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + scale, + new ModelDestination( + ModelDestination.DESTINATION_FILTER_FREQ)); + conns.add(conn); + } + if (d == 5) { + final double scale = (r / 127.0); + + ModelTransform mt = new ModelTransform() { + double s = scale; + public double transform(double value) { + return -((5.0 / 12.0) / Math.log(10)) + * Math.log(1 - value * s); + } + }; + + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(sid, mt), + -960, + new ModelDestination( + ModelDestination.DESTINATION_GAIN)); + conns.add(conn); + } + } + + return conns.toArray(new ModelConnectionBlock[conns.size()]); + } + + public void mapPolyPressureToDestination(int[] destination, int[] range) { + current_instrument = null; + if (destination.length == 0) { + cds_polypressure_connections = null; + return; + } + cds_polypressure_connections + = createModelConnections( + new ModelIdentifier("midi", "poly_pressure"), + destination, range); + } + + public void mapChannelPressureToDestination(int[] destination, int[] range) { + current_instrument = null; + if (destination.length == 0) { + cds_channelpressure_connections = null; + return; + } + cds_channelpressure_connections + = createModelConnections( + new ModelIdentifier("midi", "channel_pressure"), + destination, range); + } + + public void mapControlToDestination(int control, int[] destination, int[] range) { + + if (!((control >= 0x01 && control <= 0x1F) + || (control >= 0x40 && control <= 0x5F))) { + cds_control_connections = null; + return; + } + + current_instrument = null; + cds_control_number = control; + if (destination.length == 0) { + cds_control_connections = null; + return; + } + cds_control_connections + = createModelConnections( + new ModelIdentifier("midi_cc", Integer.toString(control)), + destination, range); + } + + public void controlChangePerNote(int noteNumber, int controller, int value) { + +/* + CC# | nn | Name | vv | default | description +-----|------|-------------------------|----------------|------------|------------------------------- +7 |07H |Note Volume |00H-40H-7FH |40H |0-100-(127/64)*100(%)(Relative) +10 |0AH |*Pan |00H-7FH absolute|Preset Value|Left-Center-Right (absolute) +33-63|21-3FH|LSB for |01H-1FH | | +71 |47H |Timbre/Harmonic Intensity|00H-40H-7FH |40H (???) | +72 |48H |Release Time |00H-40H-7FH |40H (???) | +73 |49H |Attack Time |00H-40H-7FH |40H (???) | +74 |4AH |Brightness |00H-40H-7FH |40H (???) | +75 |4BH |Decay Time |00H-40H-7FH |40H (???) | +76 |4CH |Vibrato Rate |00H-40H-7FH |40H (???) | +77 |4DH |Vibrato Depth |00H-40H-7FH |40H (???) | +78 |4EH |Vibrato Delay |00H-40H-7FH |40H (???) | +91 |5BH |*Reverb Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute) +93 |5DH |*Chorus Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute) +120 |78H |**Fine Tuning |00H-40H-7FH |40H (???) | +121 |79H |**Coarse Tuning |00H-40H-7FH |40H (???) | +*/ + + if (keybasedcontroller_active == null) { + keybasedcontroller_active = new boolean[128][]; + keybasedcontroller_value = new double[128][]; + } + if (keybasedcontroller_active[noteNumber] == null) { + keybasedcontroller_active[noteNumber] = new boolean[128]; + Arrays.fill(keybasedcontroller_active[noteNumber], false); + keybasedcontroller_value[noteNumber] = new double[128]; + Arrays.fill(keybasedcontroller_value[noteNumber], 0); + } + + if (value == -1) { + keybasedcontroller_active[noteNumber][controller] = false; + } else { + keybasedcontroller_active[noteNumber][controller] = true; + keybasedcontroller_value[noteNumber][controller] = value / 128.0; + } + + if (controller < 120) { + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].controlChange(controller, -1); + } else if (controller == 120) { + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].rpnChange(1, -1); + } else if (controller == 121) { + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].rpnChange(2, -1); + } + + } + + public int getControlPerNote(int noteNumber, int controller) { + if (keybasedcontroller_active == null) + return -1; + if (keybasedcontroller_active[noteNumber] == null) + return -1; + if (!keybasedcontroller_active[noteNumber][controller]) + return -1; + return (int)(keybasedcontroller_value[noteNumber][controller] * 128); + } + + public void controlChange(int controller, int value) { + if (current_mixer != null) + current_mixer.controlChange(controller, value); + + synchronized (control_mutex) { + switch (controller) { + /* + Mapco_midi_rpn_rpn_i = new HashMap(); + Mapco_midi_rpn_rpn = new HashMap(); + Mapco_midi_nrpn_nrpn_i = new HashMap(); + Mapco_midi_nrpn_nrpn = new HashMap(); + */ + + case 5: + // This produce asin-like curve + // as described in General Midi Level 2 Specification, page 6 + double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5; + x = Math.pow(100000.0, x) / 100.0; // x is now cent/msec + // Convert x from cent/msec to key/controlbuffertime + x = x / 100.0; // x is now keys/msec + x = x * 1000.0; // x is now keys/sec + x = x / synthesizer.getControlRate(); // x is now keys/controlbuffertime + portamento_time = x; + break; + case 6: + case 38: + case 96: + case 97: + int val = 0; + if (nrpn_control != RPN_NULL_VALUE) { + int[] val_i = co_midi_nrpn_nrpn_i.get(nrpn_control); + if (val_i != null) + val = val_i[0]; + } + if (rpn_control != RPN_NULL_VALUE) { + int[] val_i = co_midi_rpn_rpn_i.get(rpn_control); + if (val_i != null) + val = val_i[0]; + } + + if (controller == 6) + val = (val & 127) + (value << 7); + else if (controller == 38) + val = (val & (127 << 7)) + value; + else if (controller == 96 || controller == 97) { + int step = 1; + if (rpn_control == 2 || rpn_control == 3 || rpn_control == 4) + step = 128; + if (controller == 96) + val += step; + if (controller == 97) + val -= step; + } + + if (nrpn_control != RPN_NULL_VALUE) + nrpnChange(nrpn_control, val); + if (rpn_control != RPN_NULL_VALUE) + rpnChange(rpn_control, val); + + break; + case 64: // Hold1 (Damper) (cc#64) + boolean on = value >= 64; + if (sustain != on) { + sustain = on; + if (!on) { + for (int i = 0; i < voices.length; i++) { + if (voices[i].active && voices[i].sustain && + voices[i].channel == channel) { + voices[i].sustain = false; + if (!voices[i].on) { + voices[i].on = true; + voices[i].noteOff(0); + } + } + } + } else { + for (int i = 0; i < voices.length; i++) + if (voices[i].active && voices[i].channel == channel) + voices[i].redamp(); + } + } + break; + case 65: + //allNotesOff(); + portamento = value >= 64; + portamento_lastnote[0] = -1; + /* + for (int i = 0; i < portamento_lastnote.length; i++) + portamento_lastnote[i] = -1; + */ + portamento_lastnote_ix = 0; + break; + case 66: // Sostenuto (cc#66) + on = value >= 64; + if (on) { + for (int i = 0; i < voices.length; i++) { + if (voices[i].active && voices[i].on && + voices[i].channel == channel) { + voices[i].sostenuto = true; + } + } + } + if (!on) { + for (int i = 0; i < voices.length; i++) { + if (voices[i].active && voices[i].sostenuto && + voices[i].channel == channel) { + voices[i].sostenuto = false; + if (!voices[i].on) { + voices[i].on = true; + voices[i].noteOff(0); + } + } + } + } + break; + case 84: + portamento_control_note = value; + break; + case 98: + nrpn_control = (nrpn_control & (127 << 7)) + value; + rpn_control = RPN_NULL_VALUE; + break; + case 99: + nrpn_control = (nrpn_control & 127) + (value << 7); + rpn_control = RPN_NULL_VALUE; + break; + case 100: + rpn_control = (rpn_control & (127 << 7)) + value; + nrpn_control = RPN_NULL_VALUE; + break; + case 101: + rpn_control = (rpn_control & 127) + (value << 7); + nrpn_control = RPN_NULL_VALUE; + break; + case 120: + allSoundOff(); + break; + case 121: + resetAllControllers(value == 127); + break; + case 122: + localControl(value >= 64); + break; + case 123: + allNotesOff(); + break; + case 124: + setOmni(false); + break; + case 125: + setOmni(true); + break; + case 126: + if (value == 1) + setMono(true); + break; + case 127: + setMono(false); + break; + + default: + break; + } + + co_midi_cc_cc[controller][0] = value * (1.0 / 128.0); + + if (controller == 0x00) { + bank = (bank & 127) + (value << 7); + return; + } + + if (controller == 0x20) { + bank = (bank & (127 << 7)) + value; + return; + } + + this.controller[controller] = value; + + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].controlChange(controller, value); + + } + } + + public int getController(int controller) { + synchronized (control_mutex) { + return this.controller[controller]; + } + } + + public void tuningChange(int program) { + tuningChange(0, program); + } + + public void tuningChange(int bank, int program) { + synchronized (control_mutex) { + tuning = synthesizer.getTuning(new Patch(bank, program)); + } + } + + public void programChange(int program) { + programChange(bank, program); + } + + public void programChange(int bank, int program) { + synchronized (control_mutex) { + mainmixer.msec_last_activity = mainmixer.msec_pos; + this.bank = bank; + this.program = program; + current_instrument = null; + } + } + + public int getProgram() { + synchronized (control_mutex) { + return program; + } + } + + public void setPitchBend(int bend) { + if (current_mixer != null) + current_mixer.setPitchBend(bend); + synchronized (control_mutex) { + mainmixer.msec_last_activity = mainmixer.msec_pos; + co_midi_pitch[0] = bend * (1.0 / 16384.0); + pitchbend = bend; + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].setPitchBend(bend); + } + } + + public int getPitchBend() { + synchronized (control_mutex) { + return pitchbend; + } + } + + public void nrpnChange(int controller, int value) { + + /* + System.out.println("(" + channel + ").nrpnChange(" + + Integer.toHexString(controller >> 7) + + " " + Integer.toHexString(controller & 127) + + ", " + Integer.toHexString(value >> 7) + + " " + Integer.toHexString(value & 127) + ")"); + */ + + if (synthesizer.getGeneralMidiMode() == 0) { + if (controller == (0x01 << 7) + (0x08)) // Vibrato Rate + controlChange(76, value >> 7); + if (controller == (0x01 << 7) + (0x09)) // Vibrato Depth + controlChange(77, value >> 7); + if (controller == (0x01 << 7) + (0x0A)) // Vibrato Delay + controlChange(78, value >> 7); + if (controller == (0x01 << 7) + (0x20)) // Brightness + controlChange(74, value >> 7); + if (controller == (0x01 << 7) + (0x21)) // Filter Resonance + controlChange(71, value >> 7); + if (controller == (0x01 << 7) + (0x63)) // Attack Time + controlChange(73, value >> 7); + if (controller == (0x01 << 7) + (0x64)) // Decay Time + controlChange(75, value >> 7); + if (controller == (0x01 << 7) + (0x66)) // Release Time + controlChange(72, value >> 7); + + if (controller >> 7 == 0x18) // Pitch coarse + controlChangePerNote(controller % 128, 120, value >> 7); + if (controller >> 7 == 0x1A) // Volume + controlChangePerNote(controller % 128, 7, value >> 7); + if (controller >> 7 == 0x1C) // Panpot + controlChangePerNote(controller % 128, 10, value >> 7); + if (controller >> 7 == 0x1D) // Reverb + controlChangePerNote(controller % 128, 91, value >> 7); + if (controller >> 7 == 0x1E) // Chorus + controlChangePerNote(controller % 128, 93, value >> 7); + } + + int[] val_i = co_midi_nrpn_nrpn_i.get(controller); + double[] val_d = co_midi_nrpn_nrpn.get(controller); + if (val_i == null) { + val_i = new int[1]; + co_midi_nrpn_nrpn_i.put(controller, val_i); + } + if (val_d == null) { + val_d = new double[1]; + co_midi_nrpn_nrpn.put(controller, val_d); + } + val_i[0] = value; + val_d[0] = val_i[0] * (1.0 / 16384.0); + + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].nrpnChange(controller, val_i[0]); + + } + + public void rpnChange(int controller, int value) { + + /* + System.out.println("(" + channel + ").rpnChange(" + + Integer.toHexString(controller >> 7) + + " " + Integer.toHexString(controller & 127) + + ", " + Integer.toHexString(value >> 7) + + " " + Integer.toHexString(value & 127) + ")"); + */ + + if (controller == 3) { + tuning_program = (value >> 7) & 127; + tuningChange(tuning_bank, tuning_program); + } + if (controller == 4) { + tuning_bank = (value >> 7) & 127; + } + + int[] val_i = co_midi_rpn_rpn_i.get(controller); + double[] val_d = co_midi_rpn_rpn.get(controller); + if (val_i == null) { + val_i = new int[1]; + co_midi_rpn_rpn_i.put(controller, val_i); + } + if (val_d == null) { + val_d = new double[1]; + co_midi_rpn_rpn.put(controller, val_d); + } + val_i[0] = value; + val_d[0] = val_i[0] * (1.0 / 16384.0); + + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + voices[i].rpnChange(controller, val_i[0]); + } + + public void resetAllControllers() { + resetAllControllers(false); + } + + public void resetAllControllers(boolean allControls) { + synchronized (control_mutex) { + mainmixer.msec_last_activity = mainmixer.msec_pos; + + for (int i = 0; i < 128; i++) { + setPolyPressure(i, 0); + } + setChannelPressure(0); + setPitchBend(8192); + for (int i = 0; i < 128; i++) { + if (!dontResetControls[i]) + controlChange(i, 0); + } + + controlChange(71, 64); // Filter Resonance + controlChange(72, 64); // Release Time + controlChange(73, 64); // Attack Time + controlChange(74, 64); // Brightness + controlChange(75, 64); // Decay Time + controlChange(76, 64); // Vibrato Rate + controlChange(77, 64); // Vibrato Depth + controlChange(78, 64); // Vibrato Delay + + controlChange(8, 64); // Balance + controlChange(11, 127); // Expression + controlChange(98, 127); // NRPN Null + controlChange(99, 127); // NRPN Null + controlChange(100, 127); // RPN = Null + controlChange(101, 127); // RPN = Null + + // see DLS 2.1 (Power-on Default Values) + if (allControls) { + + keybasedcontroller_active = null; + keybasedcontroller_value = null; + + controlChange(7, 100); // Volume + controlChange(10, 64); // Pan + controlChange(91, 40); // Reverb + + for (int controller : co_midi_rpn_rpn.keySet()) { + // don't reset tuning settings + if (controller != 3 && controller != 4) + rpnChange(controller, 0); + } + for (int controller : co_midi_nrpn_nrpn.keySet()) + nrpnChange(controller, 0); + rpnChange(0, 2 << 7); // Bitch Bend sensitivity + rpnChange(1, 64 << 7); // Channel fine tunning + rpnChange(2, 64 << 7); // Channel Coarse Tuning + rpnChange(5, 64); // Modulation Depth, +/- 50 cent + + tuning_bank = 0; + tuning_program = 0; + tuning = new SoftTuning(); + + } + + } + } + + public void allNotesOff() { + if (current_mixer != null) + current_mixer.allNotesOff(); + synchronized (control_mutex) { + for (int i = 0; i < voices.length; i++) + if (voices[i].on && voices[i].channel == channel + && voices[i].releaseTriggered == false) { + voices[i].noteOff(0); + } + } + } + + public void allSoundOff() { + if (current_mixer != null) + current_mixer.allSoundOff(); + synchronized (control_mutex) { + for (int i = 0; i < voices.length; i++) + if (voices[i].on && voices[i].channel == channel) + voices[i].soundOff(); + } + } + + public boolean localControl(boolean on) { + return false; + } + + public void setMono(boolean on) { + if (current_mixer != null) + current_mixer.setMono(on); + synchronized (control_mutex) { + allNotesOff(); + mono = on; + } + } + + public boolean getMono() { + synchronized (control_mutex) { + return mono; + } + } + + public void setOmni(boolean on) { + if (current_mixer != null) + current_mixer.setOmni(on); + allNotesOff(); + // Omni is not supported by GM2 + } + + public boolean getOmni() { + return false; + } + + public void setMute(boolean mute) { + if (current_mixer != null) + current_mixer.setMute(mute); + synchronized (control_mutex) { + this.mute = mute; + for (int i = 0; i < voices.length; i++) + if (voices[i].active && voices[i].channel == channel) + voices[i].setMute(mute); + } + } + + public boolean getMute() { + synchronized (control_mutex) { + return mute; + } + } + + public void setSolo(boolean soloState) { + if (current_mixer != null) + current_mixer.setSolo(soloState); + + synchronized (control_mutex) { + this.solo = soloState; + + boolean soloinuse = false; + for (SoftChannel c : synthesizer.channels) { + if (c.solo) { + soloinuse = true; + break; + } + } + + if (!soloinuse) { + for (SoftChannel c : synthesizer.channels) + c.setSoloMute(false); + return; + } + + for (SoftChannel c : synthesizer.channels) + c.setSoloMute(!c.solo); + + } + + } + + private void setSoloMute(boolean mute) { + synchronized (control_mutex) { + if (solomute == mute) + return; + this.solomute = mute; + for (int i = 0; i < voices.length; i++) + if (voices[i].active && voices[i].channel == channel) + voices[i].setSoloMute(solomute); + } + } + + public boolean getSolo() { + synchronized (control_mutex) { + return solo; + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftChannelProxy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftChannelProxy.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,202 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.MidiChannel; + +/** + * A MidiChannel proxy object used for external access to synthesizer internal + * channel objects. + * + * @author Karl Helgason + */ +public class SoftChannelProxy implements MidiChannel { + + private MidiChannel channel = null; + + public MidiChannel getChannel() { + return channel; + } + + public void setChannel(MidiChannel channel) { + this.channel = channel; + } + + public void allNotesOff() { + if (channel == null) + return; + channel.allNotesOff(); + } + + public void allSoundOff() { + if (channel == null) + return; + channel.allSoundOff(); + } + + public void controlChange(int controller, int value) { + if (channel == null) + return; + channel.controlChange(controller, value); + } + + public int getChannelPressure() { + if (channel == null) + return 0; + return channel.getChannelPressure(); + } + + public int getController(int controller) { + if (channel == null) + return 0; + return channel.getController(controller); + } + + public boolean getMono() { + if (channel == null) + return false; + return channel.getMono(); + } + + public boolean getMute() { + if (channel == null) + return false; + return channel.getMute(); + } + + public boolean getOmni() { + if (channel == null) + return false; + return channel.getOmni(); + } + + public int getPitchBend() { + if (channel == null) + return 8192; + return channel.getPitchBend(); + } + + public int getPolyPressure(int noteNumber) { + if (channel == null) + return 0; + return channel.getPolyPressure(noteNumber); + } + + public int getProgram() { + if (channel == null) + return 0; + return channel.getProgram(); + } + + public boolean getSolo() { + if (channel == null) + return false; + return channel.getSolo(); + } + + public boolean localControl(boolean on) { + if (channel == null) + return false; + return channel.localControl(on); + } + + public void noteOff(int noteNumber) { + if (channel == null) + return; + channel.noteOff(noteNumber); + } + + public void noteOff(int noteNumber, int velocity) { + if (channel == null) + return; + channel.noteOff(noteNumber, velocity); + } + + public void noteOn(int noteNumber, int velocity) { + if (channel == null) + return; + channel.noteOn(noteNumber, velocity); + } + + public void programChange(int program) { + if (channel == null) + return; + channel.programChange(program); + } + + public void programChange(int bank, int program) { + if (channel == null) + return; + channel.programChange(bank, program); + } + + public void resetAllControllers() { + if (channel == null) + return; + channel.resetAllControllers(); + } + + public void setChannelPressure(int pressure) { + if (channel == null) + return; + channel.setChannelPressure(pressure); + } + + public void setMono(boolean on) { + if (channel == null) + return; + channel.setMono(on); + } + + public void setMute(boolean mute) { + if (channel == null) + return; + channel.setMute(mute); + } + + public void setOmni(boolean on) { + if (channel == null) + return; + channel.setOmni(on); + } + + public void setPitchBend(int bend) { + if (channel == null) + return; + channel.setPitchBend(bend); + } + + public void setPolyPressure(int noteNumber, int pressure) { + if (channel == null) + return; + channel.setPolyPressure(noteNumber, pressure); + } + + public void setSolo(boolean soloState) { + if (channel == null) + return; + channel.setSolo(soloState); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftChorus.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftChorus.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,343 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.Arrays; + +/** + * A chorus effect made using LFO and variable delay. One for each channel + * (left,right), with different starting phase for stereo effect. + * + * @author Karl Helgason + */ +public class SoftChorus implements SoftAudioProcessor { + + private class VariableDelay { + + private float[] delaybuffer; + private int rovepos = 0; + private volatile float gain = 1; + private volatile float rgain = 0; + private volatile float delay = 0; + private float lastdelay = 0; + private volatile float feedback = 0; + + public VariableDelay(int maxbuffersize) { + delaybuffer = new float[maxbuffersize]; + } + + public void setDelay(float delay) { + this.delay = delay; + } + + public void setFeedBack(float feedback) { + this.feedback = feedback; + } + + public void setGain(float gain) { + this.gain = gain; + } + + public void setReverbSendGain(float rgain) { + this.rgain = rgain; + } + + public void processMix(float[] in, float[] out, float[] rout) { + float gain = this.gain; + float delay = this.delay; + float feedback = this.feedback; + + float[] delaybuffer = this.delaybuffer; + int len = in.length; + float delaydelta = (delay - lastdelay) / len; + int rnlen = delaybuffer.length; + int rovepos = this.rovepos; + + if (rout == null) + for (int i = 0; i < len; i++) { + float r = rovepos - (lastdelay + 2) + rnlen; + int ri = (int) r; + float s = r - ri; + float a = delaybuffer[ri % rnlen]; + float b = delaybuffer[(ri + 1) % rnlen]; + float o = a * (1 - s) + b * (s); + out[i] += o * gain; + delaybuffer[rovepos] = in[i] + o * feedback; + rovepos = (rovepos + 1) % rnlen; + lastdelay += delaydelta; + } + else + for (int i = 0; i < len; i++) { + float r = rovepos - (lastdelay + 2) + rnlen; + int ri = (int) r; + float s = r - ri; + float a = delaybuffer[ri % rnlen]; + float b = delaybuffer[(ri + 1) % rnlen]; + float o = a * (1 - s) + b * (s); + out[i] += o * gain; + rout[i] += o * rgain; + delaybuffer[rovepos] = in[i] + o * feedback; + rovepos = (rovepos + 1) % rnlen; + lastdelay += delaydelta; + } + this.rovepos = rovepos; + lastdelay = delay; + } + + public void processReplace(float[] in, float[] out, float[] rout) { + Arrays.fill(out, 0); + Arrays.fill(rout, 0); + processMix(in, out, rout); + } + } + + private class LFODelay { + + private volatile double c_cos_delta; + private volatile double c_sin_delta; + private double c_cos = 1; + private double c_sin = 0; + private double depth = 0; + private VariableDelay vdelay; + private double samplerate; + private double controlrate; + + public LFODelay(double samplerate, double controlrate) { + this.samplerate = samplerate; + this.controlrate = controlrate; + // vdelay = new VariableDelay((int)(samplerate*4)); + vdelay = new VariableDelay((int) ((this.depth + 10) * 2)); + + } + + public void setDepth(double depth) { + this.depth = depth * samplerate; + vdelay = new VariableDelay((int) ((this.depth + 10) * 2)); + } + + public void setRate(double rate) { + double g = (Math.PI * 2) * (rate / controlrate); + c_cos_delta = Math.cos(g); + c_sin_delta = Math.sin(g); + } + + public void setPhase(double phase) { + c_cos = Math.cos(phase); + c_sin = Math.sin(phase); + } + + public void setFeedBack(float feedback) { + vdelay.setFeedBack(feedback); + } + + public void setGain(float gain) { + vdelay.setGain(gain); + } + + public void setReverbSendGain(float rgain) { + vdelay.setReverbSendGain(rgain); + } + + public void processMix(float[] in, float[] out, float[] rout) { + c_cos = c_cos * c_cos_delta - c_sin * c_sin_delta; + c_sin = c_cos * c_sin_delta + c_sin * c_cos_delta; + vdelay.setDelay((float) (depth * 0.5 * (c_cos + 2))); + vdelay.processMix(in, out, rout); + } + + public void processReplace(float[] in, float[] out, float[] rout) { + c_cos = c_cos * c_cos_delta - c_sin * c_sin_delta; + c_sin = c_cos * c_sin_delta + c_sin * c_cos_delta; + vdelay.setDelay((float) (depth * 0.5 * (c_cos + 2))); + vdelay.processReplace(in, out, rout); + + } + } + private boolean mix = true; + private SoftAudioBuffer inputA; + private SoftAudioBuffer left; + private SoftAudioBuffer right; + private SoftAudioBuffer reverb; + private LFODelay vdelay1L; + private LFODelay vdelay1R; + private float rgain = 0; + private SoftSynthesizer synth; + private boolean dirty = true; + private double dirty_vdelay1L_rate; + private double dirty_vdelay1R_rate; + private double dirty_vdelay1L_depth; + private double dirty_vdelay1R_depth; + private float dirty_vdelay1L_feedback; + private float dirty_vdelay1R_feedback; + private float dirty_vdelay1L_reverbsendgain; + private float dirty_vdelay1R_reverbsendgain; + + public void init(SoftSynthesizer synth) { + this.synth = synth; + double samplerate = synth.getFormat().getSampleRate(); + double controlrate = synth.getControlRate(); + vdelay1L = new LFODelay(samplerate, controlrate); + vdelay1R = new LFODelay(samplerate, controlrate); + vdelay1L.setGain(1.0f); // % + vdelay1R.setGain(1.0f); // % + vdelay1L.setPhase(0.5 * Math.PI); + vdelay1R.setPhase(0); + + globalParameterControlChange(new int[]{0x01 * 128 + 0x02}, 0, 2); + } + + public void globalParameterControlChange(int[] slothpath, long param, + long value) { + if (slothpath.length == 1) { + if (slothpath[0] == 0x01 * 128 + 0x02) { + if (param == 0) { // Chorus Type + switch ((int)value) { + case 0: // Chorus 1 0 (0%) 3 (0.4Hz) 5 (1.9ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 0); + globalParameterControlChange(slothpath, 1, 3); + globalParameterControlChange(slothpath, 2, 5); + globalParameterControlChange(slothpath, 4, 0); + break; + case 1: // Chorus 2 5 (4%) 9 (1.1Hz) 19 (6.3ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 5); + globalParameterControlChange(slothpath, 1, 9); + globalParameterControlChange(slothpath, 2, 19); + globalParameterControlChange(slothpath, 4, 0); + break; + case 2: // Chorus 3 8 (6%) 3 (0.4Hz) 19 (6.3ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 8); + globalParameterControlChange(slothpath, 1, 3); + globalParameterControlChange(slothpath, 2, 19); + globalParameterControlChange(slothpath, 4, 0); + break; + case 3: // Chorus 4 16 (12%) 9 (1.1Hz) 16 (5.3ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 16); + globalParameterControlChange(slothpath, 1, 9); + globalParameterControlChange(slothpath, 2, 16); + globalParameterControlChange(slothpath, 4, 0); + break; + case 4: // FB Chorus 64 (49%) 2 (0.2Hz) 24 (7.8ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 64); + globalParameterControlChange(slothpath, 1, 2); + globalParameterControlChange(slothpath, 2, 24); + globalParameterControlChange(slothpath, 4, 0); + break; + case 5: // Flanger 112 (86%) 1 (0.1Hz) 5 (1.9ms) 0 (0%) + globalParameterControlChange(slothpath, 3, 112); + globalParameterControlChange(slothpath, 1, 1); + globalParameterControlChange(slothpath, 2, 5); + globalParameterControlChange(slothpath, 4, 0); + break; + default: + break; + } + } else if (param == 1) { // Mod Rate + dirty_vdelay1L_rate = (value * 0.122); + dirty_vdelay1R_rate = (value * 0.122); + dirty = true; + } else if (param == 2) { // Mod Depth + dirty_vdelay1L_depth = ((value + 1) / 3200.0); + dirty_vdelay1R_depth = ((value + 1) / 3200.0); + dirty = true; + } else if (param == 3) { // Feedback + dirty_vdelay1L_feedback = (value * 0.00763f); + dirty_vdelay1R_feedback = (value * 0.00763f); + dirty = true; + } + if (param == 4) { // Send to Reverb + rgain = value * 0.00787f; + dirty_vdelay1L_reverbsendgain = (value * 0.00787f); + dirty_vdelay1R_reverbsendgain = (value * 0.00787f); + dirty = true; + } + + } + } + } + + public void processControlLogic() { + if (dirty) { + dirty = false; + vdelay1L.setRate(dirty_vdelay1L_rate); + vdelay1R.setRate(dirty_vdelay1R_rate); + vdelay1L.setDepth(dirty_vdelay1L_depth); + vdelay1R.setDepth(dirty_vdelay1R_depth); + vdelay1L.setFeedBack(dirty_vdelay1L_feedback); + vdelay1R.setFeedBack(dirty_vdelay1R_feedback); + vdelay1L.setReverbSendGain(dirty_vdelay1L_reverbsendgain); + vdelay1R.setReverbSendGain(dirty_vdelay1R_reverbsendgain); + } + } + double silentcounter = 1000; + + public void processAudio() { + + if (inputA.isSilent()) { + silentcounter += 1 / synth.getControlRate(); + + if (silentcounter > 1) { + if (!mix) { + left.clear(); + right.clear(); + } + return; + } + } else + silentcounter = 0; + + float[] inputA = this.inputA.array(); + float[] left = this.left.array(); + float[] right = this.right == null ? null : this.right.array(); + float[] reverb = rgain != 0 ? this.reverb.array() : null; + + if (mix) { + vdelay1L.processMix(inputA, left, reverb); + if (right != null) + vdelay1R.processMix(inputA, right, reverb); + } else { + vdelay1L.processReplace(inputA, left, reverb); + if (right != null) + vdelay1R.processReplace(inputA, right, reverb); + } + } + + public void setInput(int pin, SoftAudioBuffer input) { + if (pin == 0) + inputA = input; + } + + public void setMixMode(boolean mix) { + this.mix = mix; + } + + public void setOutput(int pin, SoftAudioBuffer output) { + if (pin == 0) + left = output; + if (pin == 1) + right = output; + if (pin == 2) + reverb = output; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftControl.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,36 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * SoftControl are the basic controls + * used for control-rate processing. + * + * @author Karl Helgason + */ +public interface SoftControl { + + public double[] get(int instance, String name); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftCubicResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftCubicResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A resampler that uses third-order (cubic) interpolation. + * + * @author Karl Helgason + */ +public class SoftCubicResampler extends SoftAbstractResampler { + + public int getPadding() { + return 3; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0) { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float fix = ix - iix; + float y0 = in[iix - 1]; + float y1 = in[iix]; + float y2 = in[iix + 1]; + float y3 = in[iix + 2]; + float a0 = y3 - y2 + y1 - y0; + float a1 = y0 - y1 - a0; + float a2 = y2 - y0; + float a3 = y1; + //float fix2 = fix * fix; + //out[ox++] = (a0 * fix + a1) * fix2 + (a2 * fix + a3); + out[ox++] = ((a0 * fix + a1) * fix + a2) * fix + a3; + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float fix = ix - iix; + float y0 = in[iix - 1]; + float y1 = in[iix]; + float y2 = in[iix + 1]; + float y3 = in[iix + 2]; + float a0 = y3 - y2 + y1 - y0; + float a1 = y0 - y1 - a0; + float a2 = y2 - y0; + float a3 = y1; + //float fix2 = fix * fix; + //out[ox++] = (a0 * fix + a1) * fix2 + (a2 * fix + a3); + out[ox++] = ((a0 * fix + a1) * fix + a2) * fix + a3; + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftEnvelopeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftEnvelopeGenerator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,298 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * AHDSR control signal envelope generator. + * + * @author Karl Helgason + */ +public class SoftEnvelopeGenerator implements SoftProcess { + + public final static int EG_OFF = 0; + public final static int EG_DELAY = 1; + public final static int EG_ATTACK = 2; + public final static int EG_HOLD = 3; + public final static int EG_DECAY = 4; + public final static int EG_SUSTAIN = 5; + public final static int EG_RELEASE = 6; + public final static int EG_SHUTDOWN = 7; + public final static int EG_END = 8; + int max_count = 10; + int used_count = 0; + private int[] stage = new int[max_count]; + private int[] stage_ix = new int[max_count]; + private double[] stage_v = new double[max_count]; + private int[] stage_count = new int[max_count]; + private double[][] on = new double[max_count][1]; + private double[][] active = new double[max_count][1]; + private double[][] out = new double[max_count][1]; + private double[][] delay = new double[max_count][1]; + private double[][] attack = new double[max_count][1]; + private double[][] hold = new double[max_count][1]; + private double[][] decay = new double[max_count][1]; + private double[][] sustain = new double[max_count][1]; + private double[][] release = new double[max_count][1]; + private double[][] shutdown = new double[max_count][1]; + private double[][] release2 = new double[max_count][1]; + private double[][] attack2 = new double[max_count][1]; + private double[][] decay2 = new double[max_count][1]; + private double control_time = 0; + + public void reset() { + for (int i = 0; i < used_count; i++) { + stage[i] = 0; + on[i][0] = 0; + out[i][0] = 0; + delay[i][0] = 0; + attack[i][0] = 0; + hold[i][0] = 0; + decay[i][0] = 0; + sustain[i][0] = 0; + release[i][0] = 0; + shutdown[i][0] = 0; + attack2[i][0] = 0; + decay2[i][0] = 0; + release2[i][0] = 0; + } + used_count = 0; + } + + public void init(SoftSynthesizer synth) { + control_time = 1.0 / synth.getControlRate(); + processControlLogic(); + } + + public double[] get(int instance, String name) { + if (instance >= used_count) + used_count = instance + 1; + if (name == null) + return out[instance]; + if (name.equals("on")) + return on[instance]; + if (name.equals("active")) + return active[instance]; + if (name.equals("delay")) + return delay[instance]; + if (name.equals("attack")) + return attack[instance]; + if (name.equals("hold")) + return hold[instance]; + if (name.equals("decay")) + return decay[instance]; + if (name.equals("sustain")) + return sustain[instance]; + if (name.equals("release")) + return release[instance]; + if (name.equals("shutdown")) + return shutdown[instance]; + if (name.equals("attack2")) + return attack2[instance]; + if (name.equals("decay2")) + return decay2[instance]; + if (name.equals("release2")) + return release2[instance]; + + return null; + } + + public void processControlLogic() { + for (int i = 0; i < used_count; i++) { + + if (stage[i] == EG_END) + continue; + + if ((stage[i] > EG_OFF) && (stage[i] < EG_RELEASE)) { + if (on[i][0] < 0.5) { + if (on[i][0] < -0.5) { + stage_count[i] = (int)(Math.pow(2, + this.shutdown[i][0] / 1200.0) / control_time); + if (stage_count[i] < 0) + stage_count[i] = 0; + stage_v[i] = out[i][0]; + stage_ix[i] = 0; + stage[i] = EG_SHUTDOWN; + } else { + if ((release2[i][0] < 0.000001) && release[i][0] < 0 + && Double.isInfinite(release[i][0])) { + out[i][0] = 0; + active[i][0] = 0; + stage[i] = EG_END; + continue; + } + + stage_count[i] = (int)(Math.pow(2, + this.release[i][0] / 1200.0) / control_time); + stage_count[i] + += (int)(this.release2[i][0]/(control_time * 1000)); + if (stage_count[i] < 0) + stage_count[i] = 0; + // stage_v[i] = out[i][0]; + stage_ix[i] = 0; + + double m = 1 - out[i][0]; + stage_ix[i] = (int)(stage_count[i] * m); + + stage[i] = EG_RELEASE; + } + } + } + + switch (stage[i]) { + case EG_OFF: + active[i][0] = 1; + if (on[i][0] < 0.5) + break; + stage[i] = EG_DELAY; + stage_ix[i] = (int)(Math.pow(2, + this.delay[i][0] / 1200.0) / control_time); + if (stage_ix[i] < 0) + stage_ix[i] = 0; + case EG_DELAY: + if (stage_ix[i] == 0) { + double attack = this.attack[i][0]; + double attack2 = this.attack2[i][0]; + + if (attack2 < 0.000001 + && (attack < 0 && Double.isInfinite(attack))) { + out[i][0] = 1; + stage[i] = EG_HOLD; + stage_count[i] = (int)(Math.pow(2, + this.hold[i][0] / 1200.0) / control_time); + stage_ix[i] = 0; + } else { + stage[i] = EG_ATTACK; + stage_count[i] = (int)(Math.pow(2, + attack / 1200.0) / control_time); + stage_count[i] += (int)(attack2 / (control_time * 1000)); + if (stage_count[i] < 0) + stage_count[i] = 0; + stage_ix[i] = 0; + } + } else + stage_ix[i]--; + break; + case EG_ATTACK: + stage_ix[i]++; + if (stage_ix[i] >= stage_count[i]) { + out[i][0] = 1; + stage[i] = EG_HOLD; + } else { + // CONVEX attack + double a = ((double)stage_ix[i]) / ((double)stage_count[i]); + a = 1 + ((40.0 / 96.0) / Math.log(10)) * Math.log(a); + if (a < 0) + a = 0; + else if (a > 1) + a = 1; + out[i][0] = a; + } + break; + case EG_HOLD: + stage_ix[i]++; + if (stage_ix[i] >= stage_count[i]) { + stage[i] = EG_DECAY; + stage_count[i] = (int)(Math.pow(2, + this.decay[i][0] / 1200.0) / control_time); + stage_count[i] += (int)(this.decay2[i][0]/(control_time*1000)); + if (stage_count[i] < 0) + stage_count[i] = 0; + stage_ix[i] = 0; + } + break; + case EG_DECAY: + stage_ix[i]++; + double sustain = this.sustain[i][0] * (1.0 / 1000.0); + if (stage_ix[i] >= stage_count[i]) { + out[i][0] = sustain; + stage[i] = EG_SUSTAIN; + if (sustain < 0.001) { + out[i][0] = 0; + active[i][0] = 0; + stage[i] = EG_END; + } + } else { + double m = ((double)stage_ix[i]) / ((double)stage_count[i]); + out[i][0] = (1 - m) + sustain * m; + } + break; + case EG_SUSTAIN: + break; + case EG_RELEASE: + stage_ix[i]++; + if (stage_ix[i] >= stage_count[i]) { + out[i][0] = 0; + active[i][0] = 0; + stage[i] = EG_END; + } else { + double m = ((double)stage_ix[i]) / ((double)stage_count[i]); + out[i][0] = (1 - m); // *stage_v[i]; + + if (on[i][0] < -0.5) { + stage_count[i] = (int)(Math.pow(2, + this.shutdown[i][0] / 1200.0) / control_time); + if (stage_count[i] < 0) + stage_count[i] = 0; + stage_v[i] = out[i][0]; + stage_ix[i] = 0; + stage[i] = EG_SHUTDOWN; + } + + // re-damping + if (on[i][0] > 0.5) { + sustain = this.sustain[i][0] * (1.0 / 1000.0); + if (out[i][0] > sustain) { + stage[i] = EG_DECAY; + stage_count[i] = (int)(Math.pow(2, + this.decay[i][0] / 1200.0) / control_time); + stage_count[i] += + (int)(this.decay2[i][0]/(control_time*1000)); + if (stage_count[i] < 0) + stage_count[i] = 0; + m = (out[i][0] - 1) / (sustain - 1); + stage_ix[i] = (int) (stage_count[i] * m); + } + } + + } + break; + case EG_SHUTDOWN: + stage_ix[i]++; + if (stage_ix[i] >= stage_count[i]) { + out[i][0] = 0; + active[i][0] = 0; + stage[i] = EG_END; + } else { + double m = ((double)stage_ix[i]) / ((double)stage_count[i]); + out[i][0] = (1 - m) * stage_v[i]; + } + break; + default: + break; + } + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftFilter.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,614 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Infinite impulse response (IIR) filter class. + * + * The filters where implemented and adapted using algorithms from musicdsp.org + * archive: 1-RC and C filter, Simple 2-pole LP LP and HP filter, biquad, + * tweaked butterworth RBJ Audio-EQ-Cookbook, EQ filter kookbook + * + * @author Karl Helgason + */ +public class SoftFilter { + + public static int FILTERTYPE_LP6 = 0x00; + public static int FILTERTYPE_LP12 = 0x01; + public static int FILTERTYPE_HP12 = 0x11; + public static int FILTERTYPE_BP12 = 0x21; + public static int FILTERTYPE_NP12 = 0x31; + public static int FILTERTYPE_LP24 = 0x03; + public static int FILTERTYPE_HP24 = 0x13; + + // + // 0x0 = 1st-order, 6 dB/oct + // 0x1 = 2nd-order, 12 dB/oct + // 0x2 = 3rd-order, 18 dB/oct + // 0x3 = 4th-order, 24 db/oct + // + // 0x00 = LP, Low Pass Filter + // 0x10 = HP, High Pass Filter + // 0x20 = BP, Band Pass Filter + // 0x30 = NP, Notch or Band Elimination Filter + // + private int filtertype = FILTERTYPE_LP6; + private float samplerate; + private float x1; + private float x2; + private float y1; + private float y2; + private float xx1; + private float xx2; + private float yy1; + private float yy2; + private float a0; + private float a1; + private float a2; + private float b1; + private float b2; + private float q; + private float gain = 1; + private float wet = 0; + private float last_wet = 0; + private float last_a0; + private float last_a1; + private float last_a2; + private float last_b1; + private float last_b2; + private float last_q; + private float last_gain; + private boolean last_set = false; + private double cutoff = 44100; + private double resonancedB = 0; + private boolean dirty = true; + + public SoftFilter(float samplerate) { + this.samplerate = samplerate; + dirty = true; + } + + public void setFrequency(double cent) { + if (cutoff == cent) + return; + cutoff = cent; + dirty = true; + } + + public void setResonance(double db) { + if (resonancedB == db) + return; + resonancedB = db; + dirty = true; + } + + public void reset() { + dirty = true; + last_set = false; + x1 = 0; + x2 = 0; + y1 = 0; + y2 = 0; + xx1 = 0; + xx2 = 0; + yy1 = 0; + yy2 = 0; + wet = 0.0f; + gain = 1.0f; + a0 = 0; + a1 = 0; + a2 = 0; + b1 = 0; + b2 = 0; + } + + public void setFilterType(int filtertype) { + this.filtertype = filtertype; + } + + public void processAudio(SoftAudioBuffer sbuffer) { + if (filtertype == FILTERTYPE_LP6) + filter1(sbuffer); + if (filtertype == FILTERTYPE_LP12) + filter2(sbuffer); + if (filtertype == FILTERTYPE_HP12) + filter2(sbuffer); + if (filtertype == FILTERTYPE_BP12) + filter2(sbuffer); + if (filtertype == FILTERTYPE_NP12) + filter2(sbuffer); + if (filtertype == FILTERTYPE_LP24) + filter4(sbuffer); + if (filtertype == FILTERTYPE_HP24) + filter4(sbuffer); + } + + public void filter4(SoftAudioBuffer sbuffer) { + + float[] buffer = sbuffer.array(); + + if (dirty) { + filter2calc(); + dirty = false; + } + if (!last_set) { + last_a0 = a0; + last_a1 = a1; + last_a2 = a2; + last_b1 = b1; + last_b2 = b2; + last_gain = gain; + last_wet = wet; + last_set = true; + } + + if (wet > 0 || last_wet > 0) { + + int len = buffer.length; + float a0 = this.last_a0; + float a1 = this.last_a1; + float a2 = this.last_a2; + float b1 = this.last_b1; + float b2 = this.last_b2; + float gain = this.last_gain; + float wet = this.last_wet; + float a0_delta = (this.a0 - this.last_a0) / len; + float a1_delta = (this.a1 - this.last_a1) / len; + float a2_delta = (this.a2 - this.last_a2) / len; + float b1_delta = (this.b1 - this.last_b1) / len; + float b2_delta = (this.b2 - this.last_b2) / len; + float gain_delta = (this.gain - this.last_gain) / len; + float wet_delta = (this.wet - this.last_wet) / len; + float x1 = this.x1; + float x2 = this.x2; + float y1 = this.y1; + float y2 = this.y2; + float xx1 = this.xx1; + float xx2 = this.xx2; + float yy1 = this.yy1; + float yy2 = this.yy2; + + if (wet_delta != 0) { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + a1 += a1_delta; + a2 += a2_delta; + b1 += b1_delta; + b2 += b2_delta; + gain += gain_delta; + wet += wet_delta; + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + float xx = (y * gain) * wet + (x) * (1 - wet); + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2); + buffer[i] = (yy * gain) * wet + (xx) * (1 - wet); + xx2 = xx1; + xx1 = xx; + yy2 = yy1; + yy1 = yy; + } + } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0 + && b1_delta == 0 && b2_delta == 0) { + for (int i = 0; i < len; i++) { + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + float xx = (y * gain) * wet + (x) * (1 - wet); + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2); + buffer[i] = (yy * gain) * wet + (xx) * (1 - wet); + xx2 = xx1; + xx1 = xx; + yy2 = yy1; + yy1 = yy; + } + } else { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + a1 += a1_delta; + a2 += a2_delta; + b1 += b1_delta; + b2 += b2_delta; + gain += gain_delta; + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + float xx = (y * gain) * wet + (x) * (1 - wet); + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + float yy = (a0*xx + a1*xx1 + a2*xx2 - b1*yy1 - b2*yy2); + buffer[i] = (yy * gain) * wet + (xx) * (1 - wet); + xx2 = xx1; + xx1 = xx; + yy2 = yy1; + yy1 = yy; + } + } + + if (Math.abs(x1) < 1.0E-8) + x1 = 0; + if (Math.abs(x2) < 1.0E-8) + x2 = 0; + if (Math.abs(y1) < 1.0E-8) + y1 = 0; + if (Math.abs(y2) < 1.0E-8) + y2 = 0; + this.x1 = x1; + this.x2 = x2; + this.y1 = y1; + this.y2 = y2; + this.xx1 = xx1; + this.xx2 = xx2; + this.yy1 = yy1; + this.yy2 = yy2; + } + + this.last_a0 = this.a0; + this.last_a1 = this.a1; + this.last_a2 = this.a2; + this.last_b1 = this.b1; + this.last_b2 = this.b2; + this.last_gain = this.gain; + this.last_wet = this.wet; + + } + + private double sinh(double x) { + return (Math.exp(x) - Math.exp(-x)) * 0.5; + } + + public void filter2calc() { + + double resonancedB = this.resonancedB; + if (resonancedB < 0) + resonancedB = 0; // Negative dB are illegal. + if (resonancedB > 30) + resonancedB = 30; // At least 22.5 dB is needed. + if (filtertype == FILTERTYPE_LP24 || filtertype == FILTERTYPE_HP24) + resonancedB *= 0.6; + + if (filtertype == FILTERTYPE_BP12) { + wet = 1; + double r = (cutoff / samplerate); + if (r > 0.45) + r = 0.45; + + double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20)); + + double omega = 2 * Math.PI * r; + double cs = Math.cos(omega); + double sn = Math.sin(omega); + double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn * 2)); + + double b0 = alpha; + double b1 = 0; + double b2 = -alpha; + double a0 = 1 + alpha; + double a1 = -2 * cs; + double a2 = 1 - alpha; + + double cf = 1.0 / a0; + this.b1 = (float) (a1 * cf); + this.b2 = (float) (a2 * cf); + this.a0 = (float) (b0 * cf); + this.a1 = (float) (b1 * cf); + this.a2 = (float) (b2 * cf); + } + + if (filtertype == FILTERTYPE_NP12) { + wet = 1; + double r = (cutoff / samplerate); + if (r > 0.45) + r = 0.45; + + double bandwidth = Math.PI * Math.pow(10.0, -(resonancedB / 20)); + + double omega = 2 * Math.PI * r; + double cs = Math.cos(omega); + double sn = Math.sin(omega); + double alpha = sn * sinh((Math.log(2)*bandwidth*omega) / (sn*2)); + + double b0 = 1; + double b1 = -2 * cs; + double b2 = 1; + double a0 = 1 + alpha; + double a1 = -2 * cs; + double a2 = 1 - alpha; + + double cf = 1.0 / a0; + this.b1 = (float)(a1 * cf); + this.b2 = (float)(a2 * cf); + this.a0 = (float)(b0 * cf); + this.a1 = (float)(b1 * cf); + this.a2 = (float)(b2 * cf); + } + + if (filtertype == FILTERTYPE_LP12 || filtertype == FILTERTYPE_LP24) { + double r = (cutoff / samplerate); + if (r > 0.45) { + if (wet == 0) { + if (resonancedB < 0.00001) + wet = 0.0f; + else + wet = 1.0f; + } + r = 0.45; + } else + wet = 1.0f; + + double c = 1.0 / (Math.tan(Math.PI * r)); + double csq = c * c; + double resonance = Math.pow(10.0, -(resonancedB / 20)); + double q = Math.sqrt(2.0f) * resonance; + double a0 = 1.0 / (1.0 + (q * c) + (csq)); + double a1 = 2.0 * a0; + double a2 = a0; + double b1 = (2.0 * a0) * (1.0 - csq); + double b2 = a0 * (1.0 - (q * c) + csq); + + this.a0 = (float)a0; + this.a1 = (float)a1; + this.a2 = (float)a2; + this.b1 = (float)b1; + this.b2 = (float)b2; + + } + + if (filtertype == FILTERTYPE_HP12 || filtertype == FILTERTYPE_HP24) { + double r = (cutoff / samplerate); + if (r > 0.45) + r = 0.45; + if (r < 0.0001) + r = 0.0001; + wet = 1.0f; + double c = (Math.tan(Math.PI * (r))); + double csq = c * c; + double resonance = Math.pow(10.0, -(resonancedB / 20)); + double q = Math.sqrt(2.0f) * resonance; + double a0 = 1.0 / (1.0 + (q * c) + (csq)); + double a1 = -2.0 * a0; + double a2 = a0; + double b1 = (2.0 * a0) * (csq - 1.0); + double b2 = a0 * (1.0 - (q * c) + csq); + + this.a0 = (float)a0; + this.a1 = (float)a1; + this.a2 = (float)a2; + this.b1 = (float)b1; + this.b2 = (float)b2; + + } + + } + + public void filter2(SoftAudioBuffer sbuffer) { + + float[] buffer = sbuffer.array(); + + if (dirty) { + filter2calc(); + dirty = false; + } + if (!last_set) { + last_a0 = a0; + last_a1 = a1; + last_a2 = a2; + last_b1 = b1; + last_b2 = b2; + last_q = q; + last_gain = gain; + last_wet = wet; + last_set = true; + } + + if (wet > 0 || last_wet > 0) { + + int len = buffer.length; + float a0 = this.last_a0; + float a1 = this.last_a1; + float a2 = this.last_a2; + float b1 = this.last_b1; + float b2 = this.last_b2; + float gain = this.last_gain; + float wet = this.last_wet; + float a0_delta = (this.a0 - this.last_a0) / len; + float a1_delta = (this.a1 - this.last_a1) / len; + float a2_delta = (this.a2 - this.last_a2) / len; + float b1_delta = (this.b1 - this.last_b1) / len; + float b2_delta = (this.b2 - this.last_b2) / len; + float gain_delta = (this.gain - this.last_gain) / len; + float wet_delta = (this.wet - this.last_wet) / len; + float x1 = this.x1; + float x2 = this.x2; + float y1 = this.y1; + float y2 = this.y2; + + if (wet_delta != 0) { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + a1 += a1_delta; + a2 += a2_delta; + b1 += b1_delta; + b2 += b2_delta; + gain += gain_delta; + wet += wet_delta; + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + buffer[i] = (y * gain) * wet + (x) * (1 - wet); + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + } else if (a0_delta == 0 && a1_delta == 0 && a2_delta == 0 + && b1_delta == 0 && b2_delta == 0) { + for (int i = 0; i < len; i++) { + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + buffer[i] = y * gain; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + } else { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + a1 += a1_delta; + a2 += a2_delta; + b1 += b1_delta; + b2 += b2_delta; + gain += gain_delta; + float x = buffer[i]; + float y = (a0*x + a1*x1 + a2*x2 - b1*y1 - b2*y2); + buffer[i] = y * gain; + x2 = x1; + x1 = x; + y2 = y1; + y1 = y; + } + } + + if (Math.abs(x1) < 1.0E-8) + x1 = 0; + if (Math.abs(x2) < 1.0E-8) + x2 = 0; + if (Math.abs(y1) < 1.0E-8) + y1 = 0; + if (Math.abs(y2) < 1.0E-8) + y2 = 0; + this.x1 = x1; + this.x2 = x2; + this.y1 = y1; + this.y2 = y2; + } + + this.last_a0 = this.a0; + this.last_a1 = this.a1; + this.last_a2 = this.a2; + this.last_b1 = this.b1; + this.last_b2 = this.b2; + this.last_q = this.q; + this.last_gain = this.gain; + this.last_wet = this.wet; + + } + + public void filter1calc() { + if (cutoff < 120) + cutoff = 120; + double c = (7.0 / 6.0) * Math.PI * 2 * cutoff / samplerate; + if (c > 1) + c = 1; + a0 = (float)(Math.sqrt(1 - Math.cos(c)) * Math.sqrt(0.5 * Math.PI)); + if (resonancedB < 0) + resonancedB = 0; + if (resonancedB > 20) + resonancedB = 20; + q = (float)(Math.sqrt(0.5) * Math.pow(10.0, -(resonancedB / 20))); + gain = (float)Math.pow(10, -((resonancedB)) / 40.0); + if (wet == 0.0f) + if (resonancedB > 0.00001 || c < 0.9999999) + wet = 1.0f; + } + + public void filter1(SoftAudioBuffer sbuffer) { + + float[] buffer = sbuffer.array(); + + if (dirty) { + filter1calc(); + dirty = false; + } + if (!last_set) { + last_a0 = a0; + last_q = q; + last_gain = gain; + last_wet = wet; + last_set = true; + } + + if (wet > 0 || last_wet > 0) { + + int len = buffer.length; + float a0 = this.last_a0; + float q = this.last_q; + float gain = this.last_gain; + float wet = this.last_wet; + float a0_delta = (this.a0 - this.last_a0) / len; + float q_delta = (this.q - this.last_q) / len; + float gain_delta = (this.gain - this.last_gain) / len; + float wet_delta = (this.wet - this.last_wet) / len; + float y2 = this.y2; + float y1 = this.y1; + + if (wet_delta != 0) { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + q += q_delta; + gain += gain_delta; + wet += wet_delta; + y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; + y2 = (1 - q * a0) * y2 + (a0) * y1; + buffer[i] = y2 * gain * wet + buffer[i] * (1 - wet); + } + } else if (a0_delta == 0 && q_delta == 0) { + for (int i = 0; i < len; i++) { + y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; + y2 = (1 - q * a0) * y2 + (a0) * y1; + buffer[i] = y2 * gain; + } + } else { + for (int i = 0; i < len; i++) { + a0 += a0_delta; + q += q_delta; + gain += gain_delta; + y1 = (1 - q * a0) * y1 - (a0) * y2 + (a0) * buffer[i]; + y2 = (1 - q * a0) * y2 + (a0) * y1; + buffer[i] = y2 * gain; + } + } + + if (Math.abs(y2) < 1.0E-8) + y2 = 0; + if (Math.abs(y1) < 1.0E-8) + y1 = 0; + this.y2 = y2; + this.y1 = y1; + } + + this.last_a0 = this.a0; + this.last_q = this.q; + this.last_gain = this.gain; + this.last_wet = this.wet; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; + +/** + * Software synthesizer internal instrument. + * + * @author Karl Helgason + */ +public class SoftInstrument extends Instrument { + + private SoftPerformer[] performers; + private ModelPerformer[] modelperformers; + private Object data; + private ModelInstrument ins; + + public SoftInstrument(ModelInstrument ins) { + super(ins.getSoundbank(), ins.getPatch(), ins.getName(), + ins.getDataClass()); + if (!(ins instanceof ModelInstrument)) { + throw new IllegalArgumentException( + "Instrument doesn't implement ModelInstrument interface!"); + } + data = ins.getData(); + this.ins = ins; + initPerformers(((ModelInstrument)ins).getPerformers()); + } + + public SoftInstrument(ModelInstrument ins, + ModelPerformer[] overrideperformers) { + super(ins.getSoundbank(), ins.getPatch(), ins.getName(), + ins.getDataClass()); + if (!(ins instanceof ModelInstrument)) { + throw new IllegalArgumentException( + "Instrument doesn't implement ModelInstrument interface!"); + } + data = ins.getData(); + this.ins = ins; + initPerformers(overrideperformers); + } + + private void initPerformers(ModelPerformer[] modelperformers) { + this.modelperformers = modelperformers; + performers = new SoftPerformer[modelperformers.length]; + for (int i = 0; i < modelperformers.length; i++) + performers[i] = new SoftPerformer(modelperformers[i]); + } + + public ModelDirector getDirector(MidiChannel channel, + ModelDirectedPlayer player) { + return ins.getDirector(modelperformers, channel, player); + } + + public ModelInstrument getSourceInstrument() { + return ins; + } + + public Object getData() { + return data; + } + + public SoftPerformer[] getPerformers() { + return performers; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftJitterCorrector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftJitterCorrector.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,267 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; + +/** + * A jitter corrector to be used with SoftAudioPusher. + * + * @author Karl Helgason + */ +public class SoftJitterCorrector extends AudioInputStream { + + private static class JitterStream extends InputStream { + + static int MAX_BUFFER_SIZE = 1048576; + boolean active = true; + Thread thread; + AudioInputStream stream; + // Cyclic buffer + int writepos = 0; + int readpos = 0; + byte[][] buffers; + byte[] nullbuff; + + // Adapative Drift Statistics + int w_count = 1000; + int w_min_tol = 2; + int w_max_tol = 10; + int w = 0; + int w_min = -1; + // Current read buffer + int bbuffer_pos = 0; + int bbuffer_max = 0; + byte[] bbuffer = null; + + public byte[] nextReadBuffer() { + synchronized (buffers) { + if (writepos > readpos) { + int w_m = writepos - readpos; + if (w_m < w_min) + w_min = w_m; + + int buffpos = readpos; + readpos++; + return buffers[buffpos % buffers.length]; + } + w_min = -1; + w = w_count - 1; + } + while (true) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + //e.printStackTrace(); + return null; + } + synchronized (buffers) { + if (writepos > readpos) { + w = 0; + w_min = -1; + w = w_count - 1; + int buffpos = readpos; + readpos++; + return buffers[buffpos % buffers.length]; + } + } + } + } + + public byte[] nextWriteBuffer() { + synchronized (buffers) { + return buffers[writepos % buffers.length]; + } + } + + public void commit() { + synchronized (buffers) { + writepos++; + if ((writepos - readpos) > buffers.length) { + int newsize = (writepos - readpos) + 10; + newsize = Math.max(buffers.length * 2, newsize); + buffers = new byte[newsize][buffers[0].length]; + } + } + } + + public JitterStream(AudioInputStream s, int buffersize, + int smallbuffersize) { + this.w_count = 10 * (buffersize / smallbuffersize); + if (w_count < 100) + w_count = 100; + this.buffers + = new byte[(buffersize/smallbuffersize)+10][smallbuffersize]; + this.bbuffer_max = MAX_BUFFER_SIZE / smallbuffersize; + this.nullbuff = new byte[smallbuffersize]; + this.stream = s; + + + Runnable runnable = new Runnable() { + + public void run() { + AudioFormat format = stream.getFormat(); + int bufflen = buffers[0].length; + int frames = bufflen / format.getFrameSize(); + long nanos = (long) (frames * 1000000000.0 + / format.getSampleRate()); + long now = System.nanoTime(); + long next = now + nanos; + int correction = 0; + while (true) { + synchronized (JitterStream.this) { + if (!active) + break; + } + int curbuffsize; + synchronized (buffers) { + curbuffsize = writepos - readpos; + if (correction == 0) { + w++; + if (w_min != Integer.MAX_VALUE) { + if (w == w_count) { + correction = 0; + if (w_min < w_min_tol) { + correction = (w_min_tol + w_max_tol) + / 2 - w_min; + } + if (w_min > w_max_tol) { + correction = (w_min_tol + w_max_tol) + / 2 - w_min; + } + w = 0; + w_min = Integer.MAX_VALUE; + } + } + } + } + while (curbuffsize > bbuffer_max) { + synchronized (buffers) { + curbuffsize = writepos - readpos; + } + synchronized (JitterStream.this) { + if (!active) + break; + } + try { + Thread.sleep(1); + } catch (InterruptedException e) { + //e.printStackTrace(); + } + } + + if (correction < 0) + correction++; + else { + byte[] buff = nextWriteBuffer(); + try { + stream.read(buff, 0, buff.length); + } catch (IOException e1) { + //e1.printStackTrace(); + } + commit(); + } + + if (correction > 0) { + correction--; + next = System.nanoTime() + nanos; + continue; + } + long wait = next - System.nanoTime(); + if (wait > 0) { + try { + Thread.sleep(wait / 1000000L); + } catch (InterruptedException e) { + //e.printStackTrace(); + } + } + next += nanos; + } + } + }; + + thread = new Thread(runnable); + thread.setPriority(Thread.MAX_PRIORITY); + thread.start(); + } + + public void close() throws IOException { + synchronized (this) { + active = false; + } + try { + thread.join(); + } catch (InterruptedException e) { + //e.printStackTrace(); + } + stream.close(); + } + + public int read() throws IOException { + byte[] b = new byte[1]; + if (read(b) == -1) + return -1; + return b[0] & 0xFF; + } + + public void fillBuffer() { + bbuffer = nextReadBuffer(); + bbuffer_pos = 0; + } + + public int read(byte[] b, int off, int len) { + if (bbuffer == null) + fillBuffer(); + int bbuffer_len = bbuffer.length; + int offlen = off + len; + while (off < offlen) { + if (available() == 0) + fillBuffer(); + else { + byte[] bbuffer = this.bbuffer; + int bbuffer_pos = this.bbuffer_pos; + while (off < offlen && bbuffer_pos < bbuffer_len) + b[off++] = bbuffer[bbuffer_pos++]; + this.bbuffer_pos = bbuffer_pos; + } + } + return len; + } + + public int available() { + return bbuffer.length - bbuffer_pos; + } + } + + public SoftJitterCorrector(AudioInputStream stream, int buffersize, + int smallbuffersize) { + super(new JitterStream(stream, buffersize, smallbuffersize), + stream.getFormat(), stream.getFrameLength()); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftLanczosResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftLanczosResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Lanczos interpolation resampler. + * + * @author Karl Helgason + */ +public class SoftLanczosResampler extends SoftAbstractResampler { + + double[] din; + float[][] sinc_table; + int sinc_table_fsize = 2000; + int sinc_table_size = 5; + int sinc_table_center = sinc_table_size / 2; + + public SoftLanczosResampler() { + super(); + sinc_table = new float[sinc_table_fsize][]; + for (int i = 0; i < sinc_table_fsize; i++) { + sinc_table[i] = sincTable(sinc_table_size, -i + / ((float) sinc_table_fsize)); + } + } + + // Normalized sinc function + public static double sinc(double x) { + return (x == 0.0) ? 1.0 : Math.sin(Math.PI * x) / (Math.PI * x); + } + + // Generate sinc table + public static float[] sincTable(int size, float offset) { + int center = size / 2; + float[] w = new float[size]; + for (int k = 0; k < size; k++) { + float x = (-center + k + offset); + if (x < -2 || x > 2) + w[k] = 0; + else if (x == 0) + w[k] = 1; + else { + w[k] = (float)(2.0 * Math.sin(Math.PI * x) + * Math.sin(Math.PI * x / 2.0) + / ((Math.PI * x) * (Math.PI * x))); + } + } + return w; + } + + public int getPadding() // must be at least half of sinc_table_size + { + return sinc_table_size / 2 + 2; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + + if (pitchstep == 0) { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float[] sinc_table + = this.sinc_table[(int) ((ix - iix) * sinc_table_fsize)]; + int xx = iix - sinc_table_center; + float y = 0; + for (int i = 0; i < sinc_table_size; i++, xx++) + y += in[xx] * sinc_table[i]; + out[ox++] = y; + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float[] sinc_table + = this.sinc_table[(int) ((ix - iix) * sinc_table_fsize)]; + int xx = iix - sinc_table_center; + float y = 0; + for (int i = 0; i < sinc_table_size; i++, xx++) + y += in[xx] * sinc_table[i]; + out[ox++] = y; + + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftLimiter.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,191 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A simple look-ahead volume limiter with very fast attack and fast release. + * This filter is used for preventing clipping. + * + * @author Karl Helgason + */ +public class SoftLimiter implements SoftAudioProcessor { + + float lastmax = 0; + float gain = 1; + float[] temp_bufferL; + float[] temp_bufferR; + boolean mix = false; + SoftAudioBuffer bufferL; + SoftAudioBuffer bufferR; + SoftAudioBuffer bufferLout; + SoftAudioBuffer bufferRout; + SoftSynthesizer synth; + + public void init(SoftSynthesizer synth) { + this.synth = synth; + } + + public void setInput(int pin, SoftAudioBuffer input) { + if (pin == 0) + bufferL = input; + if (pin == 1) + bufferR = input; + } + + public void setOutput(int pin, SoftAudioBuffer output) { + if (pin == 0) + bufferLout = output; + if (pin == 1) + bufferRout = output; + } + + public void setMixMode(boolean mix) { + this.mix = mix; + } + + public void globalParameterControlChange(int[] slothpath, long param, + long value) { + } + + double silentcounter = 0; + + public void processAudio() { + if (this.bufferL.isSilent() + && (this.bufferR == null || this.bufferR.isSilent())) { + silentcounter += 1 / synth.getControlRate(); + + if (silentcounter > 60) { + if (!mix) { + bufferLout.clear(); + bufferRout.clear(); + } + return; + } + } else + silentcounter = 0; + + float[] bufferL = this.bufferL.array(); + float[] bufferR = this.bufferR == null ? null : this.bufferR.array(); + float[] bufferLout = this.bufferLout.array(); + float[] bufferRout = this.bufferRout == null + ? null : this.bufferRout.array(); + + if (temp_bufferL == null || temp_bufferL.length < bufferL.length) + temp_bufferL = new float[bufferL.length]; + if (bufferR != null) + if (temp_bufferR == null || temp_bufferR.length < bufferR.length) + temp_bufferR = new float[bufferR.length]; + + float max = 0; + int len = bufferL.length; + + if (bufferR == null) { + for (int i = 0; i < len; i++) { + if (bufferL[i] > max) + max = bufferL[i]; + if (-bufferL[i] > max) + max = -bufferL[i]; + } + } else { + for (int i = 0; i < len; i++) { + if (bufferL[i] > max) + max = bufferL[i]; + if (bufferR[i] > max) + max = bufferR[i]; + if (-bufferL[i] > max) + max = -bufferL[i]; + if (-bufferR[i] > max) + max = -bufferR[i]; + } + } + + float lmax = lastmax; + lastmax = max; + if (lmax > max) + max = lmax; + + float newgain = 1; + if (max > 0.99f) + newgain = 0.99f / max; + else + newgain = 1; + + if (newgain > gain) + newgain = (newgain + gain * 9) / 10f; + + float gaindelta = (newgain - gain) / len; + if (mix) { + if (bufferR == null) { + for (int i = 0; i < len; i++) { + gain += gaindelta; + float bL = bufferL[i]; + float tL = temp_bufferL[i]; + temp_bufferL[i] = bL; + bufferLout[i] += tL * gain; + } + } else { + for (int i = 0; i < len; i++) { + gain += gaindelta; + float bL = bufferL[i]; + float bR = bufferR[i]; + float tL = temp_bufferL[i]; + float tR = temp_bufferR[i]; + temp_bufferL[i] = bL; + temp_bufferR[i] = bR; + bufferLout[i] += tL * gain; + bufferRout[i] += tR * gain; + } + } + + } else { + if (bufferR == null) { + for (int i = 0; i < len; i++) { + gain += gaindelta; + float bL = bufferL[i]; + float tL = temp_bufferL[i]; + temp_bufferL[i] = bL; + bufferLout[i] = tL * gain; + } + } else { + for (int i = 0; i < len; i++) { + gain += gaindelta; + float bL = bufferL[i]; + float bR = bufferR[i]; + float tL = temp_bufferL[i]; + float tR = temp_bufferR[i]; + temp_bufferL[i] = bL; + temp_bufferR[i] = bR; + bufferLout[i] = tL * gain; + bufferRout[i] = tR * gain; + } + } + + } + gain = newgain; + } + + public void processControlLogic() { + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A resampler that uses first-order (linear) interpolation. + * + * @author Karl Helgason + */ +public class SoftLinearResampler extends SoftAbstractResampler { + + public int getPadding() { + return 2; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float fix = ix - iix; + float i = in[iix]; + out[ox++] = i + (in[iix + 1] - i) * fix; + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float fix = ix - iix; + float i = in[iix]; + out[ox++] = i + (in[iix + 1] - i) * fix; + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftLinearResampler2.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A resampler that uses first-order (linear) interpolation. + * + * This one doesn't perform float to int casting inside the processing loop. + * + * @author Karl Helgason + */ +public class SoftLinearResampler2 extends SoftAbstractResampler { + + public int getPadding() { + return 2; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + + // Check if we have do anything + if (!(ix < ix_end && ox < ox_end)) + return; + + // 15 bit shift was choosed because + // it resulted in no drift between p_ix and ix. + int p_ix = (int) (ix * (1 << 15)); + int p_ix_end = (int) (ix_end * (1 << 15)); + int p_pitch = (int) (pitch * (1 << 15)); + // Pitch needs to recalculated + // to ensure no drift between p_ix and ix. + pitch = p_pitch * (1f / (1 << 15)); + + if (pitchstep == 0f) { + + // To reduce + // while (p_ix < p_ix_end && ox < ox_end) + // into + // while (ox < ox_end) + // We need to calculate new ox_end value. + int p_ix_len = p_ix_end - p_ix; + int p_mod = p_ix_len % p_pitch; + if (p_mod != 0) + p_ix_len += p_pitch - p_mod; + int ox_end2 = ox + p_ix_len / p_pitch; + if (ox_end2 < ox_end) + ox_end = ox_end2; + + while (ox < ox_end) { + int iix = p_ix >> 15; + float fix = ix - iix; + float i = in[iix]; + out[ox++] = i + (in[iix + 1] - i) * fix; + p_ix += p_pitch; + ix += pitch; + } + + } else { + + int p_pitchstep = (int) (pitchstep * (1 << 15)); + pitchstep = p_pitchstep * (1f / (1 << 15)); + + while (p_ix < p_ix_end && ox < ox_end) { + int iix = p_ix >> 15; + float fix = ix - iix; + float i = in[iix]; + out[ox++] = i + (in[iix + 1] - i) * fix; + ix += pitch; + p_ix += p_pitch; + pitch += pitchstep; + p_pitch += p_pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftLowFrequencyOscillator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftLowFrequencyOscillator.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,122 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * LFO control signal generator. + * + * @author Karl Helgason + */ +public class SoftLowFrequencyOscillator implements SoftProcess { + + private int max_count = 10; + private int used_count = 0; + private double[][] out = new double[max_count][1]; + private double[][] delay = new double[max_count][1]; + private double[][] delay2 = new double[max_count][1]; + private double[][] freq = new double[max_count][1]; + private int[] delay_counter = new int[max_count]; + private double[] sin_phase = new double[max_count]; + private double[] sin_stepfreq = new double[max_count]; + private double[] sin_step = new double[max_count]; + private double control_time = 0; + private double sin_factor = 0; + private static double PI2 = 2.0 * Math.PI; + + public void reset() { + for (int i = 0; i < used_count; i++) { + out[i][0] = 0; + delay[i][0] = 0; + delay2[i][0] = 0; + freq[i][0] = 0; + delay_counter[i] = 0; + sin_phase[i] = 0; + sin_stepfreq[i] = 0; + sin_step[i] = 0; + } + used_count = 0; + } + + public void init(SoftSynthesizer synth) { + control_time = 1.0 / synth.getControlRate(); + sin_factor = control_time * 2 * Math.PI; + for (int i = 0; i < used_count; i++) { + delay_counter[i] = (int)(Math.pow(2, + this.delay[i][0] / 1200.0) / control_time); + delay_counter[i] += (int)(delay2[i][0] / (control_time * 1000)); + } + processControlLogic(); + } + + public void processControlLogic() { + for (int i = 0; i < used_count; i++) { + if (delay_counter[i] > 0) { + delay_counter[i]--; + out[i][0] = 0.5; + } else { + double f = freq[i][0]; + + if (sin_stepfreq[i] != f) { + sin_stepfreq[i] = f; + double fr = 440.0 * Math.exp( + (f - 6900.0) * (Math.log(2) / 1200.0)); + sin_step[i] = fr * sin_factor; + } + /* + double fr = 440.0 * Math.pow(2.0, + (freq[i][0] - 6900.0) / 1200.0); + sin_phase[i] += fr * sin_factor; + */ + /* + sin_phase[i] += sin_step[i]; + while (sin_phase[i] > PI2) + sin_phase[i] -= PI2; + out[i][0] = 0.5 + Math.sin(sin_phase[i]) * 0.5; + */ + double p = sin_phase[i]; + p += sin_step[i]; + while (p > PI2) + p -= PI2; + out[i][0] = 0.5 + Math.sin(p) * 0.5; + sin_phase[i] = p; + + } + } + } + + public double[] get(int instance, String name) { + if (instance >= used_count) + used_count = instance + 1; + if (name == null) + return out[instance]; + if (name.equals("delay")) + return delay[instance]; + if (name.equals("delay2")) + return delay2[instance]; + if (name.equals("freq")) + return freq[instance]; + return null; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftMainMixer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftMainMixer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,943 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeMap; +import java.util.Map.Entry; + +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Patch; +import javax.sound.midi.ShortMessage; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; + +/** + * Software synthesizer main audio mixer. + * + * @author Karl Helgason + */ +public class SoftMainMixer { + + public final static int CHANNEL_LEFT = 0; + public final static int CHANNEL_RIGHT = 1; + public final static int CHANNEL_EFFECT1 = 2; + public final static int CHANNEL_EFFECT2 = 3; + public final static int CHANNEL_EFFECT3 = 4; + public final static int CHANNEL_EFFECT4 = 5; + public final static int CHANNEL_LEFT_DRY = 10; + public final static int CHANNEL_RIGHT_DRY = 11; + public final static int CHANNEL_SCRATCH1 = 12; + public final static int CHANNEL_SCRATCH2 = 13; + public final static int CHANNEL_CHANNELMIXER_LEFT = 14; + public final static int CHANNEL_CHANNELMIXER_RIGHT = 15; + protected boolean active_sensing_on = false; + protected long msec_last_activity = -1; + protected long msec_pos = 0; + protected boolean readfully = true; + private Object control_mutex; + private SoftSynthesizer synth; + private int nrofchannels = 2; + private SoftVoice[] voicestatus = null; + private SoftAudioBuffer[] buffers; + private SoftAudioProcessor reverb; + private SoftAudioProcessor chorus; + private SoftAudioProcessor agc; + private long msec_buffer_len = 0; + protected TreeMap midimessages = new TreeMap(); + double finetuning = 0; + double coarsetuning = 0; + double last_volume_left = 1.0; + double last_volume_right = 1.0; + private double[] co_master_balance = new double[1]; + private double[] co_master_volume = new double[1]; + private double[] co_master_coarse_tuning = new double[1]; + private double[] co_master_fine_tuning = new double[1]; + private AudioInputStream ais; + private Set registeredMixers = null; + private Set stoppedMixers = null; + private ModelChannelMixer[] cur_registeredMixers = null; + protected SoftControl co_master = new SoftControl() { + + double[] balance = co_master_balance; + double[] volume = co_master_volume; + double[] coarse_tuning = co_master_coarse_tuning; + double[] fine_tuning = co_master_fine_tuning; + + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("balance")) + return balance; + if (name.equals("volume")) + return volume; + if (name.equals("coarse_tuning")) + return coarse_tuning; + if (name.equals("fine_tuning")) + return fine_tuning; + return null; + } + }; + + private void processSystemExclusiveMessage(byte[] data) { + synchronized (synth.control_mutex) { + msec_last_activity = msec_pos; + + // Universal Non-Real-Time SysEx + if ((data[1] & 0xFF) == 0x7E) { + int deviceID = data[2] & 0xFF; + if (deviceID == 0x7F || deviceID == synth.getDeviceID()) { + int subid1 = data[3] & 0xFF; + int subid2; + switch (subid1) { + case 0x08: // MIDI Tuning Standard + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // BULK TUNING DUMP + { + // http://www.midi.org/about-midi/tuning.shtml + SoftTuning tuning = synth.getTuning(new Patch(0, + data[5] & 0xFF)); + tuning.load(data); + break; + } + case 0x04: // KEY-BASED TUNING DUMP + case 0x05: // SCALE/OCTAVE TUNING DUMP, 1 byte format + case 0x06: // SCALE/OCTAVE TUNING DUMP, 2 byte format + case 0x07: // SINGLE NOTE TUNING CHANGE (NON REAL-TIME) + // (BANK) + { + // http://www.midi.org/about-midi/tuning_extens.shtml + SoftTuning tuning = synth.getTuning(new Patch( + data[5] & 0xFF, data[6] & 0xFF)); + tuning.load(data); + break; + } + case 0x08: // scale/octave tuning 1-byte form (Non + // Real-Time) + case 0x09: // scale/octave tuning 2-byte form (Non + // Real-Time) + { + // http://www.midi.org/about-midi/tuning-scale.shtml + SoftTuning tuning = new SoftTuning(data); + int channelmask = (data[5] & 0xFF) * 16384 + + (data[6] & 0xFF) * 128 + (data[7] & 0xFF); + SoftChannel[] channels = synth.channels; + for (int i = 0; i < channels.length; i++) + if ((channelmask & (1 << i)) != 0) + channels[i].tuning = tuning; + break; + } + default: + break; + } + break; + case 0x09: // General Midi Message + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // General Midi 1 On + synth.setGeneralMidiMode(1); + reset(); + break; + case 0x02: // General Midi Off + synth.setGeneralMidiMode(0); + reset(); + break; + case 0x03: // General MidI Level 2 On + synth.setGeneralMidiMode(2); + reset(); + break; + default: + break; + } + break; + case 0x0A: // DLS Message + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // DLS On + if (synth.getGeneralMidiMode() == 0) + synth.setGeneralMidiMode(1); + synth.voice_allocation_mode = 1; + reset(); + break; + case 0x02: // DLS Off + synth.setGeneralMidiMode(0); + synth.voice_allocation_mode = 0; + reset(); + break; + case 0x03: // DLS Static Voice Allocation Off + synth.voice_allocation_mode = 0; + break; + case 0x04: // DLS Static Voice Allocation On + synth.voice_allocation_mode = 1; + break; + default: + break; + } + break; + + default: + break; + } + } + } + + // Universal Real-Time SysEx + if ((data[1] & 0xFF) == 0x7F) { + int deviceID = data[2] & 0xFF; + if (deviceID == 0x7F || deviceID == synth.getDeviceID()) { + int subid1 = data[3] & 0xFF; + int subid2; + switch (subid1) { + case 0x04: // Device Control + + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // Master Volume + case 0x02: // Master Balane + case 0x03: // Master fine tuning + case 0x04: // Master coarse tuning + int val = (data[5] & 0x7F) + + ((data[6] & 0x7F) * 128); + if (subid2 == 0x01) + setVolume(val); + else if (subid2 == 0x02) + setBalance(val); + else if (subid2 == 0x03) + setFineTuning(val); + else if (subid2 == 0x04) + setCoarseTuning(val); + break; + case 0x05: // Global Parameter Control + int ix = 5; + int slotPathLen = (data[ix++] & 0xFF); + int paramWidth = (data[ix++] & 0xFF); + int valueWidth = (data[ix++] & 0xFF); + int[] slotPath = new int[slotPathLen]; + for (int i = 0; i < slotPathLen; i++) { + int msb = (data[ix++] & 0xFF); + int lsb = (data[ix++] & 0xFF); + slotPath[i] = msb * 128 + lsb; + } + int paramCount = (data.length - 1 - ix) + / (paramWidth + valueWidth); + long[] params = new long[paramCount]; + long[] values = new long[paramCount]; + for (int i = 0; i < paramCount; i++) { + values[i] = 0; + for (int j = 0; j < paramWidth; j++) + params[i] = params[i] * 128 + + (data[ix++] & 0xFF); + for (int j = 0; j < valueWidth; j++) + values[i] = values[i] * 128 + + (data[ix++] & 0xFF); + + } + globalParameterControlChange(slotPath, params, values); + break; + default: + break; + } + break; + + case 0x08: // MIDI Tuning Standard + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x02: // SINGLE NOTE TUNING CHANGE (REAL-TIME) + { + // http://www.midi.org/about-midi/tuning.shtml + SoftTuning tuning = synth.getTuning(new Patch(0, + data[5] & 0xFF)); + tuning.load(data); + SoftVoice[] voices = synth.getVoices(); + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + if (voices[i].tuning == tuning) + voices[i].updateTuning(tuning); + break; + } + case 0x07: // SINGLE NOTE TUNING CHANGE (REAL-TIME) + // (BANK) + { + // http://www.midi.org/about-midi/tuning_extens.shtml + SoftTuning tuning = synth.getTuning(new Patch( + data[5] & 0xFF, data[6] & 0xFF)); + tuning.load(data); + SoftVoice[] voices = synth.getVoices(); + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + if (voices[i].tuning == tuning) + voices[i].updateTuning(tuning); + break; + } + case 0x08: // scale/octave tuning 1-byte form + //(Real-Time) + case 0x09: // scale/octave tuning 2-byte form + // (Real-Time) + { + // http://www.midi.org/about-midi/tuning-scale.shtml + SoftTuning tuning = new SoftTuning(data); + int channelmask = (data[5] & 0xFF) * 16384 + + (data[6] & 0xFF) * 128 + (data[7] & 0xFF); + SoftChannel[] channels = synth.channels; + for (int i = 0; i < channels.length; i++) + if ((channelmask & (1 << i)) != 0) + channels[i].tuning = tuning; + SoftVoice[] voices = synth.getVoices(); + for (int i = 0; i < voices.length; i++) + if (voices[i].active) + if ((channelmask & (1 << (voices[i].channel))) != 0) + voices[i].updateTuning(tuning); + break; + } + default: + break; + } + break; + case 0x09: // Control Destination Settings + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // Channel Pressure + { + int[] destinations = new int[(data.length - 7) / 2]; + int[] ranges = new int[(data.length - 7) / 2]; + int ix = 0; + for (int j = 6; j < data.length - 1; j += 2) { + destinations[ix] = data[j] & 0xFF; + ranges[ix] = data[j + 1] & 0xFF; + ix++; + } + int channel = data[5] & 0xFF; + SoftChannel softchannel = synth.channels[channel]; + softchannel.mapChannelPressureToDestination( + destinations, ranges); + break; + } + case 0x02: // Poly Pressure + { + int[] destinations = new int[(data.length - 7) / 2]; + int[] ranges = new int[(data.length - 7) / 2]; + int ix = 0; + for (int j = 6; j < data.length - 1; j += 2) { + destinations[ix] = data[j] & 0xFF; + ranges[ix] = data[j + 1] & 0xFF; + ix++; + } + int channel = data[5] & 0xFF; + SoftChannel softchannel = synth.channels[channel]; + softchannel.mapPolyPressureToDestination( + destinations, ranges); + break; + } + case 0x03: // Control Change + { + int[] destinations = new int[(data.length - 7) / 2]; + int[] ranges = new int[(data.length - 7) / 2]; + int ix = 0; + for (int j = 7; j < data.length - 1; j += 2) { + destinations[ix] = data[j] & 0xFF; + ranges[ix] = data[j + 1] & 0xFF; + ix++; + } + int channel = data[5] & 0xFF; + SoftChannel softchannel = synth.channels[channel]; + int control = data[6] & 0xFF; + softchannel.mapControlToDestination(control, + destinations, ranges); + break; + } + default: + break; + } + break; + + case 0x0A: // Key Based Instrument Control + { + subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // Basic Message + int channel = data[5] & 0xFF; + int keynumber = data[6] & 0xFF; + SoftChannel softchannel = synth.channels[channel]; + for (int j = 7; j < data.length - 1; j += 2) { + int controlnumber = data[j] & 0xFF; + int controlvalue = data[j + 1] & 0xFF; + softchannel.controlChangePerNote(keynumber, + controlnumber, controlvalue); + } + break; + default: + break; + } + break; + } + default: + break; + } + } + } + + } + } + + private void processMessages(long timeStamp) { + Iterator> iter = midimessages.entrySet().iterator(); + while (iter.hasNext()) { + Entry entry = iter.next(); + if (entry.getKey() > (timeStamp + 100)) + return; + processMessage(entry.getValue()); + iter.remove(); + } + } + + protected void processAudioBuffers() { + for (int i = 0; i < buffers.length; i++) { + buffers[i].clear(); + } + + double volume_left; + double volume_right; + + ModelChannelMixer[] act_registeredMixers; + + // perform control logic + synchronized (control_mutex) { + + processMessages(msec_pos); + + if (active_sensing_on) { + // Active Sensing + // if no message occurs for max 1000 ms + // then do AllSoundOff on all channels + if ((msec_pos - msec_last_activity) > 1000000) { + active_sensing_on = false; + for (SoftChannel c : synth.channels) + c.allSoundOff(); + } + + } + + for (int i = 0; i < voicestatus.length; i++) + if (voicestatus[i].active) + voicestatus[i].processControlLogic(); + msec_pos += msec_buffer_len; + + double volume = co_master_volume[0]; + volume_left = volume; + volume_right = volume; + + double balance = co_master_balance[0]; + if (balance > 0.5) + volume_left *= (1 - balance) * 2; + else + volume_right *= balance * 2; + + chorus.processControlLogic(); + reverb.processControlLogic(); + agc.processControlLogic(); + + if (cur_registeredMixers == null) { + if (registeredMixers != null) { + cur_registeredMixers = + new ModelChannelMixer[registeredMixers.size()]; + registeredMixers.toArray(cur_registeredMixers); + } + } + + act_registeredMixers = cur_registeredMixers; + if (act_registeredMixers != null) + if (act_registeredMixers.length == 0) + act_registeredMixers = null; + + } + + if (act_registeredMixers != null) { + + // Reroute default left,right output + // to channelmixer left,right input/output + SoftAudioBuffer leftbak = buffers[CHANNEL_LEFT]; + SoftAudioBuffer rightbak = buffers[CHANNEL_RIGHT]; + buffers[CHANNEL_LEFT] = buffers[CHANNEL_CHANNELMIXER_LEFT]; + buffers[CHANNEL_RIGHT] = buffers[CHANNEL_CHANNELMIXER_LEFT]; + + int bufferlen = buffers[CHANNEL_LEFT].getSize(); + + float[][] cbuffer = new float[nrofchannels][]; + cbuffer[0] = buffers[CHANNEL_LEFT].array(); + if (nrofchannels != 1) + cbuffer[1] = buffers[CHANNEL_RIGHT].array(); + + float[][] obuffer = new float[nrofchannels][]; + obuffer[0] = leftbak.array(); + if (nrofchannels != 1) + obuffer[1] = rightbak.array(); + + for (ModelChannelMixer cmixer : act_registeredMixers) { + for (int i = 0; i < cbuffer.length; i++) + Arrays.fill(cbuffer[i], 0); + boolean hasactivevoices = false; + for (int i = 0; i < voicestatus.length; i++) + if (voicestatus[i].active) + if (voicestatus[i].channelmixer == cmixer) { + voicestatus[i].processAudioLogic(buffers); + hasactivevoices = true; + } + if (!cmixer.process(cbuffer, 0, bufferlen)) { + synchronized (control_mutex) { + registeredMixers.remove(cmixer); + cur_registeredMixers = null; + } + } + + for (int i = 0; i < cbuffer.length; i++) { + float[] cbuff = cbuffer[i]; + float[] obuff = obuffer[i]; + for (int j = 0; j < bufferlen; j++) + obuff[j] += cbuff[j]; + } + + if (!hasactivevoices) { + synchronized (control_mutex) { + if (stoppedMixers != null) { + if (stoppedMixers.contains(cmixer)) { + stoppedMixers.remove(cmixer); + cmixer.stop(); + } + } + } + } + + } + + buffers[CHANNEL_LEFT] = leftbak; + buffers[CHANNEL_RIGHT] = rightbak; + + } + + for (int i = 0; i < voicestatus.length; i++) + if (voicestatus[i].active) + if (voicestatus[i].channelmixer == null) + voicestatus[i].processAudioLogic(buffers); + + // Run effects + if (synth.chorus_on) + chorus.processAudio(); + + if (synth.reverb_on) + reverb.processAudio(); + + if (nrofchannels == 1) + volume_left = (volume_left + volume_right) / 2; + + // Set Volume / Balance + if (last_volume_left != volume_left || last_volume_right != volume_right) { + float[] left = buffers[CHANNEL_LEFT].array(); + float[] right = buffers[CHANNEL_RIGHT].array(); + int bufferlen = buffers[CHANNEL_LEFT].getSize(); + + float amp; + float amp_delta; + amp = (float)(last_volume_left * last_volume_left); + amp_delta = (float)((volume_left * volume_left - amp) / bufferlen); + for (int i = 0; i < bufferlen; i++) { + amp += amp_delta; + left[i] *= amp; + } + if (nrofchannels != 1) { + amp = (float)(last_volume_right * last_volume_right); + amp_delta = (float)((volume_right*volume_right - amp) / bufferlen); + for (int i = 0; i < bufferlen; i++) { + amp += amp_delta; + right[i] *= volume_right; + } + } + last_volume_left = volume_left; + last_volume_right = volume_right; + + } else { + if (volume_left != 1.0 || volume_right != 1.0) { + float[] left = buffers[CHANNEL_LEFT].array(); + float[] right = buffers[CHANNEL_RIGHT].array(); + int bufferlen = buffers[CHANNEL_LEFT].getSize(); + float amp; + amp = (float) (volume_left * volume_left); + for (int i = 0; i < bufferlen; i++) + left[i] *= amp; + if (nrofchannels != 1) { + amp = (float)(volume_right * volume_right); + for (int i = 0; i < bufferlen; i++) + right[i] *= amp; + } + + } + } + + if (synth.agc_on) + agc.processAudio(); + + } + + public void stopMixer(ModelChannelMixer mixer) { + if (stoppedMixers == null) + stoppedMixers = new HashSet(); + stoppedMixers.add(mixer); + } + + public void registerMixer(ModelChannelMixer mixer) { + if (registeredMixers == null) + registeredMixers = new HashSet(); + registeredMixers.add(mixer); + cur_registeredMixers = null; + } + + public SoftMainMixer(SoftSynthesizer synth) { + this.synth = synth; + + msec_pos = 0; + + co_master_balance[0] = 0.5; + co_master_volume[0] = 1; + co_master_coarse_tuning[0] = 0.5; + co_master_fine_tuning[0] = 0.5; + + msec_buffer_len = (long) (1000000.0 / synth.getControlRate()); + + nrofchannels = synth.getFormat().getChannels(); + + int buffersize = (int) (synth.getFormat().getSampleRate() + / synth.getControlRate()); + + control_mutex = synth.control_mutex; + buffers = new SoftAudioBuffer[16]; + for (int i = 0; i < buffers.length; i++) { + buffers[i] = new SoftAudioBuffer(buffersize, synth.getFormat()); + } + voicestatus = synth.getVoices(); + + reverb = new SoftReverb(); + chorus = new SoftChorus(); + agc = new SoftLimiter(); + + reverb.init(synth); + chorus.init(synth); + agc.init(synth); + + reverb.setMixMode(true); + chorus.setMixMode(true); + agc.setMixMode(false); + + chorus.setInput(0, buffers[CHANNEL_EFFECT2]); + chorus.setOutput(0, buffers[CHANNEL_LEFT]); + if (nrofchannels != 1) + chorus.setOutput(1, buffers[CHANNEL_RIGHT]); + chorus.setOutput(2, buffers[CHANNEL_EFFECT1]); + + reverb.setInput(0, buffers[CHANNEL_EFFECT1]); + reverb.setOutput(0, buffers[CHANNEL_LEFT]); + if (nrofchannels != 1) + reverb.setOutput(1, buffers[CHANNEL_RIGHT]); + + agc.setInput(0, buffers[CHANNEL_LEFT]); + if (nrofchannels != 1) + agc.setInput(1, buffers[CHANNEL_RIGHT]); + agc.setOutput(0, buffers[CHANNEL_LEFT]); + if (nrofchannels != 1) + agc.setOutput(1, buffers[CHANNEL_RIGHT]); + + InputStream in = new InputStream() { + + private SoftAudioBuffer[] buffers = SoftMainMixer.this.buffers; + private int nrofchannels + = SoftMainMixer.this.synth.getFormat().getChannels(); + private int buffersize = buffers[0].getSize(); + private byte[] bbuffer = new byte[buffersize + * (SoftMainMixer.this.synth.getFormat() + .getSampleSizeInBits() / 8) + * nrofchannels]; + private int bbuffer_pos = 0; + private byte[] single = new byte[1]; + + public void fillBuffer() { + processAudioBuffers(); + for (int i = 0; i < nrofchannels; i++) + buffers[i].get(bbuffer, i); + bbuffer_pos = 0; + } + + public int read(byte[] b, int off, int len) { + int bbuffer_len = bbuffer.length; + int offlen = off + len; + int orgoff = off; + byte[] bbuffer = this.bbuffer; + while (off < offlen) { + if (available() == 0) + fillBuffer(); + else { + int bbuffer_pos = this.bbuffer_pos; + while (off < offlen && bbuffer_pos < bbuffer_len) + b[off++] = bbuffer[bbuffer_pos++]; + this.bbuffer_pos = bbuffer_pos; + if (!readfully) + return off - orgoff; + } + } + return len; + } + + public int read() throws IOException { + int ret = read(single); + if (ret == -1) + return -1; + return single[0] & 0xFF; + } + + public int available() { + return bbuffer.length - bbuffer_pos; + } + + public void close() { + SoftMainMixer.this.synth.close(); + } + }; + + ais = new AudioInputStream(in, synth.getFormat(), AudioSystem.NOT_SPECIFIED); + + } + + public AudioInputStream getInputStream() { + return ais; + } + + public void reset() { + + SoftChannel[] channels = synth.channels; + for (int i = 0; i < channels.length; i++) { + channels[i].allSoundOff(); + channels[i].resetAllControllers(true); + + if (synth.getGeneralMidiMode() == 2) { + if (i == 9) + channels[i].programChange(0, 0x78 * 128); + else + channels[i].programChange(0, 0x79 * 128); + } else + channels[i].programChange(0, 0); + } + setVolume(0x7F * 128 + 0x7F); + setBalance(0x40 * 128 + 0x00); + setCoarseTuning(0x40 * 128 + 0x00); + setFineTuning(0x40 * 128 + 0x00); + // Reset Reverb + globalParameterControlChange( + new int[]{0x01 * 128 + 0x01}, new long[]{0}, new long[]{4}); + // Reset Chorus + globalParameterControlChange( + new int[]{0x01 * 128 + 0x02}, new long[]{0}, new long[]{2}); + } + + public void setVolume(int value) { + synchronized (control_mutex) { + co_master_volume[0] = value / 16384.0; + } + } + + public void setBalance(int value) { + synchronized (control_mutex) { + co_master_balance[0] = value / 16384.0; + } + } + + public void setFineTuning(int value) { + synchronized (control_mutex) { + co_master_fine_tuning[0] = value / 16384.0; + } + } + + public void setCoarseTuning(int value) { + synchronized (control_mutex) { + co_master_coarse_tuning[0] = value / 16384.0; + } + } + + public int getVolume() { + synchronized (control_mutex) { + return (int) (co_master_volume[0] * 16384.0); + } + } + + public int getBalance() { + synchronized (control_mutex) { + return (int) (co_master_balance[0] * 16384.0); + } + } + + public int getFineTuning() { + synchronized (control_mutex) { + return (int) (co_master_fine_tuning[0] * 16384.0); + } + } + + public int getCoarseTuning() { + synchronized (control_mutex) { + return (int) (co_master_coarse_tuning[0] * 16384.0); + } + } + + public void globalParameterControlChange(int[] slothpath, long[] params, + long[] paramsvalue) { + if (slothpath.length == 0) + return; + + synchronized (control_mutex) { + + // slothpath: 01xx are reserved only for GM2 + + if (slothpath[0] == 0x01 * 128 + 0x01) { + for (int i = 0; i < paramsvalue.length; i++) { + reverb.globalParameterControlChange(slothpath, params[i], + paramsvalue[i]); + } + } + if (slothpath[0] == 0x01 * 128 + 0x02) { + for (int i = 0; i < paramsvalue.length; i++) { + chorus.globalParameterControlChange(slothpath, params[i], + paramsvalue[i]); + } + + } + + } + } + + public void processMessage(Object object) { + if (object instanceof byte[]) + processMessage((byte[]) object); + if (object instanceof MidiMessage) + processMessage((MidiMessage)object); + } + + public void processMessage(MidiMessage message) { + if (message instanceof ShortMessage) { + ShortMessage sms = (ShortMessage)message; + processMessage(sms.getChannel(), sms.getCommand(), + sms.getData1(), sms.getData2()); + return; + } + processMessage(message.getMessage()); + } + + public void processMessage(byte[] data) { + int status = 0; + if (data.length > 0) + status = data[0] & 0xFF; + + if (status == 0xF0) { + processSystemExclusiveMessage(data); + return; + } + + int cmd = (status & 0xF0); + int ch = (status & 0x0F); + + int data1; + int data2; + if (data.length > 1) + data1 = data[1] & 0xFF; + else + data1 = 0; + if (data.length > 2) + data2 = data[2] & 0xFF; + else + data2 = 0; + + processMessage(ch, cmd, data1, data2); + + } + + public void processMessage(int ch, int cmd, int data1, int data2) { + synchronized (synth.control_mutex) { + msec_last_activity = msec_pos; + } + + if (cmd == 0xF0) { + int status = cmd | ch; + switch (status) { + case ShortMessage.ACTIVE_SENSING: + synchronized (synth.control_mutex) { + active_sensing_on = true; + } + break; + default: + break; + } + return; + } + + SoftChannel[] channels = synth.channels; + if (ch >= channels.length) + return; + SoftChannel softchannel = channels[ch]; + + switch (cmd) { + case ShortMessage.NOTE_ON: + softchannel.noteOn(data1, data2); + break; + case ShortMessage.NOTE_OFF: + softchannel.noteOff(data1, data2); + break; + case ShortMessage.POLY_PRESSURE: + softchannel.setPolyPressure(data1, data2); + break; + case ShortMessage.CONTROL_CHANGE: + softchannel.controlChange(data1, data2); + break; + case ShortMessage.PROGRAM_CHANGE: + softchannel.programChange(data1); + break; + case ShortMessage.CHANNEL_PRESSURE: + softchannel.setChannelPressure(data1); + break; + case ShortMessage.PITCH_BEND: + softchannel.setPitchBend(data1 + data2 * 128); + break; + default: + break; + } + + } + + public long getMicrosecondPosition() { + return msec_pos; + } + + public void close() { + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftMidiAudioFileReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,214 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Track; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.AudioFileFormat.Type; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * MIDI File Audio Renderer/Reader + * + * @author Karl Helgason + */ +public class SoftMidiAudioFileReader extends AudioFileReader { + + public static final Type MIDI = new Type("MIDI", "mid"); + private static AudioFormat format = new AudioFormat(44100, 16, 2, true, false); + + public AudioFileFormat getAudioFileFormat(Sequence seq) + throws UnsupportedAudioFileException, IOException { + + long totallen = seq.getMicrosecondLength() / 1000000; + long len = (long) (format.getFrameRate() * (totallen + 4)); + return new AudioFileFormat(MIDI, format, (int) len); + } + + public AudioInputStream getAudioInputStream(Sequence seq) + throws UnsupportedAudioFileException, IOException { + AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer(); + AudioInputStream stream; + Receiver recv; + try { + stream = synth.openStream(format, null); + recv = synth.getReceiver(); + } catch (MidiUnavailableException e) { + throw new IOException(e.toString()); + } + float divtype = seq.getDivisionType(); + Track[] tracks = seq.getTracks(); + int[] trackspos = new int[tracks.length]; + int mpq = 500000; + int seqres = seq.getResolution(); + long lasttick = 0; + long curtime = 0; + while (true) { + MidiEvent selevent = null; + int seltrack = -1; + for (int i = 0; i < tracks.length; i++) { + int trackpos = trackspos[i]; + Track track = tracks[i]; + if (trackpos < track.size()) { + MidiEvent event = track.get(trackpos); + if (selevent == null || event.getTick() < selevent.getTick()) { + selevent = event; + seltrack = i; + } + } + } + if (seltrack == -1) + break; + trackspos[seltrack]++; + long tick = selevent.getTick(); + if (divtype == Sequence.PPQ) + curtime += ((tick - lasttick) * mpq) / seqres; + else + curtime = (long) ((tick * 1000000.0 * divtype) / seqres); + lasttick = tick; + MidiMessage msg = selevent.getMessage(); + if (msg instanceof MetaMessage) { + if (divtype == Sequence.PPQ) { + if (((MetaMessage) msg).getType() == 0x51) { + byte[] data = ((MetaMessage) msg).getData(); + mpq = ((data[0] & 0xff) << 16) + | ((data[1] & 0xff) << 8) | (data[2] & 0xff); + } + } + } else { + recv.send(msg, curtime); + } + } + + long totallen = curtime / 1000000; + long len = (long) (stream.getFormat().getFrameRate() * (totallen + 4)); + stream = new AudioInputStream(stream, stream.getFormat(), len); + return stream; + } + + public AudioInputStream getAudioInputStream(InputStream inputstream) + throws UnsupportedAudioFileException, IOException { + + inputstream.mark(200); + Sequence seq; + try { + seq = MidiSystem.getSequence(inputstream); + } catch (InvalidMidiDataException e) { + inputstream.reset(); + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + inputstream.reset(); + throw new UnsupportedAudioFileException(); + } + return getAudioInputStream(seq); + } + + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException { + Sequence seq; + try { + seq = MidiSystem.getSequence(url); + } catch (InvalidMidiDataException e) { + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + throw new UnsupportedAudioFileException(); + } + return getAudioFileFormat(seq); + } + + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException { + Sequence seq; + try { + seq = MidiSystem.getSequence(file); + } catch (InvalidMidiDataException e) { + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + throw new UnsupportedAudioFileException(); + } + return getAudioFileFormat(seq); + } + + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException { + Sequence seq; + try { + seq = MidiSystem.getSequence(url); + } catch (InvalidMidiDataException e) { + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + throw new UnsupportedAudioFileException(); + } + return getAudioInputStream(seq); + } + + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException { + if (!file.getName().toLowerCase().endsWith(".mid")) + throw new UnsupportedAudioFileException(); + Sequence seq; + try { + seq = MidiSystem.getSequence(file); + } catch (InvalidMidiDataException e) { + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + throw new UnsupportedAudioFileException(); + } + return getAudioInputStream(seq); + } + + public AudioFileFormat getAudioFileFormat(InputStream inputstream) + throws UnsupportedAudioFileException, IOException { + + inputstream.mark(200); + Sequence seq; + try { + seq = MidiSystem.getSequence(inputstream); + } catch (InvalidMidiDataException e) { + inputstream.reset(); + throw new UnsupportedAudioFileException(); + } catch (IOException e) { + inputstream.reset(); + throw new UnsupportedAudioFileException(); + } + return getAudioFileFormat(seq); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftPerformer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftPerformer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,775 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class decodes information from ModelPeformer for use in SoftVoice. + * It also adds default connections if they where missing in ModelPerformer. + * + * @author Karl Helgason + */ +public class SoftPerformer { + + static ModelConnectionBlock[] defaultconnections + = new ModelConnectionBlock[42]; + + static { + int o = 0; + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("noteon", "on", 0), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1, new ModelDestination(new ModelIdentifier("eg", "on", 0))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("noteon", "on", 0), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1, new ModelDestination(new ModelIdentifier("eg", "on", 1))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("eg", "active", 0), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1, new ModelDestination(new ModelIdentifier("mixer", "active", 0))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("eg", 0), + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + -960, new ModelDestination(new ModelIdentifier("mixer", "gain"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("noteon", "velocity"), + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_CONCAVE), + -960, new ModelDestination(new ModelIdentifier("mixer", "gain"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi", "pitch"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(new ModelIdentifier("midi_rpn", "0"), + new ModelTransform() { + public double transform(double value) { + int v = (int) (value * 16384.0); + int msb = v >> 7; + int lsb = v & 127; + return msb * 100 + lsb; + } + }), + new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("noteon", "keynumber"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 12800, new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "7"), + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_CONCAVE), + -960, new ModelDestination(new ModelIdentifier("mixer", "gain"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "8"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1000, new ModelDestination(new ModelIdentifier("mixer", "balance"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "10"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1000, new ModelDestination(new ModelIdentifier("mixer", "pan"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "11"), + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_CONCAVE), + -960, new ModelDestination(new ModelIdentifier("mixer", "gain"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "91"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1000, new ModelDestination(new ModelIdentifier("mixer", "reverb"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "93"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 1000, new ModelDestination(new ModelIdentifier("mixer", "chorus"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "71"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 200, new ModelDestination(new ModelIdentifier("filter", "q"))); + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "74"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 9600, new ModelDestination(new ModelIdentifier("filter", "freq"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "72"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 6000, new ModelDestination(new ModelIdentifier("eg", "release2"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "73"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 2000, new ModelDestination(new ModelIdentifier("eg", "attack2"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "75"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 6000, new ModelDestination(new ModelIdentifier("eg", "decay2"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "67"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_SWITCH), + -50, new ModelDestination(ModelDestination.DESTINATION_GAIN)); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_cc", "67"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_SWITCH), + -2400, new ModelDestination(ModelDestination.DESTINATION_FILTER_FREQ)); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_rpn", "1"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 100, new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("midi_rpn", "2"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 12800, new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("master", "fine_tuning"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 100, new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock( + new ModelSource( + new ModelIdentifier("master", "coarse_tuning"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 12800, new ModelDestination(new ModelIdentifier("osc", "pitch"))); + + defaultconnections[o++] = new ModelConnectionBlock(13500, + new ModelDestination(new ModelIdentifier("filter", "freq", 0))); + + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "delay", 0))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "attack", 0))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "hold", 0))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "decay", 0))); + defaultconnections[o++] = new ModelConnectionBlock(1000, + new ModelDestination(new ModelIdentifier("eg", "sustain", 0))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "release", 0))); + defaultconnections[o++] = new ModelConnectionBlock(1200.0 + * Math.log(0.015) / Math.log(2), new ModelDestination( + new ModelIdentifier("eg", "shutdown", 0))); // 15 msec default + + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "delay", 1))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "attack", 1))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "hold", 1))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "decay", 1))); + defaultconnections[o++] = new ModelConnectionBlock(1000, + new ModelDestination(new ModelIdentifier("eg", "sustain", 1))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("eg", "release", 1))); + + defaultconnections[o++] = new ModelConnectionBlock(-8.51318, + new ModelDestination(new ModelIdentifier("lfo", "freq", 0))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("lfo", "delay", 0))); + defaultconnections[o++] = new ModelConnectionBlock(-8.51318, + new ModelDestination(new ModelIdentifier("lfo", "freq", 1))); + defaultconnections[o++] = new ModelConnectionBlock( + Float.NEGATIVE_INFINITY, new ModelDestination( + new ModelIdentifier("lfo", "delay", 1))); + + } + public int keyFrom = 0; + public int keyTo = 127; + public int velFrom = 0; + public int velTo = 127; + public int exclusiveClass = 0; + public boolean selfNonExclusive = false; + public boolean forcedVelocity = false; + public boolean forcedKeynumber = false; + public ModelPerformer performer; + public ModelConnectionBlock[] connections; + public ModelOscillator[] oscillators; + public Map midi_rpn_connections = new HashMap(); + public Map midi_nrpn_connections = new HashMap(); + public int[][] midi_ctrl_connections; + public int[][] midi_connections; + public int[] ctrl_connections; + private List ctrl_connections_list = new ArrayList(); + + private static class KeySortComparator implements Comparator { + + public int compare(ModelSource o1, ModelSource o2) { + return o1.getIdentifier().toString().compareTo( + o2.getIdentifier().toString()); + } + } + private static KeySortComparator keySortComparator = new KeySortComparator(); + + private String extractKeys(ModelConnectionBlock conn) { + StringBuffer sb = new StringBuffer(); + if (conn.getSources() != null) { + sb.append("["); + ModelSource[] srcs = conn.getSources(); + ModelSource[] srcs2 = new ModelSource[srcs.length]; + for (int i = 0; i < srcs.length; i++) + srcs2[i] = srcs[i]; + Arrays.sort(srcs2, keySortComparator); + for (int i = 0; i < srcs.length; i++) { + sb.append(srcs[i].getIdentifier()); + sb.append(";"); + } + sb.append("]"); + } + sb.append(";"); + if (conn.getDestination() != null) { + sb.append(conn.getDestination().getIdentifier()); + } + sb.append(";"); + return sb.toString(); + } + + private void processSource(ModelSource src, int ix) { + ModelIdentifier id = src.getIdentifier(); + String o = id.getObject(); + if (o.equals("midi_cc")) + processMidiControlSource(src, ix); + else if (o.equals("midi_rpn")) + processMidiRpnSource(src, ix); + else if (o.equals("midi_nrpn")) + processMidiNrpnSource(src, ix); + else if (o.equals("midi")) + processMidiSource(src, ix); + else if (o.equals("noteon")) + processNoteOnSource(src, ix); + else if (o.equals("osc")) + return; + else if (o.equals("mixer")) + return; + else + ctrl_connections_list.add(ix); + } + + private void processMidiControlSource(ModelSource src, int ix) { + String v = src.getIdentifier().getVariable(); + if (v == null) + return; + int c = Integer.parseInt(v); + if (midi_ctrl_connections[c] == null) + midi_ctrl_connections[c] = new int[]{ix}; + else { + int[] olda = midi_ctrl_connections[c]; + int[] newa = new int[olda.length + 1]; + for (int i = 0; i < olda.length; i++) + newa[i] = olda[i]; + newa[newa.length - 1] = ix; + midi_ctrl_connections[c] = newa; + } + } + + private void processNoteOnSource(ModelSource src, int ix) { + String v = src.getIdentifier().getVariable(); + int c = -1; + if (v.equals("on")) + c = 3; + if (v.equals("keynumber")) + c = 4; + if (c == -1) + return; + if (midi_connections[c] == null) + midi_connections[c] = new int[]{ix}; + else { + int[] olda = midi_connections[c]; + int[] newa = new int[olda.length + 1]; + for (int i = 0; i < olda.length; i++) + newa[i] = olda[i]; + newa[newa.length - 1] = ix; + midi_connections[c] = newa; + } + } + + private void processMidiSource(ModelSource src, int ix) { + String v = src.getIdentifier().getVariable(); + int c = -1; + if (v.equals("pitch")) + c = 0; + if (v.equals("channel_pressure")) + c = 1; + if (v.equals("poly_pressure")) + c = 2; + if (c == -1) + return; + if (midi_connections[c] == null) + midi_connections[c] = new int[]{ix}; + else { + int[] olda = midi_connections[c]; + int[] newa = new int[olda.length + 1]; + for (int i = 0; i < olda.length; i++) + newa[i] = olda[i]; + newa[newa.length - 1] = ix; + midi_connections[c] = newa; + } + } + + private void processMidiRpnSource(ModelSource src, int ix) { + String v = src.getIdentifier().getVariable(); + if (v == null) + return; + int c = Integer.parseInt(v); + if (midi_rpn_connections.get(c) == null) + midi_rpn_connections.put(c, new int[]{ix}); + else { + int[] olda = midi_rpn_connections.get(c); + int[] newa = new int[olda.length + 1]; + for (int i = 0; i < olda.length; i++) + newa[i] = olda[i]; + newa[newa.length - 1] = ix; + midi_rpn_connections.put(c, newa); + } + } + + private void processMidiNrpnSource(ModelSource src, int ix) { + String v = src.getIdentifier().getVariable(); + if (v == null) + return; + int c = Integer.parseInt(v); + if (midi_nrpn_connections.get(c) == null) + midi_nrpn_connections.put(c, new int[]{ix}); + else { + int[] olda = midi_nrpn_connections.get(c); + int[] newa = new int[olda.length + 1]; + for (int i = 0; i < olda.length; i++) + newa[i] = olda[i]; + newa[newa.length - 1] = ix; + midi_nrpn_connections.put(c, newa); + } + } + + public SoftPerformer(ModelPerformer performer) { + this.performer = performer; + + keyFrom = performer.getKeyFrom(); + keyTo = performer.getKeyTo(); + velFrom = performer.getVelFrom(); + velTo = performer.getVelTo(); + exclusiveClass = performer.getExclusiveClass(); + selfNonExclusive = performer.isSelfNonExclusive(); + + Map connmap = new HashMap(); + + List performer_connections = new ArrayList(); + performer_connections.addAll(performer.getConnectionBlocks()); + + if (performer.isDefaultConnectionsEnabled()) { + + // Add modulation depth range (RPN 5) to the modulation wheel (cc#1) + + boolean isModulationWheelConectionFound = false; + for (int j = 0; j < performer_connections.size(); j++) { + ModelConnectionBlock connection = performer_connections.get(j); + ModelSource[] sources = connection.getSources(); + ModelDestination dest = connection.getDestination(); + boolean isModulationWheelConection = false; + if (dest != null && sources != null && sources.length > 1) { + for (int i = 0; i < sources.length; i++) { + // check if connection block has the source "modulation + // wheel cc#1" + if (sources[i].getIdentifier().getObject().equals( + "midi_cc")) { + if (sources[i].getIdentifier().getVariable() + .equals("1")) { + isModulationWheelConection = true; + isModulationWheelConectionFound = true; + break; + } + } + } + } + if (isModulationWheelConection) { + + ModelConnectionBlock newconnection = new ModelConnectionBlock(); + newconnection.setSources(connection.getSources()); + newconnection.setDestination(connection.getDestination()); + newconnection.addSource(new ModelSource( + new ModelIdentifier("midi_rpn", "5"))); + newconnection.setScale(connection.getScale() * 256.0); + performer_connections.set(j, newconnection); + } + } + + if (!isModulationWheelConectionFound) { + ModelConnectionBlock conn = new ModelConnectionBlock( + new ModelSource(ModelSource.SOURCE_LFO1, + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + new ModelSource(new ModelIdentifier("midi_cc", "1", 0), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_UNIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 50, + new ModelDestination(ModelDestination.DESTINATION_PITCH)); + conn.addSource(new ModelSource(new ModelIdentifier("midi_rpn", + "5"))); + conn.setScale(conn.getScale() * 256.0); + performer_connections.add(conn); + + } + + // Let Aftertouch to behave just like modulation wheel (cc#1) + boolean channel_pressure_set = false; + boolean poly_pressure = false; + ModelConnectionBlock mod_cc_1_connection = null; + int mod_cc_1_connection_src_ix = 0; + + for (ModelConnectionBlock connection : performer_connections) { + ModelSource[] sources = connection.getSources(); + ModelDestination dest = connection.getDestination(); + // if(dest != null && sources != null) + if (dest != null && sources != null) { + for (int i = 0; i < sources.length; i++) { + ModelIdentifier srcid = sources[i].getIdentifier(); + // check if connection block has the source "modulation + // wheel cc#1" + if (srcid.getObject().equals("midi_cc")) { + if (srcid.getVariable().equals("1")) { + mod_cc_1_connection = connection; + mod_cc_1_connection_src_ix = i; + } + } + // check if channel or poly pressure are already + // connected + if (srcid.getObject().equals("midi")) { + if (srcid.getVariable().equals("channel_pressure")) + channel_pressure_set = true; + if (srcid.getVariable().equals("poly_pressure")) + poly_pressure = true; + } + } + } + + } + + if (mod_cc_1_connection != null) { + if (!channel_pressure_set) { + ModelConnectionBlock mc = new ModelConnectionBlock(); + mc.setDestination(mod_cc_1_connection.getDestination()); + mc.setScale(mod_cc_1_connection.getScale()); + ModelSource[] src_list = mod_cc_1_connection.getSources(); + ModelSource[] src_list_new = new ModelSource[src_list.length]; + for (int i = 0; i < src_list_new.length; i++) + src_list_new[i] = src_list[i]; + src_list_new[mod_cc_1_connection_src_ix] = new ModelSource( + new ModelIdentifier("midi", "channel_pressure")); + mc.setSources(src_list_new); + connmap.put(extractKeys(mc), mc); + } + if (!poly_pressure) { + ModelConnectionBlock mc = new ModelConnectionBlock(); + mc.setDestination(mod_cc_1_connection.getDestination()); + mc.setScale(mod_cc_1_connection.getScale()); + ModelSource[] src_list = mod_cc_1_connection.getSources(); + ModelSource[] src_list_new = new ModelSource[src_list.length]; + for (int i = 0; i < src_list_new.length; i++) + src_list_new[i] = src_list[i]; + src_list_new[mod_cc_1_connection_src_ix] = new ModelSource( + new ModelIdentifier("midi", "poly_pressure")); + mc.setSources(src_list_new); + connmap.put(extractKeys(mc), mc); + } + } + + // Enable Vibration Sound Controllers : 76, 77, 78 + ModelConnectionBlock found_vib_connection = null; + for (ModelConnectionBlock connection : performer_connections) { + ModelSource[] sources = connection.getSources(); + if (sources.length != 0 + && sources[0].getIdentifier().getObject().equals("lfo")) { + if (connection.getDestination().getIdentifier().equals( + ModelDestination.DESTINATION_PITCH)) { + if (found_vib_connection == null) + found_vib_connection = connection; + else { + if (found_vib_connection.getSources().length > sources.length) + found_vib_connection = connection; + else if (found_vib_connection.getSources()[0] + .getIdentifier().getInstance() < 1) { + if (found_vib_connection.getSources()[0] + .getIdentifier().getInstance() > + sources[0].getIdentifier().getInstance()) { + found_vib_connection = connection; + } + } + } + + } + } + } + + int instance = 1; + + if (found_vib_connection != null) { + instance = found_vib_connection.getSources()[0].getIdentifier() + .getInstance(); + } + ModelConnectionBlock connection; + + connection = new ModelConnectionBlock( + new ModelSource(new ModelIdentifier("midi_cc", "78"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 2000, new ModelDestination( + new ModelIdentifier("lfo", "delay2", instance))); + connmap.put(extractKeys(connection), connection); + + final double scale = found_vib_connection == null ? 0 + : found_vib_connection.getScale(); + connection = new ModelConnectionBlock( + new ModelSource(new ModelIdentifier("lfo", instance)), + new ModelSource(new ModelIdentifier("midi_cc", "77"), + new ModelTransform() { + double s = scale; + public double transform(double value) { + value = value * 2 - 1; + value *= 600; + if (s == 0) { + return value; + } else if (s > 0) { + if (value < -s) + value = -s; + return value; + } else { + if (value < s) + value = -s; + return -value; + } + } + }), new ModelDestination(ModelDestination.DESTINATION_PITCH)); + connmap.put(extractKeys(connection), connection); + + connection = new ModelConnectionBlock( + new ModelSource(new ModelIdentifier("midi_cc", "76"), + ModelStandardTransform.DIRECTION_MIN2MAX, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_LINEAR), + 2400, new ModelDestination( + new ModelIdentifier("lfo", "freq", instance))); + connmap.put(extractKeys(connection), connection); + + } + + // Add default connection blocks + if (performer.isDefaultConnectionsEnabled()) + for (ModelConnectionBlock connection : defaultconnections) + connmap.put(extractKeys(connection), connection); + // Add connection blocks from modelperformer + for (ModelConnectionBlock connection : performer_connections) + connmap.put(extractKeys(connection), connection); + // seperate connection blocks : Init time, Midi Time, Midi/Control Time, + // Control Time + List connections = new ArrayList(); + + midi_ctrl_connections = new int[128][]; + for (int i = 0; i < midi_ctrl_connections.length; i++) { + midi_ctrl_connections[i] = null; + } + midi_connections = new int[5][]; + for (int i = 0; i < midi_connections.length; i++) { + midi_connections[i] = null; + } + + int ix = 0; + boolean mustBeOnTop = false; + + for (ModelConnectionBlock connection : connmap.values()) { + if (connection.getDestination() != null) { + ModelDestination dest = connection.getDestination(); + ModelIdentifier id = dest.getIdentifier(); + if (id.getObject().equals("noteon")) { + mustBeOnTop = true; + if (id.getVariable().equals("keynumber")) + forcedKeynumber = true; + if (id.getVariable().equals("velocity")) + forcedVelocity = true; + } + } + if (mustBeOnTop) { + connections.add(0, connection); + mustBeOnTop = false; + } else + connections.add(connection); + } + + for (ModelConnectionBlock connection : connections) { + if (connection.getSources() != null) { + ModelSource[] srcs = connection.getSources(); + for (int i = 0; i < srcs.length; i++) { + processSource(srcs[i], ix); + } + } + ix++; + } + + this.connections = new ModelConnectionBlock[connections.size()]; + connections.toArray(this.connections); + + this.ctrl_connections = new int[ctrl_connections_list.size()]; + + for (int i = 0; i < this.ctrl_connections.length; i++) + this.ctrl_connections[i] = ctrl_connections_list.get(i); + + oscillators = new ModelOscillator[performer.getOscillators().size()]; + performer.getOscillators().toArray(oscillators); + + for (ModelConnectionBlock conn : connections) { + if (conn.getDestination() != null) { + if (isUnnecessaryTransform(conn.getDestination().getTransform())) { + conn.getDestination().setTransform(null); + } + } + if (conn.getSources() != null) { + for (ModelSource src : conn.getSources()) { + if (isUnnecessaryTransform(src.getTransform())) { + src.setTransform(null); + } + } + } + } + + } + + private static boolean isUnnecessaryTransform(ModelTransform transform) { + if (transform == null) + return false; + if (!(transform instanceof ModelStandardTransform)) + return false; + ModelStandardTransform stransform = (ModelStandardTransform)transform; + if (stransform.getDirection() != ModelStandardTransform.DIRECTION_MIN2MAX) + return false; + if (stransform.getPolarity() != ModelStandardTransform.POLARITY_UNIPOLAR) + return false; + if (stransform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR) + return false; + return false; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftPointResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftPointResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * A resampler that uses 0-order (nearest-neighbor) interpolation. + * + * @author Karl Helgason + */ +public class SoftPointResampler extends SoftAbstractResampler { + + public int getPadding() { + return 100; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + float ox_end = out_end; + if (pitchstep == 0) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = in[(int) ix]; + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = in[(int) ix]; + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftProcess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftProcess.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Control signal processor interface + * + * @author Karl Helgason + */ +public interface SoftProcess extends SoftControl { + + public void init(SoftSynthesizer synth); + + public double[] get(int instance, String name); + + public void processControlLogic(); + + public void reset(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftProvider.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.spi.MidiDeviceProvider; + +/** + * Software synthesizer provider class. + * + * @author Karl Helgason + */ +public class SoftProvider extends MidiDeviceProvider { + + protected static Info softinfo = SoftSynthesizer.info; + private static Info[] softinfos = {softinfo}; + + public MidiDevice.Info[] getDeviceInfo() { + return softinfos; + } + + public MidiDevice getDevice(MidiDevice.Info info) { + if (info == softinfo) { + return new SoftSynthesizer(); + } + return null; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftReceiver.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.TreeMap; + +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Receiver; +import javax.sound.midi.ShortMessage; + +/** + * Software synthesizer MIDI receiver class. + * + * @author Karl Helgason + */ +public class SoftReceiver implements Receiver { + + protected boolean open = true; + private Object control_mutex; + private SoftSynthesizer synth; + protected TreeMap midimessages; + protected SoftMainMixer mainmixer; + + public SoftReceiver(SoftSynthesizer synth) { + this.control_mutex = synth.control_mutex; + this.synth = synth; + this.mainmixer = synth.getMainMixer(); + if (mainmixer != null) + this.midimessages = mainmixer.midimessages; + } + + public void send(MidiMessage message, long timeStamp) { + + synchronized (control_mutex) { + if (!open) + throw new IllegalStateException("Receiver is not open"); + } + + if (timeStamp != -1) { + synchronized (control_mutex) { + while (midimessages.get(timeStamp) != null) + timeStamp++; + if (message instanceof ShortMessage + && (((ShortMessage)message).getChannel() > 0xF)) { + midimessages.put(timeStamp, message.clone()); + } else { + midimessages.put(timeStamp, message.getMessage()); + } + } + } else { + mainmixer.processMessage(message); + } + } + + public void close() { + synchronized (control_mutex) { + open = false; + } + synth.removeReceiver(this); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Basic resampler interface. + * + * @author Karl Helgason + */ +public interface SoftResampler { + + public SoftResamplerStreamer openStreamer(); +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftResamplerStreamer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftResamplerStreamer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; + +/** + * Resampler stream interface. + * + * @author Karl Helgason + */ +public interface SoftResamplerStreamer extends ModelOscillatorStream { + + public void open(ModelWavetable osc, float outputsamplerate) + throws IOException; +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftReverb.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftReverb.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,465 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.util.Arrays; + +/** + * Reverb effect based on allpass/comb filters. First audio is send to 8 + * parelled comb filters and then mixed together and then finally send thru 3 + * different allpass filters. + * + * @author Karl Helgason + */ +public class SoftReverb implements SoftAudioProcessor { + + private class Delay { + + private float[] delaybuffer; + private int rovepos = 0; + + public Delay() { + delaybuffer = null; + } + + public void setDelay(int delay) { + if (delay == 0) + delaybuffer = null; + else + delaybuffer = new float[delay]; + rovepos = 0; + } + + public void processReplace(float[] in, float[] out) { + float[] delaybuffer = this.delaybuffer; + if (delaybuffer == null) + return; + int len = in.length; + int rnlen = delaybuffer.length; + int rovepos = this.rovepos; + + for (int i = 0; i < len; i++) { + float x = in[i]; + out[i] = delaybuffer[rovepos]; + delaybuffer[rovepos] = x; + rovepos = rovepos + 1; + if (rovepos == rnlen) + rovepos = 0; + //rovepos = (rovepos + 1) % rnlen; + } + this.rovepos = rovepos; + } + } + + private class AllPass { + + private float[] delaybuffer; + private int delaybuffersize; + private int rovepos = 0; + private float feedback; + + public AllPass(int size) { + delaybuffer = new float[size]; + delaybuffersize = size; + } + + public void setFeedBack(float feedback) { + this.feedback = feedback; + } + int ucount = 0; + + public void processReplace(float in[], float out[]) { + int len = in.length; + for (int i = 0; i < len; i++) { + + float delayout = delaybuffer[rovepos]; + + // undenormalise(delayout) + /* + if (((delayout > 0.0) && (delayout < 1.0E-10)) + || ((delayout < 0.0) && (delayout > -1.0E-10))) + delayout = 0; + */ + + float input = in[i]; + out[i] = -input + delayout; + delaybuffer[rovepos] = input + delayout * feedback; + if (++rovepos == delaybuffersize) + rovepos = 0; + } + + ucount++; + if (ucount == 10) { + ucount = 0; + for (int i = 0; i < delaybuffer.length; i++) { + double v = delaybuffer[i]; + if (((v > 0.0) && (v < 1.0E-10)) + || ((v < 0.0) && (v > -1.0E-10))) { + delaybuffer[i] = 0; + } + } + } + + } + } + + private class Comb { + + private float[] delaybuffer; + private int delaybuffersize; + private int rovepos = 0; + private float feedback; + private float filtertemp = 0; + private float filtercoeff1 = 0; + private float filtercoeff2 = 1; + + public Comb(int size) { + delaybuffer = new float[size]; + delaybuffersize = size; + } + + public void setFeedBack(float feedback) { + this.feedback = feedback; + } + int ucount = 0; + + public void processMix(float in[], float out[]) { + int len = in.length; + + float filtercoeff2 = this.filtercoeff2 * feedback; + + for (int i = 0; i < len; i++) { + float delayout = delaybuffer[rovepos]; + + // One Pole Lowpass Filter + filtertemp = (delayout * filtercoeff2) + + (filtertemp * filtercoeff1); + + // undenormalise(filtertemp) + /* + if (((filtertemp > 0.0) && (filtertemp < 1.0E-10)) + || ((filtertemp < 0.0) && (filtertemp > -1.0E-10))) + filtertemp = 0; + */ + out[i] += delayout; + delaybuffer[rovepos] = in[i] + (filtertemp);// * feedback); + + if (++rovepos == delaybuffersize) + rovepos = 0; + + } + ucount++; + if (ucount == 10) { + ucount = 0; + if (((filtertemp > 0.0) && (filtertemp < 1.0E-10)) + || ((filtertemp < 0.0) && (filtertemp > -1.0E-10))) { + filtertemp = 0; + } + for (int i = 0; i < delaybuffer.length; i++) { + double v = delaybuffer[i]; + if (((v > 0.0) && (v < 1.0E-10)) + || ((v < 0.0) && (v > -1.0E-10))) { + delaybuffer[i] = 0; + } + } + } + + + } + + public void setDamp(float val) { + filtercoeff1 = val; + filtercoeff2 = 1 - filtercoeff1; + } + } + private float roomsize; + private float damp; + private float gain = 1; + private Delay delay; + private Comb[] combL; + private Comb[] combR; + private AllPass[] allpassL; + private AllPass[] allpassR; + private float[] input; + private float[] outR; + private float[] outL; + private boolean mix = true; + private SoftAudioBuffer inputA; + private SoftAudioBuffer left; + private SoftAudioBuffer right; + private SoftSynthesizer synth; + private boolean dirty = true; + private float dirty_roomsize; + private float dirty_damp; + private float dirty_predelay; + private float dirty_gain; + + public void init(SoftSynthesizer synth) { + this.synth = synth; + double samplerate = synth.getFormat().getSampleRate(); + + double freqscale = ((double) samplerate) / 44100.0; + // freqscale = 1.0/ freqscale; + + int stereospread = 23; + + delay = new Delay(); + + combL = new Comb[8]; + combR = new Comb[8]; + combL[0] = new Comb((int) (freqscale * (1116))); + combR[0] = new Comb((int) (freqscale * (1116 + stereospread))); + combL[1] = new Comb((int) (freqscale * (1188))); + combR[1] = new Comb((int) (freqscale * (1188 + stereospread))); + combL[2] = new Comb((int) (freqscale * (1277))); + combR[2] = new Comb((int) (freqscale * (1277 + stereospread))); + combL[3] = new Comb((int) (freqscale * (1356))); + combR[3] = new Comb((int) (freqscale * (1356 + stereospread))); + combL[4] = new Comb((int) (freqscale * (1422))); + combR[4] = new Comb((int) (freqscale * (1422 + stereospread))); + combL[5] = new Comb((int) (freqscale * (1491))); + combR[5] = new Comb((int) (freqscale * (1491 + stereospread))); + combL[6] = new Comb((int) (freqscale * (1557))); + combR[6] = new Comb((int) (freqscale * (1557 + stereospread))); + combL[7] = new Comb((int) (freqscale * (1617))); + combR[7] = new Comb((int) (freqscale * (1617 + stereospread))); + + allpassL = new AllPass[4]; + allpassR = new AllPass[4]; + allpassL[0] = new AllPass((int) (freqscale * (556))); + allpassR[0] = new AllPass((int) (freqscale * (556 + stereospread))); + allpassL[1] = new AllPass((int) (freqscale * (441))); + allpassR[1] = new AllPass((int) (freqscale * (441 + stereospread))); + allpassL[2] = new AllPass((int) (freqscale * (341))); + allpassR[2] = new AllPass((int) (freqscale * (341 + stereospread))); + allpassL[3] = new AllPass((int) (freqscale * (225))); + allpassR[3] = new AllPass((int) (freqscale * (225 + stereospread))); + + for (int i = 0; i < allpassL.length; i++) { + allpassL[i].setFeedBack(0.5f); + allpassR[i].setFeedBack(0.5f); + } + + /* Init other settings */ + globalParameterControlChange(new int[]{0x01 * 128 + 0x01}, 0, 4); + + } + + public void setInput(int pin, SoftAudioBuffer input) { + if (pin == 0) + inputA = input; + } + + public void setOutput(int pin, SoftAudioBuffer output) { + if (pin == 0) + left = output; + if (pin == 1) + right = output; + } + + public void setMixMode(boolean mix) { + this.mix = mix; + } + private double silentcounter = 1000; + + public void processAudio() { + if (this.inputA.isSilent()) { + silentcounter += 1 / synth.getControlRate(); + + if (silentcounter > 60) { + if (!mix) { + left.clear(); + right.clear(); + } + return; + } + } else + silentcounter = 0; + + float[] inputA = this.inputA.array(); + float[] left = this.left.array(); + float[] right = this.right == null ? null : this.right.array(); + + int numsamples = inputA.length; + if (input == null || input.length < numsamples) + input = new float[numsamples]; + + float again = gain * 0.018f / 2; + + for (int i = 0; i < numsamples; i++) + input[i] = inputA[i] * again; + + delay.processReplace(input, input); + + + if (right != null) { + if (outR == null || outR.length < numsamples) + outR = new float[numsamples]; + Arrays.fill(outR, 0); + for (int i = 0; i < combR.length; i++) + combR[i].processMix(input, outR); + for (int i = 0; i < allpassL.length; i++) + allpassR[i].processReplace(outR, outR); + + if (mix) { + for (int i = 0; i < numsamples; i++) + right[i] += outR[i]; + } else { + for (int i = 0; i < numsamples; i++) + right[i] = outR[i]; + } + } + + + if (outL == null || outL.length < numsamples) + outL = new float[numsamples]; + Arrays.fill(outL, 0); + for (int i = 0; i < combL.length; i++) + combL[i].processMix(input, outL); + for (int i = 0; i < allpassL.length; i++) + allpassL[i].processReplace(outL, outL); + + if (mix) { + for (int i = 0; i < numsamples; i++) + left[i] += outL[i]; + } else { + for (int i = 0; i < numsamples; i++) + left[i] = outL[i]; + } + + + } + + public void globalParameterControlChange(int[] slothpath, long param, + long value) { + if (slothpath.length == 1) { + if (slothpath[0] == 0x01 * 128 + 0x01) { + + if (param == 0) { + if (value == 0) { + // Small Room A small size room with a length + // of 5m or so. + dirty_roomsize = (1.1f); + dirty_damp = (5000); + dirty_predelay = (0); + dirty_gain = (4); + dirty = true; + } + if (value == 1) { + // Medium Room A medium size room with a length + // of 10m or so. + dirty_roomsize = (1.3f); + dirty_damp = (5000); + dirty_predelay = (0); + dirty_gain = (3); + dirty = true; + } + if (value == 2) { + // Large Room A large size room suitable for + // live performances. + dirty_roomsize = (1.5f); + dirty_damp = (5000); + dirty_predelay = (0); + dirty_gain = (2); + dirty = true; + } + if (value == 3) { + // Medium Hall A medium size concert hall. + dirty_roomsize = (1.8f); + dirty_damp = (24000); + dirty_predelay = (0.02f); + dirty_gain = (1.5f); + dirty = true; + } + if (value == 4) { + // Large Hall A large size concert hall + // suitable for a full orchestra. + dirty_roomsize = (1.8f); + dirty_damp = (24000); + dirty_predelay = (0.03f); + dirty_gain = (1.5f); + dirty = true; + } + if (value == 8) { + // Plate A plate reverb simulation. + dirty_roomsize = (1.3f); + dirty_damp = (2500); + dirty_predelay = (0); + dirty_gain = (6); + dirty = true; + } + } else if (param == 1) { + dirty_roomsize = ((float) (Math.exp((value - 40) * 0.025))); + dirty = true; + } + + } + } + } + + public void processControlLogic() { + if (dirty) { + dirty = false; + setRoomSize(dirty_roomsize); + setDamp(dirty_damp); + setPreDelay(dirty_predelay); + setGain(dirty_gain); + } + } + + public void setRoomSize(float value) { + roomsize = 1 - (0.17f / value); + + for (int i = 0; i < 8; i++) { + combL[i].feedback = roomsize; + combR[i].feedback = roomsize; + } + } + + public void setPreDelay(float value) { + delay.setDelay((int)(value * synth.getFormat().getSampleRate())); + } + + public void setGain(float gain) { + this.gain = gain; + } + + public void setDamp(float value) { + double x = (value / synth.getFormat().getSampleRate()) * (2 * Math.PI); + double cx = 2 - Math.cos(x); + damp = (float)(cx - Math.sqrt(cx * cx - 1)); + if (damp > 1) + damp = 1; + if (damp < 0) + damp = 0; + + // damp = value * 0.4f; + for (int i = 0; i < 8; i++) { + combL[i].setDamp(damp); + combR[i].setDamp(damp); + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftShortMessage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftShortMessage.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.ShortMessage; + +/** + * A short message class that support for than 16 midi channels. + * + * @author Karl Helgason + */ +public class SoftShortMessage extends ShortMessage { + + int channel = 0; + + public int getChannel() { + return channel; + } + + public void setMessage(int command, int channel, int data1, int data2) + throws InvalidMidiDataException { + this.channel = channel; + super.setMessage(command, channel & 0xF, data1, data2); + } + + public Object clone() { + SoftShortMessage clone = new SoftShortMessage(); + try { + clone.setMessage(getCommand(), getChannel(), getData1(), getData2()); + } catch (InvalidMidiDataException e) { + throw new IllegalArgumentException(e); + } + return clone; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftSincResampler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftSincResampler.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,140 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +/** + * Hann windowed sinc interpolation resampler with anti-alias filtering. + * + * Using 30 points for the interpolation. + * + * @author Karl Helgason + */ +public class SoftSincResampler extends SoftAbstractResampler { + + double[] din; + float[][][] sinc_table; + int sinc_scale_size = 100; + int sinc_table_fsize = 800; + int sinc_table_size = 30; + int sinc_table_center = sinc_table_size / 2; + + public SoftSincResampler() { + super(); + sinc_table = new float[sinc_scale_size][sinc_table_fsize][]; + for (int s = 0; s < sinc_scale_size; s++) { + float scale = (float) (1.0 / (1.0 + Math.pow(s, 1.1) / 10.0)); + for (int i = 0; i < sinc_table_fsize; i++) { + sinc_table[s][i] = sincTable(sinc_table_size, + -i / ((float)sinc_table_fsize), scale); + } + } + } + + // Normalized sinc function + public static double sinc(double x) { + return (x == 0.0) ? 1.0 : Math.sin(Math.PI * x) / (Math.PI * x); + } + + // Generate hann window suitable for windowing sinc + public static float[] wHanning(int size, float offset) { + float[] window_table = new float[size]; + for (int k = 0; k < size; k++) { + window_table[k] = (float)(-0.5 + * Math.cos(2.0 * Math.PI * (double)(k + offset) + / (double) size) + 0.5); + } + return window_table; + } + + // Generate sinc table + public static float[] sincTable(int size, float offset, float scale) { + int center = size / 2; + float[] w = wHanning(size, offset); + for (int k = 0; k < size; k++) + w[k] *= sinc((-center + k + offset) * scale) * scale; + return w; + } + + public int getPadding() // must be at least half of sinc_table_size + { + return sinc_table_size / 2 + 2; + } + + public void interpolate(float[] in, float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + int max_p = sinc_scale_size - 1; + if (pitchstep == 0) { + + int p = (int) ((pitch - 1) * 10.0f); + if (p < 0) + p = 0; + else if (p > max_p) + p = max_p; + float[][] sinc_table_f = this.sinc_table[p]; + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + float[] sinc_table = + sinc_table_f[(int)((ix - iix) * sinc_table_fsize)]; + int xx = iix - sinc_table_center; + float y = 0; + for (int i = 0; i < sinc_table_size; i++, xx++) + y += in[xx] * sinc_table[i]; + out[ox++] = y; + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + int iix = (int) ix; + int p = (int) ((pitch - 1) * 10.0f); + if (p < 0) + p = 0; + else if (p > max_p) + p = max_p; + float[][] sinc_table_f = this.sinc_table[p]; + + float[] sinc_table = + sinc_table_f[(int)((ix - iix) * sinc_table_fsize)]; + int xx = iix - sinc_table_center; + float y = 0; + for (int i = 0; i < sinc_table_size; i++, xx++) + y += in[xx] * sinc_table[i]; + out[ox++] = y; + + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftSynthesizer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,992 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.media.sound; + +import java.io.File; +import java.io.IOException; +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.midi.Soundbank; +import javax.sound.midi.Transmitter; +import javax.sound.midi.VoiceStatus; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; + +/** + * The software synthesizer class. + * + * @author Karl Helgason + */ +public class SoftSynthesizer implements AudioSynthesizer, + ReferenceCountingDevice { + + private static class Info extends MidiDevice.Info { + public Info() { + super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION); + } + } + + protected static final String INFO_NAME = "Gervill"; + protected static final String INFO_VENDOR = "OpenJDK"; + protected static final String INFO_DESCRIPTION = "Software MIDI Synthesizer"; + protected static final String INFO_VERSION = "1.0"; + protected static MidiDevice.Info info = new Info(); + + private static Soundbank defaultSoundBank = null; + + protected Object control_mutex = this; + + protected int voiceIDCounter = 0; + + // 0: default + // 1: DLS Voice Allocation + protected int voice_allocation_mode = 0; + + protected boolean reverb_on = true; + protected boolean chorus_on = true; + protected boolean agc_on = true; + + protected SoftChannel[] channels; + protected SoftChannelProxy[] external_channels = null; + + private boolean largemode = false; + + // 0: GM Mode off (default) + // 1: GM Level 1 + // 2: GM Level 2 + private int gmmode = 0; + + private int deviceid = 0; + + private AudioFormat format = new AudioFormat(44100, 16, 2, true, false); + + private SourceDataLine sourceDataLine = null; + + private SoftAudioPusher pusher = null; + private AudioInputStream pusher_stream = null; + + private float controlrate = 147f; + + private boolean open = false; + private boolean implicitOpen = false; + + private SoftResampler resampler = new SoftLinearResampler(); + + private int number_of_midi_channels = 16; + private int maxpoly = 64; + private long latency = 200000; // 200 msec + private boolean jitter_correction = false; + + private SoftMainMixer mainmixer; + private SoftVoice[] voices; + + private Map tunings + = new HashMap(); + private Map inslist + = new HashMap(); + private Map availlist + = new HashMap(); + private Map loadedlist + = new HashMap(); + + private ArrayList recvslist = new ArrayList(); + + private void getBuffers(ModelInstrument instrument, + List buffers) { + for (ModelPerformer performer : instrument.getPerformers()) { + if (performer.getOscillators() != null) { + for (ModelOscillator osc : performer.getOscillators()) { + if (osc instanceof ModelByteBufferWavetable) { + ModelByteBufferWavetable w = (ModelByteBufferWavetable)osc; + ModelByteBuffer buff = w.getBuffer(); + if (buff != null) + buffers.add(buff); + buff = w.get8BitExtensionBuffer(); + if (buff != null) + buffers.add(buff); + } + } + } + } + } + + private boolean loadSamples(List instruments) { + if (largemode) + return true; + List buffers = new ArrayList(); + for (ModelInstrument instrument : instruments) + getBuffers(instrument, buffers); + try { + ModelByteBuffer.loadAll(buffers); + } catch (IOException e) { + return false; + } + return true; + } + + private boolean loadInstruments(List instruments) { + if (!isOpen()) + return false; + if (!loadSamples(instruments)) + return false; + + synchronized (control_mutex) { + if (channels != null) + for (SoftChannel c : channels) + c.current_instrument = null; + for (Instrument instrument : instruments) { + String pat = patchToString(instrument.getPatch()); + availlist.remove(pat); + SoftInstrument softins + = new SoftInstrument((ModelInstrument) instrument); + inslist.put(pat, softins); + loadedlist.put(pat, (ModelInstrument) instrument); + } + } + + return true; + } + + private void processPropertyInfo(Map info) { + AudioSynthesizerPropertyInfo[] items = getPropertyInfo(info); + + String resamplerType = (String)items[0].value; + if (resamplerType.equalsIgnoreCase("point")) + this.resampler = new SoftPointResampler(); + else if (resamplerType.equalsIgnoreCase("linear")) + this.resampler = new SoftLinearResampler2(); + else if (resamplerType.equalsIgnoreCase("linear1")) + this.resampler = new SoftLinearResampler(); + else if (resamplerType.equalsIgnoreCase("linear2")) + this.resampler = new SoftLinearResampler2(); + else if (resamplerType.equalsIgnoreCase("cubic")) + this.resampler = new SoftCubicResampler(); + else if (resamplerType.equalsIgnoreCase("lanczos")) + this.resampler = new SoftLanczosResampler(); + else if (resamplerType.equalsIgnoreCase("sinc")) + this.resampler = new SoftSincResampler(); + + setFormat((AudioFormat)items[2].value); + controlrate = (Float)items[1].value; + latency = (Long)items[3].value; + deviceid = (Integer)items[4].value; + maxpoly = (Integer)items[5].value; + reverb_on = (Boolean)items[6].value; + chorus_on = (Boolean)items[7].value; + agc_on = (Boolean)items[8].value; + largemode = (Boolean)items[9].value; + number_of_midi_channels = (Integer)items[10].value; + jitter_correction = (Boolean)items[11].value; + } + + private String patchToString(Patch patch) { + if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) + return "p." + patch.getProgram() + "." + patch.getBank(); + else + return patch.getProgram() + "." + patch.getBank(); + } + + private void setFormat(AudioFormat format) { + if (format.getChannels() > 2) { + throw new IllegalArgumentException( + "Only mono and stereo audio supported."); + } + if (AudioFloatConverter.getConverter(format) == null) + throw new IllegalArgumentException("Audio format not supported."); + this.format = format; + } + + protected void removeReceiver(Receiver recv) { + boolean perform_close = false; + synchronized (control_mutex) { + if (recvslist.remove(recv)) { + if (implicitOpen && recvslist.isEmpty()) + perform_close = true; + } + } + if (perform_close) + close(); + } + + protected SoftMainMixer getMainMixer() { + if (!isOpen()) + return null; + return mainmixer; + } + + protected SoftInstrument findInstrument(int program, int bank, int channel) { + + // Add support for GM2 banks 0x78 and 0x79 + // as specified in DLS 2.2 in Section 1.4.6 + // which allows using percussion and melodic instruments + // on all channels + if (bank >> 7 == 0x78 || bank >> 7 == 0x79) { + SoftInstrument current_instrument + = inslist.get(program + "." + bank); + if (current_instrument != null) + return current_instrument; + + String p_plaf; + if (bank >> 7 == 0x78) + p_plaf = "p."; + else + p_plaf = ""; + + // Instrument not found fallback to MSB:bank, LSB:0 + current_instrument = inslist.get(p_plaf + program + "." + + ((bank & 128) << 7)); + if (current_instrument != null) + return current_instrument; + // Instrument not found fallback to MSB:0, LSB:bank + current_instrument = inslist.get(p_plaf + program + "." + + (bank & 128)); + if (current_instrument != null) + return current_instrument; + // Instrument not found fallback to MSB:0, LSB:0 + current_instrument = inslist.get(p_plaf + program + ".0"); + if (current_instrument != null) + return current_instrument; + // Instrument not found fallback to MSB:0, LSB:0, program=0 + current_instrument = inslist.get(p_plaf + program + "0.0"); + if (current_instrument != null) + return current_instrument; + return null; + } + + // Channel 10 uses percussion instruments + String p_plaf; + if (channel == 9) + p_plaf = "p."; + else + p_plaf = ""; + + SoftInstrument current_instrument + = inslist.get(p_plaf + program + "." + bank); + if (current_instrument != null) + return current_instrument; + // Instrument not found fallback to MSB:0, LSB:0 + current_instrument = inslist.get(p_plaf + program + ".0"); + if (current_instrument != null) + return current_instrument; + // Instrument not found fallback to MSB:0, LSB:0, program=0 + current_instrument = inslist.get(p_plaf + "0.0"); + if (current_instrument != null) + return current_instrument; + return null; + } + + protected int getVoiceAllocationMode() { + return voice_allocation_mode; + } + + protected int getGeneralMidiMode() { + return gmmode; + } + + protected void setGeneralMidiMode(int gmmode) { + this.gmmode = gmmode; + } + + protected int getDeviceID() { + return deviceid; + } + + protected float getControlRate() { + return controlrate; + } + + protected SoftVoice[] getVoices() { + return voices; + } + + protected SoftTuning getTuning(Patch patch) { + String t_id = patchToString(patch); + SoftTuning tuning = tunings.get(t_id); + if (tuning == null) { + tuning = new SoftTuning(patch); + tunings.put(t_id, tuning); + } + return tuning; + } + + public long getLatency() { + synchronized (control_mutex) { + return latency; + } + } + + public AudioFormat getFormat() { + synchronized (control_mutex) { + return format; + } + } + + public int getMaxPolyphony() { + synchronized (control_mutex) { + return maxpoly; + } + } + + public MidiChannel[] getChannels() { + + synchronized (control_mutex) { + // if (external_channels == null) => the synthesizer is not open, + // create 16 proxy channels + // otherwise external_channels has the same length as channels array + if (external_channels == null) { + external_channels = new SoftChannelProxy[16]; + for (int i = 0; i < external_channels.length; i++) + external_channels[i] = new SoftChannelProxy(); + } + MidiChannel[] ret; + if (isOpen()) + ret = new MidiChannel[channels.length]; + else + ret = new MidiChannel[16]; + for (int i = 0; i < ret.length; i++) + ret[i] = external_channels[i]; + return ret; + } + } + + public VoiceStatus[] getVoiceStatus() { + if (!isOpen()) { + VoiceStatus[] tempVoiceStatusArray + = new VoiceStatus[getMaxPolyphony()]; + for (int i = 0; i < tempVoiceStatusArray.length; i++) { + VoiceStatus b = new VoiceStatus(); + b.active = false; + b.bank = 0; + b.channel = 0; + b.note = 0; + b.program = 0; + b.volume = 0; + tempVoiceStatusArray[i] = b; + } + return tempVoiceStatusArray; + } + + synchronized (control_mutex) { + VoiceStatus[] tempVoiceStatusArray = new VoiceStatus[voices.length]; + for (int i = 0; i < voices.length; i++) { + VoiceStatus a = voices[i]; + VoiceStatus b = new VoiceStatus(); + b.active = a.active; + b.bank = a.bank; + b.channel = a.channel; + b.note = a.note; + b.program = a.program; + b.volume = a.volume; + tempVoiceStatusArray[i] = b; + } + return tempVoiceStatusArray; + } + } + + public boolean isSoundbankSupported(Soundbank soundbank) { + for (Instrument ins: soundbank.getInstruments()) + if (!(ins instanceof ModelInstrument)) + return false; + return true; + } + + public boolean loadInstrument(Instrument instrument) { + if (instrument == null || (!(instrument instanceof ModelInstrument))) { + throw new IllegalArgumentException("Unsupported instrument: " + + instrument.toString()); + } + List instruments = new ArrayList(); + instruments.add((ModelInstrument)instrument); + return loadInstruments(instruments); + } + + public void unloadInstrument(Instrument instrument) { + if (instrument == null || (!(instrument instanceof ModelInstrument))) { + throw new IllegalArgumentException("Unsupported instrument: " + + instrument.toString()); + } + if (!isOpen()) + return; + + String pat = patchToString(instrument.getPatch()); + synchronized (control_mutex) { + for (SoftChannel c: channels) + c.current_instrument = null; + inslist.remove(pat); + loadedlist.remove(pat); + availlist.remove(pat); + } + } + + public boolean remapInstrument(Instrument from, Instrument to) { + + if (from == null) + throw new NullPointerException(); + if (to == null) + throw new NullPointerException(); + if (!(from instanceof ModelInstrument)) { + throw new IllegalArgumentException("Unsupported instrument: " + + from.toString()); + } + if (!(to instanceof ModelInstrument)) { + throw new IllegalArgumentException("Unsupported instrument: " + + to.toString()); + } + if (!isOpen()) + return false; + + synchronized (control_mutex) { + if (!loadedlist.containsValue(to) && !availlist.containsValue(to)) + throw new IllegalArgumentException("Instrument to is not loaded."); + unloadInstrument(from); + ModelMappedInstrument mfrom = new ModelMappedInstrument( + (ModelInstrument)to, from.getPatch()); + return loadInstrument(mfrom); + } + } + + public synchronized Soundbank getDefaultSoundbank() { + if (defaultSoundBank == null) { + try { + File javahome = new File(System.getProperties().getProperty( + "java.home")); + File libaudio = new File(new File(javahome, "lib"), "audio"); + + if (libaudio.exists()) { + File foundfile = null; + File[] files = libaudio.listFiles(); + if (files != null) { + for (int i = 0; i < files.length; i++) { + File file = files[i]; + if (file.isFile()) { + String lname = file.getName().toLowerCase(); + if (lname.endsWith(".sf2") || + lname.endsWith(".dls")) { + if (foundfile == null || (file.length() > + foundfile.length())) { + foundfile = file; + } + } + } + } + } + if (foundfile != null) { + try { + Soundbank sbk = MidiSystem.getSoundbank(foundfile); + defaultSoundBank = sbk; + return defaultSoundBank; + } catch (Exception e) { + //e.printStackTrace(); + } + } + } + + if (System.getProperties().getProperty("os.name") + .startsWith("Windows")) { + File gm_dls = new File(System.getenv("SystemRoot") + + "\\system32\\drivers\\gm.dls"); + if (gm_dls.exists()) { + try { + Soundbank sbk = MidiSystem.getSoundbank(gm_dls); + defaultSoundBank = sbk; + return defaultSoundBank; + } catch (Exception e) { + //e.printStackTrace(); + } + } + } + } catch (AccessControlException e) { + } catch (Exception e) { + //e.printStackTrace(); + } + + try { + defaultSoundBank = EmergencySoundbank.createSoundbank(); + } catch (Exception e) { + //e.printStackTrace(); + } + + } + return defaultSoundBank; + } + + public Instrument[] getAvailableInstruments() { + if (!isOpen()) { + Soundbank defsbk = getDefaultSoundbank(); + if (defsbk == null) + return new Instrument[0]; + return defsbk.getInstruments(); + } + + synchronized (control_mutex) { + ModelInstrument[] inslist_array = + new ModelInstrument[availlist.values().size()]; + availlist.values().toArray(inslist_array); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; + } + } + + public Instrument[] getLoadedInstruments() { + if (!isOpen()) + return new Instrument[0]; + + synchronized (control_mutex) { + ModelInstrument[] inslist_array = + new ModelInstrument[loadedlist.values().size()]; + loadedlist.values().toArray(inslist_array); + Arrays.sort(inslist_array, new ModelInstrumentComparator()); + return inslist_array; + } + } + + public boolean loadAllInstruments(Soundbank soundbank) { + List instruments = new ArrayList(); + for (Instrument ins: soundbank.getInstruments()) { + if (ins == null || !(ins instanceof ModelInstrument)) { + throw new IllegalArgumentException( + "Unsupported instrument: " + ins); + } + instruments.add((ModelInstrument)ins); + } + return loadInstruments(instruments); + } + + public void unloadAllInstruments(Soundbank soundbank) { + if (!isOpen()) + return; + + for (Instrument ins: soundbank.getInstruments()) { + if (ins instanceof ModelInstrument) { + unloadInstrument(ins); + } + } + } + + public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) { + List instruments = new ArrayList(); + for (Patch patch: patchList) { + Instrument ins = soundbank.getInstrument(patch); + if (ins == null || !(ins instanceof ModelInstrument)) { + throw new IllegalArgumentException( + "Unsupported instrument: " + ins); + } + instruments.add((ModelInstrument)ins); + } + return loadInstruments(instruments); + } + + public void unloadInstruments(Soundbank soundbank, Patch[] patchList) { + if (!isOpen()) + return; + + for (Patch pat: patchList) { + Instrument ins = soundbank.getInstrument(pat); + if (ins instanceof ModelInstrument) { + unloadInstrument(ins); + } + } + } + + public MidiDevice.Info getDeviceInfo() { + return info; + } + + public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map info) { + List list = + new ArrayList(); + + AudioSynthesizerPropertyInfo item; + + item = new AudioSynthesizerPropertyInfo("interpolation", "linear"); + item.choices = new String[]{"linear", "linear1", "linear2", "cubic", + "lanczos", "sinc", "point"}; + item.description = "Interpolation method"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("control rate", 147f); + item.description = "Control rate"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("format", + new AudioFormat(44100, 16, 2, true, false)); + item.description = "Default audio format"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("latency", 120000L); + item.description = "Default latency"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("device id", 0); + item.description = "Device ID for SysEx Messages"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("max polyphony", 64); + item.description = "Maximum polyphony"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("reverb", true); + item.description = "Turn reverb effect on or off"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("chorus", true); + item.description = "Turn chorus effect on or off"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("auto gain control", true); + item.description = "Turn auto gain control on or off"; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("large mode", false); + item.description = "Turn large mode on or off."; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("midi channels", 16); + item.description = "Number of midi channels."; + list.add(item); + + item = new AudioSynthesizerPropertyInfo("jitter correction", true); + item.description = "Turn jitter correction on or off."; + list.add(item); + + AudioSynthesizerPropertyInfo[] items; + items = list.toArray(new AudioSynthesizerPropertyInfo[list.size()]); + + if (info != null) + for (AudioSynthesizerPropertyInfo item2: items) { + Object v = info.get(item2.name); + Class c = (item2.valueClass); + if (v != null) + if (c.isInstance(v)) + item2.value = v; + } + + return items; + } + + public void open() throws MidiUnavailableException { + if (isOpen()) { + synchronized (control_mutex) { + implicitOpen = false; + } + return; + } + open(null, null); + } + + public void open(SourceDataLine line, Map info) throws MidiUnavailableException { + if (isOpen()) { + synchronized (control_mutex) { + implicitOpen = false; + } + return; + } + synchronized (control_mutex) { + try { + if (line != null) + setFormat(line.getFormat()); + + AudioInputStream ais = openStream(getFormat(), info); + + if (line == null) + line = AudioSystem.getSourceDataLine(getFormat()); + + double latency = this.latency; + + if (!line.isOpen()) { + int bufferSize = getFormat().getFrameSize() + * (int)(getFormat().getFrameRate() * (latency/1000000f)); + line.open(getFormat(), bufferSize); + + // Remember that we opened that line + // so we can close again in SoftSynthesizer.close() + sourceDataLine = line; + } + if (!line.isActive()) + line.start(); + + int controlbuffersize = 512; + try { + controlbuffersize = ais.available(); + } catch (IOException e) { + } + + // Tell mixer not fill read buffers fully. + // This lowers latency, and tells DataPusher + // to read in smaller amounts. + //mainmixer.readfully = false; + //pusher = new DataPusher(line, ais); + + int buffersize = line.getBufferSize(); + buffersize -= buffersize % controlbuffersize; + + if (buffersize < 3 * controlbuffersize) + buffersize = 3 * controlbuffersize; + + if (jitter_correction) { + ais = new SoftJitterCorrector(ais, buffersize, + controlbuffersize); + } + pusher = new SoftAudioPusher(line, ais, controlbuffersize); + pusher_stream = ais; + pusher.start(); + + + } catch (LineUnavailableException e) { + if (isOpen()) + close(); + // am: need MidiUnavailableException(Throwable) ctor! + throw new MidiUnavailableException(e.toString()); + } + + } + } + + public AudioInputStream openStream(AudioFormat targetFormat, + Map info) throws MidiUnavailableException { + + if (isOpen()) + throw new MidiUnavailableException("Synthesizer is already open"); + + synchronized (control_mutex) { + open = true; + implicitOpen = false; + + gmmode = 0; + voice_allocation_mode = 0; + + processPropertyInfo(info); + if (targetFormat != null) + setFormat(targetFormat); + + Soundbank defbank = getDefaultSoundbank(); + if (defbank != null) { + loadAllInstruments(defbank); + availlist.putAll(loadedlist); + loadedlist.clear(); + } + + voices = new SoftVoice[maxpoly]; + for (int i = 0; i < maxpoly; i++) + voices[i] = new SoftVoice(this); + + mainmixer = new SoftMainMixer(this); + + channels = new SoftChannel[number_of_midi_channels]; + for (int i = 0; i < channels.length; i++) + channels[i] = new SoftChannel(this, i); + + if (external_channels == null) { + // Always create external_channels array + // with 16 or more channels + // so getChannels works correctly + // when the synhtesizer is closed. + if (channels.length < 16) + external_channels = new SoftChannelProxy[16]; + else + external_channels = new SoftChannelProxy[channels.length]; + for (int i = 0; i < external_channels.length; i++) + external_channels[i] = new SoftChannelProxy(); + } else { + // We must resize external_channels array + // but we must also copy the old SoftChannelProxy + // into the new one + if (channels.length > external_channels.length) { + SoftChannelProxy[] new_external_channels + = new SoftChannelProxy[channels.length]; + for (int i = 0; i < external_channels.length; i++) + new_external_channels[i] = external_channels[i]; + for (int i = external_channels.length; + i < new_external_channels.length; i++) { + new_external_channels[i] = new SoftChannelProxy(); + } + } + } + + for (int i = 0; i < channels.length; i++) + external_channels[i].setChannel(channels[i]); + + for (SoftVoice voice: getVoices()) + voice.resampler = resampler.openStreamer(); + + for (Receiver recv: getReceivers()) { + SoftReceiver srecv = ((SoftReceiver)recv); + srecv.open = open; + srecv.mainmixer = mainmixer; + srecv.midimessages = mainmixer.midimessages; + } + + return mainmixer.getInputStream(); + } + } + + public void close() { + + if (!isOpen()) + return; + + SoftAudioPusher pusher_to_be_closed = null; + AudioInputStream pusher_stream_to_be_closed = null; + synchronized (control_mutex) { + if (pusher != null) { + pusher_to_be_closed = pusher; + pusher_stream_to_be_closed = pusher_stream; + pusher = null; + pusher_stream = null; + } + } + + if (pusher_to_be_closed != null) { + // Pusher must not be closed synchronized against control_mutex, + // this may result in synchronized conflict between pusher + // and current thread. + pusher_to_be_closed.stop(); + + try { + pusher_stream_to_be_closed.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + } + + synchronized (control_mutex) { + + if (mainmixer != null) + mainmixer.close(); + open = false; + implicitOpen = false; + mainmixer = null; + voices = null; + channels = null; + + if (external_channels != null) + for (int i = 0; i < external_channels.length; i++) + external_channels[i].setChannel(null); + + if (sourceDataLine != null) { + sourceDataLine.drain(); + sourceDataLine.close(); + sourceDataLine = null; + } + + inslist.clear(); + availlist.clear(); + loadedlist.clear(); + tunings.clear(); + + while (recvslist.size() != 0) + recvslist.get(recvslist.size() - 1).close(); + + } + } + + public boolean isOpen() { + synchronized (control_mutex) { + return open; + } + } + + public long getMicrosecondPosition() { + + if (!isOpen()) + return 0; + + synchronized (control_mutex) { + return mainmixer.getMicrosecondPosition(); + } + } + + public int getMaxReceivers() { + return -1; + } + + public int getMaxTransmitters() { + return 0; + } + + public Receiver getReceiver() throws MidiUnavailableException { + + synchronized (control_mutex) { + SoftReceiver receiver = new SoftReceiver(this); + receiver.open = open; + recvslist.add(receiver); + return receiver; + } + } + + public List getReceivers() { + + synchronized (control_mutex) { + ArrayList recvs = new ArrayList(); + recvs.addAll(recvslist); + return recvs; + } + } + + public Transmitter getTransmitter() throws MidiUnavailableException { + + throw new MidiUnavailableException("No transmitter available"); + } + + public List getTransmitters() { + + return new ArrayList(); + } + + public Receiver getReceiverReferenceCounting() + throws MidiUnavailableException { + + if (!isOpen()) { + open(); + synchronized (control_mutex) { + implicitOpen = true; + } + } + + return getReceiver(); + } + + public Transmitter getTransmitterReferenceCounting() + throws MidiUnavailableException { + + throw new MidiUnavailableException("No transmitter available"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftTuning.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftTuning.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,256 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.UnsupportedEncodingException; + +import javax.sound.midi.Patch; + +/** + * A tuning program container, for use with MIDI Tuning. + * See: http://www.midi.org + * + * @author Karl Helgason + */ +public class SoftTuning { + + private String name = null; + private double[] tuning = new double[128]; + private Patch patch = null; + + public SoftTuning() { + name = "12-TET"; + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100; + } + + public SoftTuning(byte[] data) { + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100; + load(data); + } + + public SoftTuning(Patch patch) { + this.patch = patch; + name = "12-TET"; + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100; + } + + public SoftTuning(Patch patch, byte[] data) { + this.patch = patch; + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100; + load(data); + } + + private boolean checksumOK(byte[] data) { + int x = data[1] & 0xFF; + for (int i = 2; i < data.length - 2; i++) + x = x ^ (data[i] & 0xFF); + return (data[data.length - 2] & 0xFF) == (x & 127); + } + + /* + private boolean checksumOK2(byte[] data) { + int x = data[1] & 0xFF; // 7E + x = x ^ (data[2] & 0xFF); // + x = x ^ (data[4] & 0xFF); // nn + x = x ^ (data[5] & 0xFF); // tt + for (int i = 22; i < data.length - 2; i++) + x = x ^ (data[i] & 0xFF); + return (data[data.length - 2] & 0xFF) == (x & 127); + } + */ + public void load(byte[] data) { + // Universal Non-Real-Time / Real-Time SysEx + if ((data[1] & 0xFF) == 0x7E || (data[1] & 0xFF) == 0x7F) { + int subid1 = data[3] & 0xFF; + switch (subid1) { + case 0x08: // MIDI Tuning Standard + int subid2 = data[4] & 0xFF; + switch (subid2) { + case 0x01: // BULK TUNING DUMP (NON-REAL-TIME) + { + // http://www.midi.org/about-midi/tuning.shtml + //if (!checksumOK2(data)) + // break; + try { + name = new String(data, 6, 16, "ascii"); + } catch (UnsupportedEncodingException e) { + name = null; + } + int r = 22; + for (int i = 0; i < 128; i++) { + int xx = data[r++] & 0xFF; + int yy = data[r++] & 0xFF; + int zz = data[r++] & 0xFF; + if (!(xx == 127 && yy == 127 && zz == 127)) + tuning[i] = 100.0 * + (((xx * 16384) + (yy * 128) + zz) / 16384.0); + } + break; + } + case 0x02: // SINGLE NOTE TUNING CHANGE (REAL-TIME) + { + // http://www.midi.org/about-midi/tuning.shtml + int ll = data[6] & 0xFF; + int r = 7; + for (int i = 0; i < ll; i++) { + int kk = data[r++] & 0xFF; + int xx = data[r++] & 0xFF; + int yy = data[r++] & 0xFF; + int zz = data[r++] & 0xFF; + if (!(xx == 127 && yy == 127 && zz == 127)) + tuning[kk] = 100.0*(((xx*16384) + (yy*128) + zz)/16384.0); + } + break; + } + case 0x04: // KEY-BASED TUNING DUMP (NON-REAL-TIME) + { + // http://www.midi.org/about-midi/tuning_extens.shtml + if (!checksumOK(data)) + break; + try { + name = new String(data, 7, 16, "ascii"); + } catch (UnsupportedEncodingException e) { + name = null; + } + int r = 23; + for (int i = 0; i < 128; i++) { + int xx = data[r++] & 0xFF; + int yy = data[r++] & 0xFF; + int zz = data[r++] & 0xFF; + if (!(xx == 127 && yy == 127 && zz == 127)) + tuning[i] = 100.0*(((xx*16384) + (yy*128) + zz)/16384.0); + } + break; + } + case 0x05: // SCALE/OCTAVE TUNING DUMP, 1 byte format + // (NON-REAL-TIME) + { + // http://www.midi.org/about-midi/tuning_extens.shtml + if (!checksumOK(data)) + break; + try { + name = new String(data, 7, 16, "ascii"); + } catch (UnsupportedEncodingException e) { + name = null; + } + int[] octave_tuning = new int[12]; + for (int i = 0; i < 12; i++) + octave_tuning[i] = (data[i + 23] & 0xFF) - 64; + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100 + octave_tuning[i % 12]; + break; + } + case 0x06: // SCALE/OCTAVE TUNING DUMP, 2 byte format + // (NON-REAL-TIME) + { + // http://www.midi.org/about-midi/tuning_extens.shtml + if (!checksumOK(data)) + break; + try { + name = new String(data, 7, 16, "ascii"); + } catch (UnsupportedEncodingException e) { + name = null; + } + double[] octave_tuning = new double[12]; + for (int i = 0; i < 12; i++) { + int v = (data[i * 2 + 23] & 0xFF) * 128 + + (data[i * 2 + 24] & 0xFF); + octave_tuning[i] = (v / 8192.0 - 1) * 100.0; + } + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100 + octave_tuning[i % 12]; + break; + } + case 0x07: // SINGLE NOTE TUNING CHANGE (NON + // REAL-TIME/REAL-TIME) (BANK) + // http://www.midi.org/about-midi/tuning_extens.shtml + int ll = data[7] & 0xFF; + int r = 8; + for (int i = 0; i < ll; i++) { + int kk = data[r++] & 0xFF; + int xx = data[r++] & 0xFF; + int yy = data[r++] & 0xFF; + int zz = data[r++] & 0xFF; + if (!(xx == 127 && yy == 127 && zz == 127)) + tuning[kk] = 100.0 + * (((xx*16384) + (yy*128) + zz) / 16384.0); + } + break; + case 0x08: // scale/octave tuning 1-byte form (Non + // Real-Time/REAL-TIME) + { + // http://www.midi.org/about-midi/tuning-scale.shtml + int[] octave_tuning = new int[12]; + for (int i = 0; i < 12; i++) + octave_tuning[i] = (data[i + 8] & 0xFF) - 64; + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100 + octave_tuning[i % 12]; + break; + } + case 0x09: // scale/octave tuning 2-byte form (Non + // Real-Time/REAL-TIME) + { + // http://www.midi.org/about-midi/tuning-scale.shtml + double[] octave_tuning = new double[12]; + for (int i = 0; i < 12; i++) { + int v = (data[i * 2 + 8] & 0xFF) * 128 + + (data[i * 2 + 9] & 0xFF); + octave_tuning[i] = (v / 8192.0 - 1) * 100.0; + } + for (int i = 0; i < tuning.length; i++) + tuning[i] = i * 100 + octave_tuning[i % 12]; + break; + } + default: + break; + } + } + } + } + + public double[] getTuning() { + return tuning; + } + + public double getTuning(int noteNumber) { + return tuning[noteNumber]; + } + + public Patch getPatch() { + return patch; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/SoftVoice.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/SoftVoice.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,841 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.midi.VoiceStatus; + +/** + * Software synthesizer voice class. + * + * @author Karl Helgason + */ +public class SoftVoice extends VoiceStatus { + + public int exclusiveClass = 0; + public boolean releaseTriggered = false; + private int noteOn_noteNumber = 0; + private int noteOn_velocity = 0; + private int noteOff_velocity = 0; + protected ModelChannelMixer channelmixer = null; + protected double tunedKey = 0; + protected SoftTuning tuning = null; + protected SoftChannel stealer_channel = null; + protected ModelConnectionBlock[] stealer_extendedConnectionBlocks = null; + protected SoftPerformer stealer_performer = null; + protected ModelChannelMixer stealer_channelmixer = null; + protected int stealer_voiceID = -1; + protected int stealer_noteNumber = 0; + protected int stealer_velocity = 0; + protected boolean stealer_releaseTriggered = false; + protected int voiceID = -1; + protected boolean sustain = false; + protected boolean sostenuto = false; + protected boolean portamento = false; + private SoftFilter filter_left; + private SoftFilter filter_right; + private SoftProcess eg = new SoftEnvelopeGenerator(); + private SoftProcess lfo = new SoftLowFrequencyOscillator(); + protected Map objects = + new HashMap(); + protected SoftSynthesizer synthesizer; + protected SoftInstrument instrument; + protected SoftPerformer performer; + protected SoftChannel softchannel = null; + protected boolean on = false; + private boolean audiostarted = false; + private boolean started = false; + private boolean stopping = false; + private float osc_attenuation = 0.0f; + private ModelOscillatorStream osc_stream; + private int osc_stream_nrofchannels; + private float[][] osc_buff = new float[2][]; + private boolean osc_stream_off_transmitted = false; + private boolean out_mixer_end = false; + private float out_mixer_left = 0; + private float out_mixer_right = 0; + private float out_mixer_effect1 = 0; + private float out_mixer_effect2 = 0; + private float last_out_mixer_left = 0; + private float last_out_mixer_right = 0; + private float last_out_mixer_effect1 = 0; + private float last_out_mixer_effect2 = 0; + protected ModelConnectionBlock[] extendedConnectionBlocks = null; + private ModelConnectionBlock[] connections; + // Last value added to destination + private double[] connections_last = new double[50]; + // Pointer to source value + private double[][][] connections_src = new double[50][3][]; + // Key-based override (if any) + private int[][] connections_src_kc = new int[50][3]; + // Pointer to destination value + private double[][] connections_dst = new double[50][]; + private boolean soundoff = false; + private float lastMuteValue = 0; + private float lastSoloMuteValue = 0; + protected double[] co_noteon_keynumber = new double[1]; + protected double[] co_noteon_velocity = new double[1]; + protected double[] co_noteon_on = new double[1]; + private SoftControl co_noteon = new SoftControl() { + double[] keynumber = co_noteon_keynumber; + double[] velocity = co_noteon_velocity; + double[] on = co_noteon_on; + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("keynumber")) + return keynumber; + if (name.equals("velocity")) + return velocity; + if (name.equals("on")) + return on; + return null; + } + }; + private double[] co_mixer_active = new double[1]; + private double[] co_mixer_gain = new double[1]; + private double[] co_mixer_pan = new double[1]; + private double[] co_mixer_balance = new double[1]; + private double[] co_mixer_reverb = new double[1]; + private double[] co_mixer_chorus = new double[1]; + private SoftControl co_mixer = new SoftControl() { + double[] active = co_mixer_active; + double[] gain = co_mixer_gain; + double[] pan = co_mixer_pan; + double[] balance = co_mixer_balance; + double[] reverb = co_mixer_reverb; + double[] chorus = co_mixer_chorus; + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("active")) + return active; + if (name.equals("gain")) + return gain; + if (name.equals("pan")) + return pan; + if (name.equals("balance")) + return balance; + if (name.equals("reverb")) + return reverb; + if (name.equals("chorus")) + return chorus; + return null; + } + }; + private double[] co_osc_pitch = new double[1]; + private SoftControl co_osc = new SoftControl() { + double[] pitch = co_osc_pitch; + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("pitch")) + return pitch; + return null; + } + }; + private double[] co_filter_freq = new double[1]; + private double[] co_filter_type = new double[1]; + private double[] co_filter_q = new double[1]; + private SoftControl co_filter = new SoftControl() { + double[] freq = co_filter_freq; + double[] ftype = co_filter_type; + double[] q = co_filter_q; + public double[] get(int instance, String name) { + if (name == null) + return null; + if (name.equals("freq")) + return freq; + if (name.equals("type")) + return ftype; + if (name.equals("q")) + return q; + return null; + } + }; + protected SoftResamplerStreamer resampler; + private int nrofchannels; + + public SoftVoice(SoftSynthesizer synth) { + synthesizer = synth; + filter_left = new SoftFilter(synth.getFormat().getSampleRate()); + filter_right = new SoftFilter(synth.getFormat().getSampleRate()); + nrofchannels = synth.getFormat().getChannels(); + } + + private int getValueKC(ModelIdentifier id) { + if (id.getObject().equals("midi_cc")) { + int ic = Integer.parseInt(id.getVariable()); + if (ic != 0 && ic != 32) { + if (ic < 120) + return ic; + } + } else if (id.getObject().equals("midi_rpn")) { + if (id.getVariable().equals("1")) + return 120; // Fine tuning + if (id.getVariable().equals("2")) + return 121; // Coarse tuning + } + return -1; + } + + private double[] getValue(ModelIdentifier id) { + SoftControl o = objects.get(id.getObject()); + if (o == null) + return null; + return o.get(id.getInstance(), id.getVariable()); + } + + private double transformValue(double value, ModelSource src) { + if (src.getTransform() != null) + return src.getTransform().transform(value); + else + return value; + } + + private double transformValue(double value, ModelDestination dst) { + if (dst.getTransform() != null) + return dst.getTransform().transform(value); + else + return value; + } + + private double processKeyBasedController(double value, int keycontrol) { + if (keycontrol == -1) + return value; + if (softchannel.keybasedcontroller_active != null) + if (softchannel.keybasedcontroller_active[note] != null) + if (softchannel.keybasedcontroller_active[note][keycontrol]) { + double key_controlvalue = + softchannel.keybasedcontroller_value[note][keycontrol]; + if (keycontrol == 10 || keycontrol == 91 || keycontrol == 93) + return key_controlvalue; + value += key_controlvalue * 2.0 - 1.0; + if (value > 1) + value = 1; + else if (value < 0) + value = 0; + } + return value; + } + + private void processConnection(int ix) { + ModelConnectionBlock conn = connections[ix]; + double[][] src = connections_src[ix]; + double[] dst = connections_dst[ix]; + if (dst == null || Double.isInfinite(dst[0])) + return; + + double value = conn.getScale(); + if (softchannel.keybasedcontroller_active == null) { + ModelSource[] srcs = conn.getSources(); + for (int i = 0; i < srcs.length; i++) { + value *= transformValue(src[i][0], srcs[i]); + if (value == 0) + break; + } + } else { + ModelSource[] srcs = conn.getSources(); + int[] src_kc = connections_src_kc[ix]; + for (int i = 0; i < srcs.length; i++) { + value *= transformValue(processKeyBasedController(src[i][0], + src_kc[i]), srcs[i]); + if (value == 0) + break; + } + } + + value = transformValue(value, conn.getDestination()); + dst[0] = dst[0] - connections_last[ix] + value; + connections_last[ix] = value; + // co_mixer_gain[0] = 0; + } + + protected void updateTuning(SoftTuning newtuning) { + tunedKey = tuning.getTuning(note) / 100.0; + if (!portamento) { + co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0); + int[] c = performer.midi_connections[4]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + } + + protected void setNote(int noteNumber) { + note = noteNumber; + tunedKey = tuning.getTuning(noteNumber) / 100.0; + } + + protected void noteOn(int noteNumber, int velocity) { + + sustain = false; + sostenuto = false; + portamento = false; + + soundoff = false; + on = true; + active = true; + started = true; + // volume = velocity; + + noteOn_noteNumber = noteNumber; + noteOn_velocity = velocity; + + lastMuteValue = 0; + lastSoloMuteValue = 0; + + setNote(noteNumber); + + if (performer.forcedKeynumber) + co_noteon_keynumber[0] = 0; + else + co_noteon_keynumber[0] = tunedKey * (1f / 128f); + if (performer.forcedVelocity) + co_noteon_velocity[0] = 0; + else + co_noteon_velocity[0] = velocity * (1f / 128f); + co_mixer_active[0] = 0; + co_mixer_gain[0] = 0; + co_mixer_pan[0] = 0; + co_mixer_balance[0] = 0; + co_mixer_reverb[0] = 0; + co_mixer_chorus[0] = 0; + co_osc_pitch[0] = 0; + co_filter_freq[0] = 0; + co_filter_q[0] = 0; + co_filter_type[0] = 0; + co_noteon_on[0] = 1; + + eg.reset(); + lfo.reset(); + filter_left.reset(); + filter_right.reset(); + + objects.put("master", synthesizer.getMainMixer().co_master); + objects.put("eg", eg); + objects.put("lfo", lfo); + objects.put("noteon", co_noteon); + objects.put("osc", co_osc); + objects.put("mixer", co_mixer); + objects.put("filter", co_filter); + + connections = performer.connections; + + if (connections_last == null + || connections_last.length < connections.length) { + connections_last = new double[connections.length]; + } + if (connections_src == null + || connections_src.length < connections.length) { + connections_src = new double[connections.length][][]; + connections_src_kc = new int[connections.length][]; + } + if (connections_dst == null + || connections_dst.length < connections.length) { + connections_dst = new double[connections.length][]; + } + for (int i = 0; i < connections.length; i++) { + ModelConnectionBlock conn = connections[i]; + connections_last[i] = 0; + if (conn.getSources() != null) { + ModelSource[] srcs = conn.getSources(); + if (connections_src[i] == null + || connections_src[i].length < srcs.length) { + connections_src[i] = new double[srcs.length][]; + connections_src_kc[i] = new int[srcs.length]; + } + double[][] src = connections_src[i]; + int[] src_kc = connections_src_kc[i]; + connections_src[i] = src; + for (int j = 0; j < srcs.length; j++) { + src_kc[j] = getValueKC(srcs[j].getIdentifier()); + src[j] = getValue(srcs[j].getIdentifier()); + } + } + + if (conn.getDestination() != null) + connections_dst[i] = getValue(conn.getDestination() + .getIdentifier()); + else + connections_dst[i] = null; + } + + for (int i = 0; i < connections.length; i++) + processConnection(i); + + if (extendedConnectionBlocks != null) { + for (ModelConnectionBlock connection: extendedConnectionBlocks) { + double value = 0; + + if (softchannel.keybasedcontroller_active == null) { + for (ModelSource src: connection.getSources()) { + double x = getValue(src.getIdentifier())[0]; + ModelTransform t = src.getTransform(); + if (t == null) + value += x; + else + value += t.transform(x); + } + } else { + for (ModelSource src: connection.getSources()) { + double x = getValue(src.getIdentifier())[0]; + x = processKeyBasedController(x, + getValueKC(src.getIdentifier())); + ModelTransform t = src.getTransform(); + if (t == null) + value += x; + else + value += t.transform(x); + } + } + + ModelDestination dest = connection.getDestination(); + ModelTransform t = dest.getTransform(); + if (t != null) + value = t.transform(value); + getValue(dest.getIdentifier())[0] += value; + } + } + + eg.init(synthesizer); + lfo.init(synthesizer); + + } + + protected void setPolyPressure(int pressure) { + int[] c = performer.midi_connections[2]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void setChannelPressure(int pressure) { + int[] c = performer.midi_connections[1]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void controlChange(int controller, int value) { + int[] c = performer.midi_ctrl_connections[controller]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void nrpnChange(int controller, int value) { + int[] c = performer.midi_nrpn_connections.get(controller); + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void rpnChange(int controller, int value) { + int[] c = performer.midi_rpn_connections.get(controller); + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void setPitchBend(int bend) { + int[] c = performer.midi_connections[0]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void setMute(boolean mute) { + co_mixer_gain[0] -= lastMuteValue; + lastMuteValue = mute ? -960 : 0; + co_mixer_gain[0] += lastMuteValue; + } + + protected void setSoloMute(boolean mute) { + co_mixer_gain[0] -= lastSoloMuteValue; + lastSoloMuteValue = mute ? -960 : 0; + co_mixer_gain[0] += lastSoloMuteValue; + } + + protected void shutdown() { + if (co_noteon_on[0] < -0.5) + return; + on = false; + + co_noteon_on[0] = -1; + + int[] c = performer.midi_connections[3]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void soundOff() { + on = false; + soundoff = true; + } + + protected void noteOff(int velocity) { + if (!on) + return; + on = false; + + noteOff_velocity = velocity; + + if (softchannel.sustain) { + sustain = true; + return; + } + if (sostenuto) + return; + + co_noteon_on[0] = 0; + + int[] c = performer.midi_connections[3]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void redamp() { + if (co_noteon_on[0] > 0.5) + return; + if (co_noteon_on[0] < -0.5) + return; // don't redamp notes in shutdown stage + + sustain = true; + co_noteon_on[0] = 1; + + int[] c = performer.midi_connections[3]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + protected void processControlLogic() { + if (stopping) { + active = false; + stopping = false; + audiostarted = false; + if (osc_stream != null) + try { + osc_stream.close(); + } catch (IOException e) { + //e.printStackTrace(); + } + + if (stealer_channel != null) { + stealer_channel.initVoice(this, stealer_performer, + stealer_voiceID, stealer_noteNumber, stealer_velocity, + stealer_extendedConnectionBlocks, stealer_channelmixer, + stealer_releaseTriggered); + stealer_releaseTriggered = false; + stealer_channel = null; + stealer_performer = null; + stealer_voiceID = -1; + stealer_noteNumber = 0; + stealer_velocity = 0; + stealer_extendedConnectionBlocks = null; + stealer_channelmixer = null; + } + } + if (started) { + audiostarted = true; + + ModelOscillator osc = performer.oscillators[0]; + + osc_stream_off_transmitted = false; + if (osc instanceof ModelWavetable) { + try { + resampler.open((ModelWavetable)osc, + synthesizer.getFormat().getSampleRate()); + osc_stream = resampler; + } catch (IOException e) { + //e.printStackTrace(); + } + } else { + osc_stream = osc.open(synthesizer.getFormat().getSampleRate()); + } + osc_attenuation = osc.getAttenuation(); + osc_stream_nrofchannels = osc.getChannels(); + if (osc_buff == null || osc_buff.length < osc_stream_nrofchannels) + osc_buff = new float[osc_stream_nrofchannels][]; + + if (osc_stream != null) + osc_stream.noteOn(softchannel, this, noteOn_noteNumber, + noteOn_velocity); + + + } + if (audiostarted) { + if (portamento) { + double note_delta = tunedKey - (co_noteon_keynumber[0] * 128); + double note_delta_a = Math.abs(note_delta); + if (note_delta_a < 0.0000000001) { + co_noteon_keynumber[0] = tunedKey * (1.0 / 128.0); + portamento = false; + } else { + if (note_delta_a > softchannel.portamento_time) + note_delta = Math.signum(note_delta) + * softchannel.portamento_time; + co_noteon_keynumber[0] += note_delta * (1.0 / 128.0); + } + + int[] c = performer.midi_connections[4]; + if (c == null) + return; + for (int i = 0; i < c.length; i++) + processConnection(c[i]); + } + + eg.processControlLogic(); + lfo.processControlLogic(); + + for (int i = 0; i < performer.ctrl_connections.length; i++) + processConnection(performer.ctrl_connections[i]); + + osc_stream.setPitch((float)co_osc_pitch[0]); + + int filter_type = (int)co_filter_type[0]; + double filter_freq; + + if (co_filter_freq[0] == 13500.0) + filter_freq = 19912.126958213175; + else + filter_freq = 440.0 * Math.exp( + ((co_filter_freq[0]) - 6900.0) * + (Math.log(2.0) / 1200.0)); + /* + filter_freq = 440.0 * Math.pow(2.0, + ((co_filter_freq[0]) - 6900.0) / 1200.0);*/ + /* + * double velocity = co_noteon_velocity[0]; if(velocity < 0.5) + * filter_freq *= ((velocity * 2)*0.75 + 0.25); + */ + + double q = co_filter_q[0] / 10.0; + filter_left.setFilterType(filter_type); + filter_left.setFrequency(filter_freq); + filter_left.setResonance(q); + filter_right.setFilterType(filter_type); + filter_right.setFrequency(filter_freq); + filter_right.setResonance(q); + /* + float gain = (float) Math.pow(10, + (-osc_attenuation + co_mixer_gain[0]) / 200.0); + */ + float gain = (float)Math.exp( + (-osc_attenuation + co_mixer_gain[0])*(Math.log(10) / 200.0)); + + if (co_mixer_gain[0] <= -960) + gain = 0; + + if (soundoff) { + stopping = true; + gain = 0; + /* + * if(co_mixer_gain[0] > -960) + * co_mixer_gain[0] -= 960; + */ + } + + volume = (int)(Math.sqrt(gain) * 128); + + // gain *= 0.2; + + double pan = co_mixer_pan[0] * (1.0 / 1000.0); + // System.out.println("pan = " + pan); + if (pan < 0) + pan = 0; + else if (pan > 1) + pan = 1; + + if (pan == 0.5) { + out_mixer_left = gain * 0.7071067811865476f; + out_mixer_right = out_mixer_left; + } else { + out_mixer_left = gain * (float)Math.cos(pan * Math.PI * 0.5); + out_mixer_right = gain * (float)Math.sin(pan * Math.PI * 0.5); + } + + double balance = co_mixer_balance[0] * (1.0 / 1000.0); + if (balance != 0.5) { + if (balance > 0.5) + out_mixer_left *= (1 - balance) * 2; + else + out_mixer_right *= balance * 2; + } + + if (synthesizer.reverb_on) { + out_mixer_effect1 = (float)(co_mixer_reverb[0] * (1.0 / 1000.0)); + out_mixer_effect1 *= gain; + } else + out_mixer_effect1 = 0; + if (synthesizer.chorus_on) { + out_mixer_effect2 = (float)(co_mixer_chorus[0] * (1.0 / 1000.0)); + out_mixer_effect2 *= gain; + } else + out_mixer_effect2 = 0; + out_mixer_end = co_mixer_active[0] < 0.5; + + if (!on) + if (!osc_stream_off_transmitted) { + osc_stream_off_transmitted = true; + if (osc_stream != null) + osc_stream.noteOff(noteOff_velocity); + } + + } + if (started) { + last_out_mixer_left = out_mixer_left; + last_out_mixer_right = out_mixer_right; + last_out_mixer_effect1 = out_mixer_effect1; + last_out_mixer_effect2 = out_mixer_effect2; + started = false; + } + + } + + protected void mixAudioStream(SoftAudioBuffer in, SoftAudioBuffer out, + float amp_from, float amp_to) { + int bufferlen = in.getSize(); + if (amp_from < 0.000000001 && amp_to < 0.000000001) + return; + if (amp_from == amp_to) { + float[] fout = out.array(); + float[] fin = in.array(); + for (int i = 0; i < bufferlen; i++) + fout[i] += fin[i] * amp_to; + } else { + float amp = amp_from; + float amp_delta = (amp_to - amp_from) / bufferlen; + float[] fout = out.array(); + float[] fin = in.array(); + for (int i = 0; i < bufferlen; i++) { + amp += amp_delta; + fout[i] += fin[i] * amp; + } + } + + } + + protected void processAudioLogic(SoftAudioBuffer[] buffer) { + if (!audiostarted) + return; + + int bufferlen = buffer[0].getSize(); + + try { + osc_buff[0] = buffer[SoftMainMixer.CHANNEL_LEFT_DRY].array(); + if (nrofchannels != 1) + osc_buff[1] = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY].array(); + int ret = osc_stream.read(osc_buff, 0, bufferlen); + if (ret == -1) { + stopping = true; + return; + } + if (ret != bufferlen) { + Arrays.fill(osc_buff[0], ret, bufferlen, 0f); + if (nrofchannels != 1) + Arrays.fill(osc_buff[1], ret, bufferlen, 0f); + } + + } catch (IOException e) { + //e.printStackTrace(); + } + + SoftAudioBuffer left = buffer[SoftMainMixer.CHANNEL_LEFT]; + SoftAudioBuffer right = buffer[SoftMainMixer.CHANNEL_RIGHT]; + SoftAudioBuffer eff1 = buffer[SoftMainMixer.CHANNEL_EFFECT1]; + SoftAudioBuffer eff2 = buffer[SoftMainMixer.CHANNEL_EFFECT2]; + SoftAudioBuffer leftdry = buffer[SoftMainMixer.CHANNEL_LEFT_DRY]; + SoftAudioBuffer rightdry = buffer[SoftMainMixer.CHANNEL_RIGHT_DRY]; + + if (osc_stream_nrofchannels == 1) + rightdry = null; + + if (!Double.isInfinite(co_filter_freq[0])) { + filter_left.processAudio(leftdry); + if (rightdry != null) + filter_right.processAudio(rightdry); + } + + if (nrofchannels == 1) { + out_mixer_left = (out_mixer_left + out_mixer_right) / 2; + mixAudioStream(leftdry, left, last_out_mixer_left, out_mixer_left); + if (rightdry != null) + mixAudioStream(rightdry, left, last_out_mixer_left, + out_mixer_left); + } else { + mixAudioStream(leftdry, left, last_out_mixer_left, out_mixer_left); + if (rightdry != null) + mixAudioStream(rightdry, right, last_out_mixer_right, + out_mixer_right); + else + mixAudioStream(leftdry, right, last_out_mixer_right, + out_mixer_right); + } + + if (rightdry == null) { + mixAudioStream(leftdry, eff1, last_out_mixer_effect1, + out_mixer_effect1); + mixAudioStream(leftdry, eff2, last_out_mixer_effect2, + out_mixer_effect2); + } else { + mixAudioStream(leftdry, eff1, last_out_mixer_effect1 * 0.5f, + out_mixer_effect1 * 0.5f); + mixAudioStream(leftdry, eff2, last_out_mixer_effect2 * 0.5f, + out_mixer_effect2 * 0.5f); + mixAudioStream(rightdry, eff1, last_out_mixer_effect1 * 0.5f, + out_mixer_effect1 * 0.5f); + mixAudioStream(rightdry, eff2, last_out_mixer_effect2 * 0.5f, + out_mixer_effect2 * 0.5f); + } + + last_out_mixer_left = out_mixer_left; + last_out_mixer_right = out_mixer_right; + last_out_mixer_effect1 = out_mixer_effect1; + last_out_mixer_effect2 = out_mixer_effect2; + + if (out_mixer_end) { + stopping = true; + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/media/sound/WaveFloatFileReader.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,167 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.media.sound; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * Floating-point encoded (format 3) WAVE file loader. + * + * @author Karl Helgason + */ +public class WaveFloatFileReader extends AudioFileReader { + + public AudioFileFormat getAudioFileFormat(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + stream.mark(200); + AudioFileFormat format; + try { + format = internal_getAudioFileFormat(stream); + } finally { + stream.reset(); + } + return format; + } + + private AudioFileFormat internal_getAudioFileFormat(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + RIFFReader riffiterator = new RIFFReader(stream); + if (!riffiterator.getFormat().equals("RIFF")) + throw new UnsupportedAudioFileException(); + if (!riffiterator.getType().equals("WAVE")) + throw new UnsupportedAudioFileException(); + + boolean fmt_found = false; + boolean data_found = false; + + int channels = 1; + long samplerate = 1; + long framerate = 1; + int framesize = 1; + int bits = 1; + + while (riffiterator.hasNextChunk()) { + RIFFReader chunk = riffiterator.nextChunk(); + + if (chunk.getFormat().equals("fmt ")) { + fmt_found = true; + + int format = chunk.readUnsignedShort(); + if (format != 3) // WAVE_FORMAT_IEEE_FLOAT only + throw new UnsupportedAudioFileException(); + channels = chunk.readUnsignedShort(); + samplerate = chunk.readUnsignedInt(); + framerate = chunk.readUnsignedInt(); + framesize = chunk.readUnsignedShort(); + bits = chunk.readUnsignedShort(); + } + if (chunk.getFormat().equals("data")) { + data_found = true; + break; + } + } + + if (!fmt_found) + throw new UnsupportedAudioFileException(); + if (!data_found) + throw new UnsupportedAudioFileException(); + + AudioFormat audioformat = new AudioFormat( + AudioFloatConverter.PCM_FLOAT, samplerate, bits, channels, + framesize, framerate, false); + AudioFileFormat fileformat = new AudioFileFormat( + AudioFileFormat.Type.WAVE, audioformat, + AudioSystem.NOT_SPECIFIED); + return fileformat; + } + + public AudioInputStream getAudioInputStream(InputStream stream) + throws UnsupportedAudioFileException, IOException { + + AudioFileFormat format = getAudioFileFormat(stream); + RIFFReader riffiterator = new RIFFReader(stream); + if (!riffiterator.getFormat().equals("RIFF")) + throw new UnsupportedAudioFileException(); + if (!riffiterator.getType().equals("WAVE")) + throw new UnsupportedAudioFileException(); + while (riffiterator.hasNextChunk()) { + RIFFReader chunk = riffiterator.nextChunk(); + if (chunk.getFormat().equals("data")) { + return new AudioInputStream(chunk, format.getFormat(), + chunk.getSize()); + } + } + throw new UnsupportedAudioFileException(); + } + + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException { + InputStream stream = url.openStream(); + AudioFileFormat format; + try { + format = getAudioFileFormat(new BufferedInputStream(stream)); + } finally { + stream.close(); + } + return format; + } + + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException { + InputStream stream = new FileInputStream(file); + AudioFileFormat format; + try { + format = getAudioFileFormat(new BufferedInputStream(stream)); + } finally { + stream.close(); + } + return format; + } + + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } + + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException { + return getAudioInputStream(new BufferedInputStream(new FileInputStream( + file))); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiDeviceProvider --- a/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiDeviceProvider Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiDeviceProvider Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ # Providers for midi devices -com.sun.media.sound.MixerSynthProvider com.sun.media.sound.RealTimeSequencerProvider com.sun.media.sound.MidiOutDeviceProvider com.sun.media.sound.MidiInDeviceProvider +com.sun.media.sound.SoftProvider diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiFileReader --- a/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiFileReader Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.MidiFileReader Fri May 30 00:00:00 2008 +0200 @@ -1,3 +1,2 @@ # Providers for midi sequences com.sun.media.sound.StandardMidiFileReader -com.sun.media.sound.RmfFileReader diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.SoundbankReader --- a/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.SoundbankReader Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.midi.spi.SoundbankReader Fri May 30 00:00:00 2008 +0200 @@ -1,2 +1,5 @@ # Providers for Soundbanks -com.sun.media.sound.HsbParser +com.sun.media.sound.SF2SoundbankReader +com.sun.media.sound.DLSSoundbankReader +com.sun.media.sound.AudioFileSoundbankReader +com.sun.media.sound.JARSoundbankReader diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.AudioFileReader --- a/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.AudioFileReader Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.AudioFileReader Fri May 30 00:00:00 2008 +0200 @@ -2,3 +2,5 @@ com.sun.media.sound.AuFileReader com.sun.media.sound.AiffFileReader com.sun.media.sound.WaveFileReader +com.sun.media.sound.WaveFloatFileReader +com.sun.media.sound.SoftMidiAudioFileReader diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.MixerProvider --- a/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.MixerProvider Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/media/sound/services/javax.sound.sampled.spi.MixerProvider Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,3 @@ # last mixer is default mixer com.sun.media.sound.PortMixerProvider -com.sun.media.sound.SimpleInputDeviceProvider -com.sun.media.sound.HeadspaceMixerProvider com.sun.media.sound.DirectAudioDeviceProvider diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/Main.java --- a/jdk/src/share/classes/com/sun/tools/hat/Main.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/Main.java Fri May 30 00:00:00 2008 +0200 @@ -23,18 +23,10 @@ * have any questions. */ - /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. + * at JavaSoft/Sun. */ package com.sun.tools.hat; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/README.txt --- a/jdk/src/share/classes/com/sun/tools/hat/README.txt Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/README.txt Fri May 30 00:00:00 2008 +0200 @@ -1,4 +1,3 @@ -README on HAT: -------------- This HAT source originally came from the http://hat.dev.java.net site. diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/build.xml --- a/jdk/src/share/classes/com/sun/tools/hat/build.xml Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/build.xml Fri May 30 00:00:00 2008 +0200 @@ -27,19 +27,9 @@ diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/AbstractJavaHeapObjectVisitor.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/AbstractJavaHeapObjectVisitor.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/AbstractJavaHeapObjectVisitor.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; @@ -46,7 +35,6 @@ /** * A visitor for a JavaThing. @see JavaObject#visitReferencedObjects() * - * @author A. Sundararajan [jhat] */ diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/ArrayTypeCodes.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/ArrayTypeCodes.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/ArrayTypeCodes.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; @@ -46,7 +35,6 @@ /** * Primitive array type codes as defined by VM specification. * - * @author A. Sundararajan [jhat] */ public interface ArrayTypeCodes { // Typecodes for array elements. diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/HackJavaValue.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/HackJavaValue.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/HackJavaValue.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaBoolean.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaBoolean.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaByte.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaByte.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaByte.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaChar.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaChar.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaChar.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaClass.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaClass.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaClass.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaDouble.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaDouble.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaDouble.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaField.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaField.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaField.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaFloat.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaFloat.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaFloat.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObject.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObject.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObject.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObjectVisitor.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObjectVisitor.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaHeapObjectVisitor.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaInt.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaInt.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaInt.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLazyReadObject.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLazyReadObject.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLazyReadObject.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLong.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLong.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaLong.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObject.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObject.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObject.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectArray.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectArray.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectArray.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectRef.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectRef.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaObjectRef.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaShort.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaShort.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaShort.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaStatic.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaStatic.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaStatic.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaThing.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaThing.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaThing.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValue.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValue.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValue.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValueArray.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValueArray.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/JavaValueArray.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludes.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludes.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludes.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; @@ -50,7 +39,6 @@ * transitive closure of objects reachable from a given object, allowing * some kind of real determination of the "size" of that object. * - * @author A. Sundararajan [jhat] */ public interface ReachableExcludes { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludesImpl.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludesImpl.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableExcludesImpl.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableObjects.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableObjects.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReachableObjects.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/ReferenceChain.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReferenceChain.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/ReferenceChain.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/Root.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/Root.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/Root.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/Snapshot.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/Snapshot.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/Snapshot.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/StackFrame.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/StackFrame.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/StackFrame.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/model/StackTrace.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/model/StackTrace.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/model/StackTrace.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.model; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLEngine.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLEngine.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLEngine.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.oql; @@ -51,7 +40,6 @@ /** * This is Object Query Language Interpreter * - * @author A. Sundararajan [jhat] */ public class OQLEngine { static { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLException.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLException.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLException.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.oql; @@ -46,7 +35,6 @@ /** * OQLException is thrown if OQL execution results in error * - * @author A. Sundararajan [jhat] */ public class OQLException extends Exception { public OQLException(String msg) { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/oql/OQLQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.oql; @@ -46,7 +35,6 @@ /** * This represents a parsed OQL query * - * @author A. Sundararajan [jhat] */ class OQLQuery { OQLQuery(String selectExpr, boolean isInstanceOf, diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/oql/ObjectVisitor.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/oql/ObjectVisitor.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/oql/ObjectVisitor.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.oql; @@ -47,7 +36,6 @@ * This visitor is supplied to OQLEngine.executeQuery * to receive result set objects one by one. * - * @author A. Sundararajan [jhat] */ public interface ObjectVisitor { // return true to terminate the result set callback earlier diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/FileReadBuffer.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/FileReadBuffer.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/FileReadBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/HprofReader.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,11 @@ * have any questions. */ + /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/MappedReadBuffer.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/MappedReadBuffer.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/MappedReadBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,11 @@ * have any questions. */ + /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionDataInputStream.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionDataInputStream.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionDataInputStream.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; @@ -50,7 +39,6 @@ * A DataInputStream that keeps track of total bytes read * (in effect 'position' in stream) so far. * - * @author A. Sundararajan [jhat] */ public class PositionDataInputStream extends DataInputStream { public PositionDataInputStream(InputStream in) { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionInputStream.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionInputStream.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/PositionInputStream.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; @@ -51,7 +40,6 @@ * InputStream that keeps track of total bytes read (in effect * 'position' in stream) from the input stream. * - * @author A. Sundararajan [jhat] */ public class PositionInputStream extends FilterInputStream { private long position = 0L; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/ReadBuffer.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/ReadBuffer.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/ReadBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/parser/Reader.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/parser/Reader.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/parser/Reader.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.parser; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/AllClassesQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/AllClassesQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/AllClassesQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/AllRootsQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/AllRootsQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/AllRootsQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/ClassQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/ClassQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/ClassQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; @@ -99,8 +88,7 @@ } out.println("

    Instance Data Members:

    "); - JavaField[] ff = clazz.getFields(); - ff = (JavaField[]) ff.clone(); + JavaField[] ff = clazz.getFields().clone(); ArraySorter.sort(ff, new Comparer() { public int compare(Object lhs, Object rhs) { JavaField left = (JavaField) lhs; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerObjectsQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerObjectsQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerObjectsQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerSummaryQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerSummaryQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/FinalizerSummaryQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/HistogramQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/HistogramQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/HistogramQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; @@ -50,7 +39,6 @@ /** * Prints histogram sortable by class name, count and size. * - * @author A. Sundararajan [jhat] */ public class HistogramQuery extends QueryHandler { public void run() { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/HttpReader.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/HttpReader.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/HttpReader.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesCountQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesCountQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesCountQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/InstancesQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLHelp.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLHelp.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLHelp.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/OQLQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/ObjectQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/ObjectQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/ObjectQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/PlatformClasses.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/PlatformClasses.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/PlatformClasses.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; @@ -90,9 +81,7 @@ // is the right thing to do anyway. } } - int num = list.size(); - names = new String[num]; - names = (String[]) list.toArray(names); + names = list.toArray(new String[list.size()]); } return names; } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryHandler.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryHandler.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryHandler.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,10 @@ */ - -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryListener.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryListener.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/QueryListener.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/ReachableQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/ReachableQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/ReachableQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,10 @@ */ - -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/RefsByTypeQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/RefsByTypeQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/RefsByTypeQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; @@ -49,7 +38,6 @@ /** * References by type summary * - * @author A. Sundararajan [jhat] */ public class RefsByTypeQuery extends QueryHandler { public void run() { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/RootStackQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/RootStackQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/RootStackQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/server/RootsQuery.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/server/RootsQuery.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/server/RootsQuery.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.server; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/util/ArraySorter.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/util/ArraySorter.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/util/ArraySorter.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.util; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/util/Comparer.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/util/Comparer.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/util/Comparer.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.util; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/util/CompositeEnumeration.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/util/CompositeEnumeration.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/util/CompositeEnumeration.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,9 @@ /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.util; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/util/Misc.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/util/Misc.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/util/Misc.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.util; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/internal/util/VectorSorter.java --- a/jdk/src/share/classes/com/sun/tools/hat/internal/util/VectorSorter.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/internal/util/VectorSorter.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,10 @@ */ -/* The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * +/* * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. + * at JavaSoft/Sun. */ package com.sun.tools.hat.internal.util; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/resources/hat.js --- a/jdk/src/share/classes/com/sun/tools/hat/resources/hat.js Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/resources/hat.js Fri May 30 00:00:00 2008 +0200 @@ -23,22 +23,10 @@ * have any questions. */ - /* - * The contents of this file are subject to the Sun Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. A copy of the License is available at - * http://www.sun.com/, and in the file LICENSE.html in the - * doc directory. - * * The Original Code is HAT. The Initial Developer of the * Original Code is Bill Foote, with contributions from others - * at JavaSoft/Sun. Portions created by Bill Foote and others - * at Javasoft/Sun are Copyright (C) 1997-2004. All Rights Reserved. - * - * In addition to the formal license, I ask that you don't - * change the history or donations files without permission. - * + * at JavaSoft/Sun. */ var hatPkg = Packages.com.sun.tools.hat.internal; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html --- a/jdk/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/com/sun/tools/hat/resources/oqlhelp.html Fri May 30 00:00:00 2008 +0200 @@ -25,7 +25,6 @@ - diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/java/beans/MetaData.java --- a/jdk/src/share/classes/java/beans/MetaData.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/java/beans/MetaData.java Fri May 30 00:00:00 2008 +0200 @@ -1420,7 +1420,7 @@ registerConstructor("javax.swing.plaf.BorderUIResource$EmptyBorderUIResource", new String[]{"borderInsets"}); registerConstructor("javax.swing.border.EtchedBorder", new String[]{"etchType", "highlightColor", "shadowColor"}); registerConstructor("javax.swing.plaf.BorderUIResource$EtchedBorderUIResource", new String[]{"etchType", "highlightColor", "shadowColor"}); - registerConstructor("javax.swing.border.LineBorder", new String[]{"lineColor", "thickness"}); + registerConstructor("javax.swing.border.LineBorder", new String[]{"lineColor", "thickness", "roundedCorners"}); registerConstructor("javax.swing.plaf.BorderUIResource$LineBorderUIResource", new String[]{"lineColor", "thickness"}); registerConstructor("javax.swing.border.SoftBevelBorder", new String[]{"bevelType", "highlightOuterColor", "highlightInnerColor", "shadowOuterColor", "shadowInnerColor"}); // registerConstructorWithBadEqual("javax.swing.plaf.BorderUIResource$SoftBevelBorderUIResource", new String[]{"bevelType", "highlightOuter", "highlightInner", "shadowOuter", "shadowInner"}); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/java/util/IdentityHashMap.java --- a/jdk/src/share/classes/java/util/IdentityHashMap.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/java/util/IdentityHashMap.java Fri May 30 00:00:00 2008 +0200 @@ -188,7 +188,6 @@ /** * Use NULL_KEY for key if it is null. */ - private static Object maskNull(Object key) { return (key == null ? NULL_KEY : key); } @@ -378,8 +377,8 @@ */ public boolean containsValue(Object value) { Object[] tab = table; - for (int i = 1; i < tab.length; i+= 2) - if (tab[i] == value) + for (int i = 1; i < tab.length; i += 2) + if (tab[i] == value && tab[i - 1] != null) return true; return false; @@ -904,7 +903,6 @@ * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ - private transient Set> entrySet = null; /** diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/classes/java/util/TreeMap.java --- a/jdk/src/share/classes/java/util/TreeMap.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/share/classes/java/util/TreeMap.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1021,7 +1021,7 @@ } Iterator descendingKeyIterator() { - return new DescendingKeyIterator(getFirstEntry()); + return new DescendingKeyIterator(getLastEntry()); } static final class KeySet extends AbstractSet implements NavigableSet { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/lib/audio/soundbank.gm Binary file jdk/src/share/lib/audio/soundbank.gm has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/lib/cmm/lcms/GRAY.pf Binary file jdk/src/share/lib/cmm/lcms/GRAY.pf has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/lib/cmm/lcms/LINEAR_RGB.pf Binary file jdk/src/share/lib/cmm/lcms/LINEAR_RGB.pf has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/share/lib/cmm/lcms/PYCC.pf Binary file jdk/src/share/lib/cmm/lcms/PYCC.pf has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c --- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c Fri May 30 00:00:00 2008 +0200 @@ -1627,6 +1627,8 @@ #define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI +typedef Status + (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp); typedef XRRScreenConfiguration* (*XRRGetScreenInfoType)(Display *dpy, Drawable root); typedef void @@ -1651,6 +1653,7 @@ short rate, Time timestamp); +static XRRQueryVersionType awt_XRRQueryVersion; static XRRGetScreenInfoType awt_XRRGetScreenInfo; static XRRFreeScreenConfigInfoType awt_XRRFreeScreenConfigInfo; static XRRConfigRatesType awt_XRRConfigRates; @@ -1673,6 +1676,8 @@ static jboolean X11GD_InitXrandrFuncs(JNIEnv *env) { + int rr_maj_ver = 0, rr_min_ver = 0; + void *pLibRandR = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_LOCAL); if (pLibRandR == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, @@ -1680,6 +1685,41 @@ return JNI_FALSE; } + LOAD_XRANDR_FUNC(XRRQueryVersion); + + if (!(*awt_XRRQueryVersion)(awt_display, &rr_maj_ver, &rr_min_ver)) { + J2dRlsTraceLn(J2D_TRACE_ERROR, + "X11GD_InitXrandrFuncs: XRRQueryVersion returned an error status"); + dlclose(pLibRandR); + return JNI_FALSE; + } + + if (usingXinerama) { + /* + * We can proceed as long as this is RANDR 1.2 or above. + * As of Xorg server 1.3 onwards the Xinerama backend may actually be + * a fake one provided by RANDR itself. See Java bug 6636469 for info. + */ + if (!(rr_maj_ver > 1 || (rr_maj_ver == 1 && rr_min_ver >= 2))) { + J2dRlsTraceLn2(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. " + "Xinerama is active and Xrandr version is %d.%d", + rr_maj_ver, rr_min_ver); + dlclose(pLibRandR); + return JNI_FALSE; + } + + /* + * REMIND: Fullscreen mode doesn't work quite right with multi-monitor + * setups and RANDR 1.2. So for now we also require a single screen. + */ + if (awt_numScreens > 1 ) { + J2dRlsTraceLn(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. " + "Multiple screens in use"); + dlclose(pLibRandR); + return JNI_FALSE; + } + } + LOAD_XRANDR_FUNC(XRRGetScreenInfo); LOAD_XRANDR_FUNC(XRRFreeScreenConfigInfo); LOAD_XRANDR_FUNC(XRRConfigRates); @@ -1815,15 +1855,6 @@ int opcode = 0, firstEvent = 0, firstError = 0; jboolean ret; - if (usingXinerama) { - /* - * REMIND: we'll just punt if Xinerama is enabled; we can remove this - * restriction in the future if we find Xinerama and XRandR playing - * well together... - */ - return JNI_FALSE; - } - AWT_LOCK(); ret = (jboolean)XQueryExtension(awt_display, "RANDR", &opcode, &firstEvent, &firstError); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java --- a/jdk/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,608 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - @test - @bug 6187066 - @summary Tests the Window.autoRequestFocus property for the Window.setVisible() method. - @author anton.tarasov: area=awt.focus - @library ../../regtesthelpers - @build Util - @run main AutoRequestFocusSetVisibleTest -*/ - -import java.awt.*; -import java.awt.event.*; -import java.applet.Applet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.lang.reflect.InvocationTargetException; -import test.java.awt.regtesthelpers.Util; - -public class AutoRequestFocusSetVisibleTest extends Applet { - static Frame focusedFrame; - static Button focusOwner; - static Frame frame; - static Button frameButton; - static Frame frame2; - static Button frameButton2; - static Window window; - static Button winButton; - static Window ownedWindow; - static Button ownWinButton; - static Dialog ownedDialog; - static Button ownDlgButton; - static Dialog dialog; - static Button dlgButton; - - static String toolkitClassName; - static Robot robot = Util.createRobot(); - - public static void main(String[] args) { - AutoRequestFocusSetVisibleTest app = new AutoRequestFocusSetVisibleTest(); - app.init(); - app.start(); - } - - public void init() { - // Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - Sysout.createDialogWithInstructions(new String[] - {"This is an automatic test. Simply wait until it is done." - }); - toolkitClassName = Toolkit.getDefaultToolkit().getClass().getName(); - } - - void recreateGUI() { - if (focusedFrame != null) { - focusedFrame.dispose(); - frame.dispose(); - frame2.dispose(); - window.dispose(); - ownedWindow.dispose(); - ownedDialog.dispose(); - dialog.dispose(); - } - - focusedFrame = new Frame("Base Frame"); - focusOwner = new Button("button"); - - frame = new Frame("Test Frame"); - frameButton = new Button("button"); - - frame2 = new Frame("Test Frame"); - frameButton2 = new Button("button"); - - window = new Window(focusedFrame); - winButton = new Button("button"); - - ownedWindow = new Window(frame) { - /* - * When 'frame' is shown along with the 'ownedWindow' - * (i.e. showWithParent==true) then it can appear - * that the 'ownedWindow' is shown too early and - * it can't be focused due to its owner can't be - * yet activated. So, to avoid this race, we pospone - * a little the showing of the 'ownedWindow'. - */ - public void show() { - robot.delay(100); - super.show(); - } - }; - ownWinButton = new Button("button"); - - ownedDialog = new Dialog(frame2); - ownDlgButton = new Button("button"); - - dialog = new Dialog(focusedFrame, "Test Dialog"); - dlgButton = new Button("button"); - - focusedFrame.add(focusOwner); - focusedFrame.setBounds(100, 100, 300, 300); - - frame.setBounds(140, 140, 220, 220); - frame.add(frameButton); - - frame2.setBounds(140, 140, 220, 220); - frame2.add(frameButton2); - - window.setBounds(140, 140, 220, 220); - window.add(winButton); - - ownedWindow.setBounds(180, 180, 140, 140); - ownedWindow.add(ownWinButton); - - ownedDialog.setBounds(180, 180, 140, 140); - ownedDialog.add(ownDlgButton); - - dialog.setBounds(140, 140, 220, 220); - dialog.add(dlgButton); - } - - public void start() { - - /////////////////////////////////////////////////////// - // 1. Show Frame with owned modal Dialog without delay. - // Check that the Dialog takes focus. - /////////////////////////////////////////////////////// - - recreateGUI(); - - Sysout.println("Stage 1 in progress..."); - - dialog.setModal(true); - dialog.setAutoRequestFocus(false); - setVisible(focusedFrame, true); - - TestHelper.invokeLaterAndWait(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }, robot); - - if (focusOwner.hasFocus()) { - throw new TestFailedException("the modal dialog must gain focus but it didn't!"); - } - setVisible(dialog, false); - - ////////////////////////////////////////////////// - // 2. Show Frame, activate, auto hide, auto show. - // Check that the Frame takes focus. - ////////////////////////////////////////////////// - - recreateGUI(); - - Sysout.println("Stage 2 in progress..."); - - setVisible(focusedFrame, false); - - focusedFrame.setAutoRequestFocus(false); - setVisible(focusedFrame, true); - - Util.clickOnTitle(focusedFrame, robot); - Util.waitForIdle(robot); - - if (!focusedFrame.isFocused()) { - throw new Error("Test error: the frame couldn't be focused."); - } - - focusedFrame.setExtendedState(Frame.ICONIFIED); - Util.waitForIdle(robot); - focusedFrame.setExtendedState(Frame.NORMAL); - Util.waitForIdle(robot); - - if (!focusedFrame.isFocused()) { - throw new TestFailedException("the restored frame must gain focus but it didn't!"); - } - - - //////////////////////// - // 3.1 Show Frame normal. - //////////////////////// - - recreateGUI(); - - test("Stage 3.1 in progress...", frame, frameButton); - - - // 3.2. Show Frame maximized both. - ///////////////////////////////// - - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) { - System.out.println("Stage 3.2: Frame.MAXIMIZED_BOTH not supported. Skipping."); - } else { - frame.setExtendedState(Frame.MAXIMIZED_BOTH); - - test("Stage 3.2 in progress...", frame, frameButton); - } - - - // 3.3. Show Frame maximized vertically. - /////////////////////////////////////// - - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_VERT)) { - System.out.println("Stage 3.3: Frame.MAXIMIZED_VERT not supported. Skipping."); - } else { - frame.setExtendedState(Frame.MAXIMIZED_VERT); - - test("Stage 3.3 in progress...", frame, frameButton); - } - - - // 3.4. Show Frame maximized horizontally. - ///////////////////////////////////////// - - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_HORIZ)) { - System.out.println("Stage 3.4: Frame.MAXIMIZED_HORIZ not supported. Skipping."); - } else { - frame.setExtendedState(Frame.MAXIMIZED_HORIZ); - - test("Stage 3.4 in progress...", frame, frameButton); - } - - - // 3.5. Show Frame iconified. - //////////////////////////// - - if (!Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.ICONIFIED)) { - System.out.println("Stage 3.5: Frame.ICONIFIED not supported. Skipping."); - } else { - frame.setExtendedState(Frame.ICONIFIED); - - test("Stage 3.5 in progress...", frame, frameButton); - } - - - /////////////////// - // 4.1 Show Window. - /////////////////// - recreateGUI(); - test("Stage 4.1 in progress...", window, winButton); - - - // 4.2 Show Dialog. - ////////////////// - - test("Stage 4.2 in progress...", dialog, dlgButton); - - - // 4.3. Show modal Dialog. - ///////////////////////// - - dialog.setModal(true); - test("Stage 4.3 in progress...", dialog, dlgButton, true); - - - /////////////////////////////////// - // 5.1 Show Frame with owned Window. - /////////////////////////////////// - - // On Windows, an owned Window will not be focused on its showing - // if the owner is not currently active. - if ("sun.awt.windows.WToolkit".equals(toolkitClassName)) { - Sysout.println("Stage 5.1 - Skiping."); - } else { - setVisible(ownedWindow, true); - setVisible(frame, false); // 'ownedWindow' will be shown along with the owner. - - test("Stage 5.1 in progress...", frame, ownedWindow, ownWinButton, true); - } - - - // 5.2 Show Frame with owned Dialog. - /////////////////////////////////// - - setVisible(ownedDialog, true); - setVisible(frame2, false); // 'ownedDialog' will be shown along with the owner. - - test("Stage 5.2 in progress...", frame2, ownedDialog, ownDlgButton, true); - - - /////////////////////////////////// - // 6. Show unblocking modal Dialog. - /////////////////////////////////// - - if ("sun.awt.motif.MToolkit".equals(toolkitClassName)) { - Sysout.println("Stage 6 - Skiping."); - } else { - Sysout.println("Stage 6 in progress..."); - - // --- - // Testing the bug of activating invisible modal Dialog (awt_Window::SetAndActivateModalBlocker). - // Having some window not excluded from modality, so that it would be blocked. - Frame f = new Frame("Aux. Frame"); - f.setSize(100, 100); - setVisible(f, true); - // --- - - setVisible(focusedFrame, true); - if (!focusOwner.hasFocus()) { - Util.clickOnComp(focusOwner, robot); - Util.waitForIdle(robot); - if (!focusOwner.hasFocus()) { - throw new Error("Test error: the frame couldn't be focused."); - } - } - - dialog.setModal(true); - dialog.setAutoRequestFocus(false); - focusedFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - - TestHelper.invokeLaterAndWait(new Runnable() { - public void run() { - dialog.setVisible(true); - } - }, robot); - - if (dialog.isFocused()) { - throw new TestFailedException("the unblocking dialog shouldn't gain focus but it did!"); - } - setVisible(dialog, false); - } - - Sysout.println("Test passed."); - } - - /* - * @param msg notifies test stage number - * @param showWindow a window to show/test (if ownedWindow == null) - * @param ownedWindow an owned window to show/test, or null if showWindow should be tested - * @param clickButton a button of the window (owner or owned) expected to be on the top of stack order - * @param shouldFocusChange true the test window should gain focus - */ - void test(String msg, final Window showWindow, Window ownedWindow, final Button clickButton, boolean shouldFocusChange) { - Window testWindow = (ownedWindow == null ? showWindow : ownedWindow); - - Sysout.println(msg); - - if (showWindow.isVisible()) { - showWindow.dispose(); - Util.waitForIdle(robot); - } - if (!focusedFrame.isVisible()) { - setVisible(focusedFrame, true); - } - if (!focusOwner.hasFocus()) { - Util.clickOnComp(focusOwner, robot); - Util.waitForIdle(robot); - if (!focusOwner.hasFocus()) { - throw new Error("Test error: the frame couldn't be focused."); - } - } - - ////////////////////////////////////////// - // Test focus change on showing the window - ////////////////////////////////////////// - - final Runnable showAction = new Runnable() { - public void run() { - showWindow.setAutoRequestFocus(false); - showWindow.setVisible(true); - } - }; - - final Runnable trackerAction = new Runnable() { - public void run() { - if (showWindow instanceof Dialog && ((Dialog)showWindow).isModal()) { - TestHelper.invokeLaterAndWait(showAction, robot); - } else { - showAction.run(); - } - } - }; - - if (shouldFocusChange) { - trackerAction.run(); - Util.waitForIdle(robot); - - if (!testWindow.isFocused()) { - throw new TestFailedException("the window must gain focus but it didn't!"); - } - - } else if (TestHelper.trackFocusChangeFor(trackerAction, robot)) { - throw new TestFailedException("the window shouldn't gain focus but it did!"); - } - - - //////////////////////////////////////////// - // Test that the window was shown on the top. - // Test that it can be focused. - //////////////////////////////////////////// - - if (!(testWindow instanceof Frame) || - ((Frame)testWindow).getExtendedState() != Frame.ICONIFIED) - { - boolean performed = Util.trackActionPerformed(clickButton, new Runnable() { - public void run() { - /* - * If 'showWindow' is not on the top then - * 'focusOwner' button completely overlaps 'clickButton' - * and we won't catch the action. - */ - Util.clickOnComp(clickButton, robot); - } - }, 1000, false); - - if (!performed) { - // In case of loosing ACTION_PERFORMED, try once more. - Sysout.println("(ACTION_EVENT was not generated. One more attemp.)"); - performed = Util.trackActionPerformed(clickButton, new Runnable() { - public void run() { - Util.clickOnComp(clickButton, robot); - } - }, 1000, false); - - if (!performed) { - throw new TestFailedException("the window shown is not on the top!"); - } - } - } - - recreateGUI(); - } - - void test(String msg, final Window showWindow, Button clickButton) { - test(msg, showWindow, null, clickButton, false); - } - void test(String msg, final Window showWindow, Button clickButton, boolean shouldFocusChange) { - test(msg, showWindow, null, clickButton, shouldFocusChange); - } - void test(String msg, final Window showWindow, Window ownedWindow, Button clickButton) { - test(msg, showWindow, ownedWindow, clickButton, false); - } - - private static void setVisible(Window w, boolean b) { - w.setVisible(b); - try { - Util.waitForIdle(robot); - } catch (RuntimeException rte) { // InfiniteLoop - rte.printStackTrace(); - } - robot.delay(200); - } -} - -class TestFailedException extends RuntimeException { - TestFailedException(String msg) { - super("Test failed: " + msg); - } -} - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); -// dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); -// dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - -// setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java --- a/jdk/test/java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,571 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - @test - @bug 6187066 - @summary Tests the Window.autoRequestFocus property for the Window.toFront() method. - @author anton.tarasov: area=awt.focus - @library ../../regtesthelpers - @build Util - @run main AutoRequestFocusToFrontTest -*/ - -import java.awt.*; -import java.awt.event.*; -import java.applet.Applet; -import java.util.concurrent.atomic.AtomicBoolean; -import java.lang.reflect.InvocationTargetException; -import test.java.awt.regtesthelpers.Util; - -public class AutoRequestFocusToFrontTest extends Applet { - static boolean haveDelays; - - static Frame auxFrame; - static Frame frame; - static Button frameButton; - static Frame frame2; - static Button frameButton2; - static Frame frame3; - static Button frameButton3; - static Window window; - static Button winButton; - static Dialog dialog; - static Button dlgButton; - static Window ownedWindow; - static Button ownWinButton; - static Dialog ownedDialog; - static Button ownDlgButton; - static Dialog modalDialog; - static Button modalDlgButton; - - static String toolkitClassName; - static Robot robot = Util.createRobot(); - - public static void main(String[] args) { - - if (args.length != 0) { - haveDelays = "delay".equals(args[0]) ? true : false; - } - - AutoRequestFocusToFrontTest app = new AutoRequestFocusToFrontTest(); - app.init(); - app.start(); - } - - public void init() { - // Create instructions for the user here, as well as set up - // the environment -- set the layout manager, add buttons, - // etc. - this.setLayout (new BorderLayout ()); - Sysout.createDialogWithInstructions(new String[] - {"This is an automatic test. Simply wait until it is done." - }); - toolkitClassName = Toolkit.getDefaultToolkit().getClass().getName(); - } - - static void recreateGUI() { - if (auxFrame != null) { - auxFrame.dispose(); - frame.dispose(); - frame2.dispose(); - frame3.dispose(); - window.dispose(); - dialog.dispose(); - ownedWindow.dispose(); - ownedDialog.dispose(); - modalDialog.dispose(); - } - - auxFrame = new Frame("Auxiliary Frame"); - - frame = new Frame("Test Frame"); - frameButton = new Button("button"); - - frame2 = new Frame("Test Frame 2"); - frameButton2 = new Button("button"); - - frame3 = new Frame("Test Frame 3"); - frameButton3 = new Button("button"); - - window = new Window(null); - winButton = new Button("button"); - dialog = new Dialog((Frame)null, "Test Dialog"); - dlgButton = new Button("button"); - - ownedWindow = new Window(frame); - ownWinButton = new Button("button"); - - ownedDialog = new Dialog(frame2, "Test Owned Dialog"); - ownDlgButton = new Button("button"); - - modalDialog = new Dialog(frame3, "Test Modal Dialog"); - modalDlgButton = new Button("button"); - - auxFrame.setBounds(100, 100, 300, 300); - - frame.setBounds(120, 120, 260, 260); - frame.add(frameButton); - - frame2.setBounds(120, 120, 260, 260); - frame2.add(frameButton2); - - frame3.setBounds(120, 120, 260, 260); - frame3.add(frameButton3); - - window.setBounds(120, 120, 260, 260); - window.add(winButton); - - dialog.setBounds(120, 120, 260, 260); - dialog.add(dlgButton); - - ownedWindow.setBounds(140, 140, 220, 220); - ownedWindow.add(ownWinButton); - - ownedDialog.setBounds(140, 140, 220, 220); - ownedDialog.add(ownDlgButton); - - modalDialog.setBounds(140, 140, 220, 220); - modalDialog.add(modalDlgButton); - modalDialog.setModal(true); - } - - public void start() { - // 1. Simple Frame. - ////////////////// - - recreateGUI(); - Test.setWindows(frame, null, null); - Test.test("Test stage 1 in progress", frameButton); - - - // 2. Ownerless Window. - ////////////////////// - - recreateGUI(); - Test.setWindows(window, null, null); - Test.test("Test stage 2 in progress", winButton); - - - // 3. Ownerless Dialog. - ////////////////////// - - recreateGUI(); - Test.setWindows(dialog, null, null); - Test.test("Test stage 3 in progress", dlgButton); - - - // 4.1. Owner Frame (with owned Window). - /////////////////////////////////////// - - recreateGUI(); - Test.setWindows(frame, null, new Window[] {ownedWindow, frame}); - Test.test("Test stage 4.1 in progress", ownWinButton); - - - // 4.2. Owned Window (with owner Frame). - /////////////////////////////////////// - - recreateGUI(); - Test.setWindows(ownedWindow, null, new Window[] {ownedWindow, frame}); - Test.test("Test stage 4.2 in progress", ownWinButton); - - - // 5.1. Owner Frame (with owned Dialog). - /////////////////////////////////////// - - recreateGUI(); - Test.setWindows(frame2, null, new Window[] {ownedDialog, frame2}); - Test.test("Test stage 5.1 in progress", ownDlgButton); - - - // 5.2. Owned Dialog (with owner Frame). - /////////////////////////////////////// - - recreateGUI(); - Test.setWindows(ownedDialog, null, new Window[] {ownedDialog, frame2}); - Test.test("Test stage 5.2 in progress", ownDlgButton); - - - //////////////////////////////////////////////// - // 6.1. Owned modal Dialog (with owner Frame). - // Focused frame is excluded from modality. - //////////////////////////////////////////////// - - if (!"sun.awt.motif.MToolkit".equals(toolkitClassName)) { - recreateGUI(); - auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - - Test.setWindows(modalDialog, modalDialog, new Window[] {modalDialog, frame3}); - Test.test("Test stage 6.1 in progress", modalDlgButton); - } - - - // 6.2. Owner Frame (with owned modal Dialog). - // Focused frame is excluded from modality. - //////////////////////////////////////////////// - - if (!"sun.awt.motif.MToolkit".equals(toolkitClassName)) { - recreateGUI(); - auxFrame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - - Test.setWindows(frame3, modalDialog, new Window[] {modalDialog, frame3}); - Test.test("Test stage 6.2 in progress", modalDlgButton, true); - } - - /////////////////////////////////////////////////// - // 7. Calling setVisible(true) for the shown Frame. - /////////////////////////////////////////////////// - - recreateGUI(); - Test.setWindows(frame, null, null); - Test.setTestSetVisible(); - Test.test("Test stage 7 in progress", frameButton); - - - Sysout.println("Test passed."); - } - - static class Test { - static Window testWindow; // a window to move to front with autoRequestFocus set - static Window focusWindow; // a window to gain focus - static Window[] showWindows; // windows to show, or null if only testWindow should be shown - - static boolean testSetVisible; - - static void setWindows(Window _testWindow, Window _focusWindow, Window[] _showWindows) { - testWindow = _testWindow; - focusWindow = _focusWindow; - showWindows = _showWindows; - } - static void setTestSetVisible() { - testSetVisible = true; - } - - /* - * @param msg notifies test stage number - * @param testButton a button of the window (owner or owned) that is to be on the top of stack order - * @param shouldFocusChange true for modal dialogs - */ - static void test(String msg, final Button testButton, boolean shouldFocusChange) { - Sysout.println(msg); - - showWindows(testWindow, showWindows, true); - - pause(100); - - ///////////////////////////////////////////////////////// - // Test that calling toFront() doesn't cause focus change - // when 'autoRequestFocus' is false. - ///////////////////////////////////////////////////////// - - Runnable action = new Runnable() { - public void run() { - testWindow.setAutoRequestFocus(false); - if (testSetVisible) { - setVisible(testWindow, true); - } else { - toFront(testWindow); - } - } - }; - - if (shouldFocusChange) { - action.run(); - Util.waitForIdle(robot); - if (!focusWindow.isFocused()) { - throw new TestFailedException("the window must gain focus on moving to front but it didn't!"); - } - } else if (TestHelper.trackFocusChangeFor(action, robot)) { - throw new TestFailedException("the window shouldn't gain focus on moving to front but it did!"); - } - - pause(100); - - /////////////////////////////////////////////////////// - // Test that the window (or its owned window) is on top. - /////////////////////////////////////////////////////// - - // The latest versions of Metacity (e.g. 2.16) have problems with moving a window to the front. - if (Util.getWMID() != Util.METACITY_WM) { - - boolean performed = Util.trackActionPerformed(testButton, new Runnable() { - public void run() { - Util.clickOnComp(testButton, robot); - } - }, 1000, false); - - if (!performed) { - // For the case when the robot failed to trigger ACTION_EVENT. - Sysout.println("(ACTION_EVENT was not generated. One more attemp.)"); - performed = Util.trackActionPerformed(testButton, new Runnable() { - public void run() { - Util.clickOnComp(testButton, robot); - } - }, 1000, false); - if (!performed) { - throw new TestFailedException("the window moved to front is not on the top!"); - } - } - } - - showWindows(testWindow, showWindows, false); - - - ///////////////////////////////////////////////// - // Test that calling toFront() focuses the window - // when 'autoRequestFocus' is true. - ///////////////////////////////////////////////// - - // Skip this stage for unfocusable window - if (!testWindow.isFocusableWindow()) { - return; - } - - showWindows(testWindow, showWindows, true); - - pause(100); - - boolean gained = Util.trackWindowGainedFocus(testWindow, new Runnable() { - public void run() { - testWindow.setAutoRequestFocus(true); - if (testSetVisible) { - setVisible(testWindow, true); - } else { - toFront(testWindow); - } - } - }, 1000, false); - - // Either the window or its owned window must be focused - if (!gained && !testButton.hasFocus()) { - throw new TestFailedException("the window should gain focus automatically but it didn't!"); - } - - showWindows(testWindow, showWindows, false); - } - - static void test(String msg, Button testButton) { - test(msg, testButton, false); - } - - private static void showWindows(Window win, Window[] wins, final boolean visible) { - pause(100); - - if (wins == null) { - wins = new Window[] {win}; // operate with 'win' - } - for (final Window w: wins) { - if (visible) { - if ((w instanceof Dialog) && ((Dialog)w).isModal()) { - TestHelper.invokeLaterAndWait(new Runnable() { - public void run() { - w.setVisible(true); - } - }, robot); - } else { - setVisible(w, true); - } - } else { - w.dispose(); - } - } - setVisible(auxFrame, visible); - - if (visible) { - if (!auxFrame.isFocused()) { - Util.clickOnTitle(auxFrame, robot); - Util.waitForIdle(robot); - if (!auxFrame.isFocused()) { - throw new Error("Test error: the frame couldn't be focused."); - } - } - } - } - } - - private static void setVisible(Window w, boolean b) { - w.setVisible(b); - try { - Util.waitForIdle(robot); - } catch (RuntimeException rte) { // InfiniteLoop - rte.printStackTrace(); - } - robot.delay(200); - } - - private static void toFront(Window w) { - w.toFront(); - Util.waitForIdle(robot); - robot.delay(200); - } - - private static void pause(int msec) { - if (haveDelays) { - robot.delay(msec); - } - } -} - -class TestFailedException extends RuntimeException { - TestFailedException(String msg) { - super("Test failed: " + msg); - } -} - -/**************************************************** - Standard Test Machinery - DO NOT modify anything below -- it's a standard - chunk of code whose purpose is to make user - interaction uniform, and thereby make it simpler - to read and understand someone else's test. - ****************************************************/ - -/** - This is part of the standard test machinery. - It creates a dialog (with the instructions), and is the interface - for sending text messages to the user. - To print the instructions, send an array of strings to Sysout.createDialog - WithInstructions method. Put one line of instructions per array entry. - To display a message for the tester to see, simply call Sysout.println - with the string to be displayed. - This mimics System.out.println but works within the test harness as well - as standalone. - */ - -class Sysout -{ - static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); -// dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); -// dialog.setVisible(true); - println( "Any messages for the tester will display here." ); - } - - - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); - } - - - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); - } - -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog -{ - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - -// setVisible(true); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); - System.out.println(messageIn); - } - -}// TestDialog class diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/awt/Focus/AutoRequestFocusTest/TestHelper.java --- a/jdk/test/java/awt/Focus/AutoRequestFocusTest/TestHelper.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - * Util class used for testing RFE 6187066. - * @author anton.tarasov - */ - -import java.awt.*; -import java.awt.event.*; -import test.java.awt.regtesthelpers.Util; -import java.util.concurrent.atomic.AtomicBoolean; -import java.lang.reflect.InvocationTargetException; - -public class TestHelper { - private static volatile boolean focusChanged; - private static volatile boolean trackFocusChange; - private static boolean focusChangeTrackerSet; - - /* - * @param action the action to perform - * @return if {@code action} caused focus change - */ - public static boolean trackFocusChangeFor(Runnable action, Robot robot) { - if (!focusChangeTrackerSet) { - setFocusChangeTracker(); - } - - focusChanged = false; - trackFocusChange = true; - - action.run(); - - Util.waitForIdle(robot); - - trackFocusChange = false; - - return focusChanged; - } - - public static void invokeLaterAndWait(Runnable action, Robot robot) { - EventQueue.invokeLater(action); - try { - EventQueue.invokeAndWait(new Runnable() { // waiting for action - public void run() {} - }); - } catch (InterruptedException ie) { - } catch (InvocationTargetException ite) {} - - Util.waitForIdle(robot); // waiting for events - } - - private static void setFocusChangeTracker() { - Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { - public void eventDispatched(AWTEvent e) { - int id = e.getID(); - if (trackFocusChange && - (id == FocusEvent.FOCUS_GAINED || id == FocusEvent.FOCUS_LOST || - id == WindowEvent.WINDOW_GAINED_FOCUS || id == WindowEvent.WINDOW_LOST_FOCUS || - id == WindowEvent.WINDOW_ACTIVATED || id == WindowEvent.WINDOW_DEACTIVATED)) - { - System.out.println(e.toString()); - focusChanged = true; - } - } - }, FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_FOCUS_EVENT_MASK | WindowEvent.WINDOW_EVENT_MASK); - - focusChangeTrackerSet = true; - } -} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/lang/reflect/Generics/Probe.java --- a/jdk/test/java/lang/reflect/Generics/Probe.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/java/lang/reflect/Generics/Probe.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 5003916 + * @bug 5003916 6704655 * @summary Testing parsing of signatures attributes of nested classes * @author Joseph D. Darcy * @compile -source 1.5 Probe.java @@ -32,8 +32,10 @@ import java.lang.reflect.*; import java.lang.annotation.*; +import java.util.*; +import static java.util.Arrays.*; -@Classes({ +@Classes(value={ "java.util.concurrent.FutureTask", "java.util.concurrent.ConcurrentHashMap$EntryIterator", "java.util.concurrent.ConcurrentHashMap$KeyIterator", @@ -56,7 +58,9 @@ "java.util.HashMap$ValueIterator", "java.util.LinkedHashMap$EntryIterator", "java.util.LinkedHashMap$KeyIterator", - "java.util.LinkedHashMap$ValueIterator", + "java.util.LinkedHashMap$ValueIterator" + }, + sunClasses={ "javax.crypto.SunJCE_c", "javax.crypto.SunJCE_e", "javax.crypto.SunJCE_f", @@ -66,7 +70,15 @@ }) public class Probe { public static void main (String[] args) throws Throwable { - String [] names = (Probe.class).getAnnotation(Classes.class).value(); + Classes classesAnnotation = (Probe.class).getAnnotation(Classes.class); + List names = + new ArrayList(asList(classesAnnotation.value())); + + if (System.getProperty("java.runtime.name").startsWith("Java(TM)")) { + // Sun production JDK; test crypto classes too + for(String name: classesAnnotation.sunClasses()) + names.add(name); + } int errs = 0; for(String name: names) { @@ -140,4 +152,5 @@ @Retention(RetentionPolicy.RUNTIME) @interface Classes { String [] value(); // list of classes to probe + String [] sunClasses(); // list of Sun-production JDK specific classes to probe } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/util/Collection/MOAT.java --- a/jdk/test/java/util/Collection/MOAT.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/java/util/Collection/MOAT.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 6207984 6272521 6192552 6269713 6197726 6260652 5073546 4137464 * 4155650 4216399 4294891 6282555 6318622 6355327 6383475 6420753 - * 6431845 4802633 6570566 6570575 6570924 + * 6431845 4802633 6570566 6570575 6570924 6691185 6691215 * @summary Run many tests on many Collection and Map implementations * @author Martin Buchholz */ @@ -155,7 +155,7 @@ check(c.containsAll(new ArrayList())); } - private static void testEmptyCollection(Collection c) { + private static void testEmptyCollection(Collection c) { check(c.isEmpty()); equal(c.size(), 0); equal(c.toString(),"[]"); @@ -165,6 +165,23 @@ Object[] a = new Object[1]; a[0] = Boolean.TRUE; equal(c.toArray(a), a); equal(a[0], null); + testEmptyIterator(c.iterator()); + } + + static void testEmptyIterator(final Iterator it) { + if (rnd.nextBoolean()) + check(! it.hasNext()); + + THROWS(NoSuchElementException.class, + new Fun(){void f(){ it.next(); }}); + + try { it.remove(); } + catch (IllegalStateException _) { pass(); } + catch (UnsupportedOperationException _) { pass(); } + catch (Throwable t) { unexpected(t); } + + if (rnd.nextBoolean()) + check(! it.hasNext()); } private static void testEmptyList(List c) { @@ -173,10 +190,12 @@ equal2(c, Collections.emptyList()); } - private static void testEmptySet(Set c) { + private static void testEmptySet(Set c) { testEmptyCollection(c); equal(c.hashCode(), 0); equal2(c, Collections.emptySet()); + if (c instanceof NavigableSet) + testEmptyIterator(((NavigableSet)c).descendingIterator()); } private static void testImmutableCollection(final Collection c) { @@ -221,13 +240,20 @@ testEmptyCollection(c); } - private static void testEmptyMap(final Map m) { + private static void testEmptyMap(final Map m) { check(m.isEmpty()); equal(m.size(), 0); equal(m.toString(),"{}"); testEmptySet(m.keySet()); testEmptySet(m.entrySet()); testEmptyCollection(m.values()); + + try { check(! m.containsValue(null)); } + catch (NullPointerException _) { /* OK */ } + try { check(! m.containsKey(null)); } + catch (NullPointerException _) { /* OK */ } + check(! m.containsValue(1)); + check(! m.containsKey(1)); } private static void testImmutableMap(final Map m) { @@ -433,8 +459,18 @@ if (! supportsAdd(c)) return; //System.out.println("add() supported"); - if (c instanceof NavigableSet) - testNavigableSet((NavigableSet)c); + if (c instanceof NavigableSet) { + System.out.println("NavigableSet tests..."); + + NavigableSet ns = (NavigableSet)c; + testNavigableSet(ns); + testNavigableSet(ns.headSet(6, false)); + testNavigableSet(ns.headSet(5, true)); + testNavigableSet(ns.tailSet(0, false)); + testNavigableSet(ns.tailSet(1, true)); + testNavigableSet(ns.subSet(0, false, 5, true)); + testNavigableSet(ns.subSet(1, true, 6, false)); + } if (c instanceof Queue) testQueue((Queue)c); @@ -514,8 +550,19 @@ if (m instanceof ConcurrentMap) testConcurrentMap((ConcurrentMap) m); - if (m instanceof NavigableMap) - testNavigableMap((NavigableMap) m); + if (m instanceof NavigableMap) { + System.out.println("NavigableMap tests..."); + + NavigableMap nm = + (NavigableMap) m; + testNavigableMap(nm); + testNavigableMap(nm.headMap(6, false)); + testNavigableMap(nm.headMap(5, true)); + testNavigableMap(nm.tailMap(0, false)); + testNavigableMap(nm.tailMap(1, true)); + testNavigableMap(nm.subMap(1, true, 6, false)); + testNavigableMap(nm.subMap(0, false, 5, true)); + } checkFunctionalInvariants(m); @@ -697,8 +744,6 @@ private static void testNavigableMap(NavigableMap m) { - System.out.println("NavigableMap tests..."); - clear(m); checkNavigableMapKeys(m, 1, null, null, null, null); @@ -717,9 +762,11 @@ checkNavigableMapKeys(m, 5, 3, 5, 5, null); checkNavigableMapKeys(m, 6, 5, 5, null, null); - { - final Iterator it - = m.descendingKeySet().iterator(); + for (final Iterator it : + (Iterator[]) + new Iterator[] { + m.descendingKeySet().iterator(), + m.navigableKeySet().descendingIterator()}) { equalNext(it, 5); equalNext(it, 3); equalNext(it, 1); @@ -742,8 +789,6 @@ private static void testNavigableSet(NavigableSet s) { - System.out.println("NavigableSet tests..."); - clear(s); checkNavigableSetKeys(s, 1, null, null, null, null); @@ -762,8 +807,11 @@ checkNavigableSetKeys(s, 5, 3, 5, 5, null); checkNavigableSetKeys(s, 6, 5, 5, null, null); - { - final Iterator it = s.descendingIterator(); + for (final Iterator it : + (Iterator[]) + new Iterator[] { + s.descendingIterator(), + s.descendingSet().iterator()}) { equalNext(it, 5); equalNext(it, 3); equalNext(it, 1); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/util/NavigableMap/LockStep.java --- a/jdk/test/java/util/NavigableMap/LockStep.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/java/util/NavigableMap/LockStep.java Fri May 30 00:00:00 2008 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6420753 6242436 + * @bug 6420753 6242436 6691185 * @summary Compare NavigableMap implementations for identical behavior * @author Martin Buchholz */ @@ -159,6 +159,7 @@ Object[] a = new Object[1]; a[0] = Boolean.TRUE; equal(c.toArray(a), a); equal(a[0], null); + check(! c.iterator().hasNext()); } static void testEmptySet(Set c) { @@ -262,6 +263,16 @@ } } + static void equalIterators(final Iterator it1, + final Iterator it2) { + while (it1.hasNext()) { + if (maybe(2)) + check(it2.hasNext()); + equal(it1.next(), it2.next()); + } + check(! it2.hasNext()); + } + static void equalNavigableSetsLeaf(final NavigableSet s1, final NavigableSet s2) { equal2(s1, s2); @@ -273,6 +284,8 @@ equal(s1.first(), s2.first()); equal(s1.last(), s2.last()); } + equalIterators(s1.iterator(), s2.iterator()); + equalIterators(s1.descendingIterator(), s2.descendingIterator()); checkNavigableSet(s1); checkNavigableSet(s2); } @@ -493,30 +506,23 @@ static MapFrobber randomAdder(NavigableMap m) { final Integer k = unusedKey(m); - MapFrobber f; - switch (rnd.nextInt(4)) { - case 0: f = new MapFrobber() {void frob(NavigableMap m) { - equal(m.put(k, k+1), null); - equal(m.get(k), k+1); - if (maybe(4)) { - equal(m.put(k, k+1), k+1); - equal(m.get(k), k+1);}}}; - break; - case 1: f = new MapFrobber() {void frob(NavigableMap m) { - m.descendingMap().put(k, k+1); - equal(m.get(k), k+1);}}; - break; - case 2: f = new MapFrobber() {void frob(NavigableMap m) { - m.tailMap(k,true).headMap(k,true).put(k,k+1);}}; - break; - case 3: f = new MapFrobber() {void frob(NavigableMap m) { - m.tailMap(k,true).headMap(k,true).descendingMap().put(k,k+1);}}; - break; - default: throw new Error(); - } - final MapFrobber ff = f; + final MapFrobber[] randomAdders = { + new MapFrobber() {void frob(NavigableMap m) { + equal(m.put(k, k+1), null); + equal(m.get(k), k+1); + if (maybe(4)) { + equal(m.put(k, k+1), k+1); + equal(m.get(k), k+1);}}}, + new MapFrobber() {void frob(NavigableMap m) { + m.descendingMap().put(k, k+1); + equal(m.get(k), k+1);}}, + new MapFrobber() {void frob(NavigableMap m) { + m.tailMap(k,true).headMap(k,true).put(k,k+1);}}, + new MapFrobber() {void frob(NavigableMap m) { + m.tailMap(k,true).headMap(k,true).descendingMap().put(k,k+1);}} + }; return new MapFrobber() {void frob(NavigableMap m) { - ff.frob(m); + randomAdders[rnd.nextInt(randomAdders.length)].frob(m); if (maybe(2)) equal(m.get(k), k+1); if (maybe(4)) { equal(m.put(k, k+1), k+1); @@ -525,26 +531,19 @@ static SetFrobber randomAdder(NavigableSet s) { final Integer e = unusedElt(s); - SetFrobber f; - switch (rnd.nextInt(4)) { - case 0: f = new SetFrobber() {void frob(NavigableSet s) { - check(s.add(e));}}; - break; - case 1: f = new SetFrobber() {void frob(NavigableSet s) { - s.descendingSet().add(e);}}; - break; - case 2: f = new SetFrobber() {void frob(NavigableSet s) { - s.tailSet(e,true).headSet(e,true).add(e);}}; - break; - case 3: f = new SetFrobber() {void frob(NavigableSet s) { - s.descendingSet().tailSet(e,true).headSet(e,true).add(e);}}; - break; - default: throw new Error(); - } - final SetFrobber ff = f; + final SetFrobber[] randomAdders = { + new SetFrobber() {void frob(NavigableSet s) { + check(s.add(e));}}, + new SetFrobber() {void frob(NavigableSet s) { + s.descendingSet().add(e);}}, + new SetFrobber() {void frob(NavigableSet s) { + s.tailSet(e,true).headSet(e,true).add(e);}}, + new SetFrobber() {void frob(NavigableSet s) { + s.descendingSet().tailSet(e,true).headSet(e,true).add(e);}} + }; return new SetFrobber() {void frob(NavigableSet s) { if (maybe(2)) check(! s.contains(e)); - ff.frob(s); + randomAdders[rnd.nextInt(randomAdders.length)].frob(s); if (maybe(2)) check(! s.add(e)); if (maybe(2)) check(s.contains(e));}}; } @@ -605,89 +604,112 @@ static MapFrobber randomRemover(NavigableMap m) { final Integer k = usedKey(m); - switch (rnd.nextInt(7)) { - default: throw new Error(); - case 0: return new MapFrobber() {void frob(NavigableMap m) { - Map.Entry e = m.firstEntry(); - equal(m.pollFirstEntry(), e); - checkUnusedKey(m, e.getKey());}}; - case 1: return new MapFrobber() {void frob(NavigableMap m) { - Map.Entry e = m.lastEntry(); - equal(m.pollLastEntry(), e); - checkUnusedKey(m, e.getKey());}}; - case 2: return new MapFrobber() {void frob(NavigableMap m) { - check(m.remove(k) != null); - checkUnusedKey(m, k);}}; - case 3: return new MapFrobber() {void frob(NavigableMap m) { - m.subMap(k, true, k, true).clear(); - checkUnusedKey(m, k);}}; - case 4: return new MapFrobber() {void frob(NavigableMap m) { - m.descendingMap().subMap(k, true, k, true).clear(); - checkUnusedKey(m, k);}}; - case 5: return new MapFrobber() {void frob(NavigableMap m) { - final Iterator it = m.keySet().iterator(); - while (it.hasNext()) - if (it.next().equals(k)) { - it.remove(); - if (maybe(2)) - THROWS(IllegalStateException.class, - new Fun(){void f(){ it.remove(); }}); - } - checkUnusedKey(m, k);}}; - case 6: return new MapFrobber() {void frob(NavigableMap m) { - final Iterator it = m.entrySet().iterator(); - while (it.hasNext()) - if (it.next().getKey().equals(k)) { - it.remove(); - if (maybe(2)) - THROWS(IllegalStateException.class, remover(it)); - } - checkUnusedKey(m, k);}}; - } + final MapFrobber[] randomRemovers = { + new MapFrobber() {void frob(NavigableMap m) { + Map.Entry e = m.firstEntry(); + equal(m.pollFirstEntry(), e); + checkUnusedKey(m, e.getKey());}}, + new MapFrobber() {void frob(NavigableMap m) { + Map.Entry e = m.lastEntry(); + equal(m.pollLastEntry(), e); + checkUnusedKey(m, e.getKey());}}, + new MapFrobber() {void frob(NavigableMap m) { + check(m.remove(k) != null); + checkUnusedKey(m, k);}}, + new MapFrobber() {void frob(NavigableMap m) { + m.subMap(k, true, k, true).clear(); + checkUnusedKey(m, k);}}, + new MapFrobber() {void frob(NavigableMap m) { + m.descendingMap().subMap(k, true, k, true).clear(); + checkUnusedKey(m, k);}}, + new MapFrobber() {void frob(NavigableMap m) { + final Iterator it = m.keySet().iterator(); + while (it.hasNext()) + if (it.next().equals(k)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, + new Fun(){void f(){ it.remove(); }}); + } + checkUnusedKey(m, k);}}, + new MapFrobber() {void frob(NavigableMap m) { + final Iterator it = m.navigableKeySet().descendingIterator(); + while (it.hasNext()) + if (it.next().equals(k)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, + new Fun(){void f(){ it.remove(); }}); + } + checkUnusedKey(m, k);}}, + new MapFrobber() {void frob(NavigableMap m) { + final Iterator it = m.entrySet().iterator(); + while (it.hasNext()) + if (it.next().getKey().equals(k)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, remover(it)); + } + checkUnusedKey(m, k);}}, + }; + + return randomRemovers[rnd.nextInt(randomRemovers.length)]; } static SetFrobber randomRemover(NavigableSet s) { final Integer e = usedElt(s); - switch (rnd.nextInt(7)) { - default: throw new Error(); - case 0: return new SetFrobber() {void frob(NavigableSet s) { - Object e = s.first(); - equal(s.pollFirst(), e); - checkUnusedElt(s, e);}}; - case 1: return new SetFrobber() {void frob(NavigableSet s) { - Object e = s.last(); - equal(s.pollLast(), e); - checkUnusedElt(s, e);}}; - case 2: return new SetFrobber() {void frob(NavigableSet s) { - check(s.remove(e)); - checkUnusedElt(s, e);}}; - case 3: return new SetFrobber() {void frob(NavigableSet s) { - s.subSet(e, true, e, true).clear(); - checkUnusedElt(s, e);}}; - case 4: return new SetFrobber() {void frob(NavigableSet s) { - s.descendingSet().subSet(e, true, e, true).clear(); - checkUnusedElt(s, e);}}; - case 5: return new SetFrobber() {void frob(NavigableSet s) { - final Iterator it = s.iterator(); - while (it.hasNext()) - if (it.next().equals(e)) { - it.remove(); - if (maybe(2)) - THROWS(IllegalStateException.class, - new Fun(){void f(){ it.remove(); }}); - } - checkUnusedElt(s, e);}}; - case 6: return new SetFrobber() {void frob(NavigableSet s) { - final Iterator it = s.descendingSet().iterator(); - while (it.hasNext()) - if (it.next().equals(e)) { - it.remove(); - if (maybe(2)) - THROWS(IllegalStateException.class, - new Fun(){void f(){ it.remove(); }}); - } - checkUnusedElt(s, e);}}; - } + + final SetFrobber[] randomRemovers = { + new SetFrobber() {void frob(NavigableSet s) { + Object e = s.first(); + equal(s.pollFirst(), e); + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + Object e = s.last(); + equal(s.pollLast(), e); + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + check(s.remove(e)); + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + s.subSet(e, true, e, true).clear(); + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + s.descendingSet().subSet(e, true, e, true).clear(); + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + final Iterator it = s.iterator(); + while (it.hasNext()) + if (it.next().equals(e)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, + new Fun(){void f(){ it.remove(); }}); + } + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + final Iterator it = s.descendingSet().iterator(); + while (it.hasNext()) + if (it.next().equals(e)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, + new Fun(){void f(){ it.remove(); }}); + } + checkUnusedElt(s, e);}}, + new SetFrobber() {void frob(NavigableSet s) { + final Iterator it = s.descendingIterator(); + while (it.hasNext()) + if (it.next().equals(e)) { + it.remove(); + if (maybe(2)) + THROWS(IllegalStateException.class, + new Fun(){void f(){ it.remove(); }}); + } + checkUnusedElt(s, e);}} + }; + + return randomRemovers[rnd.nextInt(randomRemovers.length)]; } static void lockStep(NavigableMap m1, diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java --- a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java Fri May 30 00:00:00 2008 +0200 @@ -21,7 +21,6 @@ * have any questions. */ /* - * */ import java.text.*; @@ -48,7 +47,7 @@ for (Locale target: availloc) { // pure JRE implementation - OpenListResourceBundle rb = (OpenListResourceBundle)LocaleData.getCurrencyNames(target); + ResourceBundle rb = LocaleData.getCurrencyNames(target); boolean jreHasBundle = rb.getLocale().equals(target); for (Locale test: testloc) { @@ -65,38 +64,23 @@ // the localized symbol for the target locale String currencyresult = c.getSymbol(target); - // the localized name for the target locale - String nameresult = c.getDisplayName(target); - // provider's name (if any) String providerscurrency = null; - String providersname = null; if (providerloc.contains(target)) { providerscurrency = cnp.getSymbol(c.getCurrencyCode(), target); - providersname = cnp.getDisplayName(c.getCurrencyCode(), target); } // JRE's name (if any) String jrescurrency = null; - String jresname = null; - String key = c.getCurrencyCode(); - String nameKey = key.toLowerCase(Locale.ROOT); if (jreHasBundle) { try { - jrescurrency = rb.getString(key); + jrescurrency = rb.getString(c.getCurrencyCode()); } catch (MissingResourceException mre) { // JRE does not have any resource, "jrescurrency" should remain null } - try { - jresname = rb.getString(nameKey); - } catch (MissingResourceException mre) { - // JRE does not have any resource, "jresname" should remain null - } } checkValidity(target, jrescurrency, providerscurrency, currencyresult, jrescurrency!=null); - checkValidity(target, jresname, providersname, nameresult, - jreHasBundle && rb.handleGetKeys().contains(nameKey)); } } } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/management/Introspector/LegacyIntrospectorTest.java --- a/jdk/test/javax/management/Introspector/LegacyIntrospectorTest.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - * @test - * @bug 6316460 - * @summary Test that the legacy com.sun.management.jmx.Introspector - * methods work. - * @author Eamonn McManus - * @run clean LegacyIntrospectorTest - * @run build LegacyIntrospectorTest - * @run main LegacyIntrospectorTest - */ - -import javax.management.*; -import com.sun.management.jmx.*; - -public class LegacyIntrospectorTest { - public static interface TestMBean { - public int getWhatever(); - } - public static class Test implements TestMBean { - public int getWhatever() {return 0;} - } - - @SuppressWarnings("deprecation") - public static void main(String[] args) throws Exception { - MBeanInfo mbi = Introspector.testCompliance(Test.class); - MBeanAttributeInfo mbai = mbi.getAttributes()[0]; - if (!mbai.getName().equals("Whatever")) - throw new Exception("Wrong attribute name: " + mbai.getName()); - Class c = Introspector.getMBeanInterface(Test.class); - if (c != TestMBean.class) - throw new Exception("Wrong interface: " + c); - - MBeanServer mbs1 = new MBeanServerImpl(); - if (!mbs1.getDefaultDomain().equals("DefaultDomain")) - throw new Exception("Wrong default domain: " + mbs1.getDefaultDomain()); - - MBeanServer mbs2 = new MBeanServerImpl("Foo"); - if (!mbs2.getDefaultDomain().equals("Foo")) - throw new Exception("Wrong default domain: " + mbs2.getDefaultDomain()); - - ObjectName delegateName = - new ObjectName("JMImplementation:type=MBeanServerDelegate"); - MBeanInfo delegateInfo = mbs2.getMBeanInfo(delegateName); - MBeanInfo refDelegateInfo = - MBeanServerFactory.newMBeanServer().getMBeanInfo(delegateName); - if (!delegateInfo.equals(refDelegateInfo)) - throw new Exception("Wrong delegate info from MBeanServerImpl: " + - delegateInfo); - - System.out.println("TEST PASSED"); - } -} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/E4XErrorTest.java --- a/jdk/test/javax/script/E4XErrorTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/E4XErrorTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346734 + * @bug 6346734 6705893 * @summary We do *not* support E4X (ECMAScript for XML) in our * implementation. We want to throw error on XML literals * as early as possible rather than at "runtime" - i.e., when @@ -37,9 +37,10 @@ public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } // The test below depends on the error message content diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Helper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/script/Helper.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +import javax.script.*; + +/** + * Helper class to consolidate testing requirements for a js engine. + * A js engine is required as part of Sun's product JDK. + */ +public class Helper { + private Helper() {}; // Don't instantiate + + public static ScriptEngine getJsEngine(ScriptEngineManager m) { + ScriptEngine e = m.getEngineByName("js"); + if (e == null && + System.getProperty("java.runtime.name").startsWith("Java(TM)")) { + // A js engine is requied for Sun's product JDK + throw new RuntimeException("no js engine found"); + } + return e; + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/JavaScriptScopeTest.java --- a/jdk/test/javax/script/JavaScriptScopeTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/JavaScriptScopeTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346733 + * @bug 6346733 6705893 * @summary Verify that independent Bindings instances don't * get affected by default scope assignments. Also, verify * that script globals can be created and accessed from Java @@ -36,9 +36,10 @@ public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval("var v = 'hello';"); // Create a new scope diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/NullUndefinedVarTest.java --- a/jdk/test/javax/script/NullUndefinedVarTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/NullUndefinedVarTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346732 + * @bug 6346732 6705893 * @summary should be able to assign null and undefined * value to JavaScript global variables. */ @@ -34,9 +34,10 @@ public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval("var n = null; " + "if (n !== null) throw 'expecting null';" + diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/PluggableContextTest.java --- a/jdk/test/javax/script/PluggableContextTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/PluggableContextTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6398614 + * @bug 6398614 6705893 * @summary Create a user defined ScriptContext and check * that script can access variables from non-standard scopes */ @@ -35,7 +35,11 @@ ScriptEngineManager m = new ScriptEngineManager(); ScriptContext ctx = new MyContext(); ctx.setAttribute("x", "hello", MyContext.APP_SCOPE); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } // the following reference to 'x' throws exception // if APP_SCOPE is not searched. e.eval("x", ctx); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/ProviderTest.java --- a/jdk/test/javax/script/ProviderTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/ProviderTest.java Fri May 30 00:00:00 2008 +0200 @@ -35,9 +35,10 @@ if (se == null) { throw new RuntimeException("can't locate dummy engine"); } - se = manager.getEngineByName("js"); + se = Helper.getJsEngine(manager); if (se == null) { - throw new RuntimeException("can't locate JavaScript engine"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } } } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/RhinoExceptionTest.java --- a/jdk/test/javax/script/RhinoExceptionTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/RhinoExceptionTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,8 +23,8 @@ /* * @test - * @bug 6474943 - * @summary Test that Rhion exception messages are + * @bug 6474943 6705893 + * @summary Test that Rhino exception messages are * available from ScriptException. */ @@ -36,7 +36,11 @@ public static void main(String[] args) throws Exception { ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } engine.put("msg", ERROR_MSG); try { engine.eval("throw new Error(msg);"); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test1.java --- a/jdk/test/javax/script/Test1.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test1.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Create JavaScript engine and execute a simple script. * Tests script engine discovery mechanism. */ @@ -35,9 +35,10 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest1\n"); ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } jsengine.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test1.js"))); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test2.java --- a/jdk/test/javax/script/Test2.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test2.java Fri May 30 00:00:00 2008 +0200 @@ -50,7 +50,11 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest2\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine eng = m.getEngineByName("js"); + ScriptEngine eng = Helper.getJsEngine(m); + if (eng == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } eng.put("Testobj", new Testobj("Hello World")); eng.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test2.js"))); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test3.java --- a/jdk/test/javax/script/Test3.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test3.java Fri May 30 00:00:00 2008 +0200 @@ -4,6 +4,7 @@ * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT @@ -23,7 +24,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test engine and global scopes */ @@ -37,7 +38,11 @@ final Reader reader = new FileReader( new File(System.getProperty("test.src", "."), "Test3.js")); ScriptEngineManager m = new ScriptEngineManager(); - final ScriptEngine engine = m.getEngineByName("js"); + final ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Bindings en = new SimpleBindings(); engine.setBindings(en, ScriptContext.ENGINE_SCOPE); en.put("key", "engine value"); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test4.java --- a/jdk/test/javax/script/Test4.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test4.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test script functions implementing Java interface */ @@ -34,7 +34,11 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest4\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } e.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test4.js"))); Invocable inv = (Invocable)e; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test5.java --- a/jdk/test/javax/script/Test5.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test5.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Tests engine, global scopes and scope hiding. */ @@ -34,7 +34,11 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest5\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Bindings g = new SimpleBindings(); Bindings e = new SimpleBindings(); g.put("key", "value in global"); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test6.java --- a/jdk/test/javax/script/Test6.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test6.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test basic script compilation. Value eval'ed from * compiled and interpreted scripts should be same. */ @@ -35,7 +35,11 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest6\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine engine = m.getEngineByName("js"); + ScriptEngine engine = Helper.getJsEngine(m); + if (engine == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } Reader reader = new FileReader( new File(System.getProperty("test.src", "."), "Test6.js")); engine.eval(reader); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test7.java --- a/jdk/test/javax/script/Test7.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test7.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Tests importPackage and java access in script */ @@ -37,7 +37,11 @@ new File(System.getProperty("test.src", "."), "Test7.js"); Reader r = new FileReader(file); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine eng = m.getEngineByName("js"); + ScriptEngine eng = Helper.getJsEngine(m); + if (eng == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } eng.put("filename", file.getAbsolutePath()); eng.eval(r); String str = (String)eng.get("firstLine"); diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/Test8.java --- a/jdk/test/javax/script/Test8.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/Test8.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6249843 + * @bug 6249843 6705893 * @summary Test invoking script function or method from Java */ @@ -34,7 +34,11 @@ public static void main(String[] args) throws Exception { System.out.println("\nTest8\n"); ScriptEngineManager m = new ScriptEngineManager(); - ScriptEngine e = m.getEngineByName("js"); + ScriptEngine e = Helper.getJsEngine(m); + if (e == null) { + System.out.println("Warning: No js engine found; test vacuously passes."); + return; + } e.eval(new FileReader( new File(System.getProperty("test.src", "."), "Test8.js"))); Invocable inv = (Invocable)e; diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/script/VersionTest.java --- a/jdk/test/javax/script/VersionTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/javax/script/VersionTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /* * @test - * @bug 6346729 + * @bug 6346729 6705893 * @summary Create JavaScript engine and check language and engine version */ @@ -37,9 +37,10 @@ public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); - ScriptEngine jsengine = manager.getEngineByName("js"); + ScriptEngine jsengine = Helper.getJsEngine(manager); if (jsengine == null) { - throw new RuntimeException("no js engine found"); + System.out.println("Warning: No js engine found; test vacuously passes."); + return; } String langVersion = jsengine.getFactory().getLanguageVersion(); if (! langVersion.equals(JS_LANG_VERSION)) { diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/GetFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/GetFormat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatConverter getFormat method */ + +import javax.sound.sampled.*; +import com.sun.media.sound.*; + +public class GetFormat { + + public static void main(String[] args) throws Exception { + AudioFormat frm = new AudioFormat(8000, 16, 1, true, false); + AudioFloatConverter conv = AudioFloatConverter.getConverter(frm); + if(!conv.getFormat().matches(frm)) + throw new RuntimeException("Incorrect audio format returned."); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/ToFloatArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatConverter/ToFloatArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,143 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatConverter toFloatArray method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ToFloatArray { + + public static void main(String[] args) throws Exception { + + float[] testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + + // Check conversion from float2byte and byte2float. + for (int big = 0; big < 2; big+=1) + for (int signed = 0; signed < 2; signed+=1) + for (int bits = 8; bits <= 32; bits+=8) { + AudioFormat frm = new AudioFormat(44100, bits, 1, signed==1, big==1); + byte[] buff = new byte[testarray.length * frm.getFrameSize()]; + float[] testarray2 = new float[testarray.length]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(frm); + conv.toByteArray(testarray, buff); + conv.toFloatArray(buff, testarray2); + for (int i = 0; i < testarray2.length; i++) { + if(Math.abs(testarray[i] - testarray2[i]) > 0.05) + throw new RuntimeException("Conversion failed for " + frm +" , arrays not equal enough!\n"); + } + } + + // Check big/little + for (int big = 0; big < 2; big+=1) + for (int signed = 0; signed < 2; signed+=1) + for (int bits = 8; bits <= 32; bits+=8) { + AudioFormat frm = new AudioFormat(44100, bits, 1, signed==1, big==1); + byte[] buff = new byte[testarray.length * frm.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(frm); + conv.toByteArray(testarray, buff); + byte[] buff2 = new byte[testarray.length * frm.getFrameSize()]; + int fs = frm.getFrameSize(); + for (int i = 0; i < buff2.length; i+=fs) { + for (int j = 0; j < fs; j++) { + buff2[i+(fs-j-1)] = buff[i+j]; + } + } + float[] testarray2 = new float[testarray.length]; + AudioFormat frm2 = new AudioFormat(44100, bits, 1, signed==1, big==0); + AudioFloatConverter.getConverter(frm2).toFloatArray(buff2, testarray2); + for (int i = 0; i < testarray2.length; i++) { + if(Math.abs(testarray[i] - testarray2[i]) > 0.05) + { + throw new RuntimeException("Conversion failed for " + frm +" to " + frm2 + " , arrays not equal enough!\n"); + } + } + } + + // Check signed/unsigned + for (int big = 0; big < 2; big+=1) + for (int signed = 0; signed < 2; signed+=1) + for (int bits = 8; bits <= 32; bits+=8) { + AudioFormat frm = new AudioFormat(44100, bits, 1, signed==1, big==1); + byte[] b = new byte[testarray.length * frm.getFrameSize()]; + AudioFloatConverter conv = AudioFloatConverter.getConverter(frm); + conv.toByteArray(testarray, b); + int fs = frm.getFrameSize(); + if(big==1) + { + for(int i=0; i < b.length; i+= fs ) + b[i] = (b[i] >= 0) ? (byte)(0x80 | b[i]) : (byte)(0x7F & b[i]); + } + else + { + for(int i=(0+fs-1); i < b.length; i+= fs ) + b[i] = (b[i] >= 0) ? (byte)(0x80 | b[i]) : (byte)(0x7F & b[i]); + } + float[] testarray2 = new float[testarray.length]; + AudioFormat frm2 = new AudioFormat(44100, bits, 1, signed==0, big==1); + AudioFloatConverter.getConverter(frm2).toFloatArray(b, testarray2); + for (int i = 0; i < testarray2.length; i++) { + if(Math.abs(testarray[i] - testarray2[i]) > 0.05) + { + throw new RuntimeException("Conversion failed for " + frm +" to " + frm2 + " , arrays not equal enough!\n"); + } + } + } + + // Check if conversion 32->24, 24->16, 16->8 result in same float data + AudioFormat frm = new AudioFormat(44100, 32, 1, true, true); + byte[] b = new byte[testarray.length * frm.getFrameSize()]; + AudioFloatConverter.getConverter(frm).toByteArray(testarray, b); + for (int bits = 8; bits <= 32; bits+=8) { + AudioFormat frm2 = new AudioFormat(44100, bits, 1, true, true); + byte[] b2 = new byte[testarray.length * frm2.getFrameSize()]; + int fs1 = frm.getFrameSize(); + int fs2 = frm2.getFrameSize(); + int ii = 0; + for (int i = 0; i < b.length; i+=fs1) + for (int j = 0; j < fs2; j++) + b2[ii++] = b[i+j]; + float[] testarray2 = new float[testarray.length]; + AudioFloatConverter.getConverter(frm2).toFloatArray(b2, testarray2); + for (int i = 0; i < testarray2.length; i++) { + if(Math.abs(testarray[i] - testarray2[i]) > 0.05) + { + throw new RuntimeException("Conversion failed for " + frm +" to " + frm2 + " , arrays not equal enough!\n"); + } + } + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Available.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Available.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream available method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Available { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float[] buff = new float[512]; + if(stream.available() != 1024) + throw new RuntimeException("stream.available return incorrect value."); + stream.read(buff); + if(stream.available() != 512) + throw new RuntimeException("stream.available return incorrect value."); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Close.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Close.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream close method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Close { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + getStream1().close(); + getStream2().close(); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/GetFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/GetFormat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream getFormat method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetFormat { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + if(!getStream1().getFormat().matches(format)) + throw new RuntimeException("Incorrect audio format returned."); + if(!getStream2().getFormat().matches(format)) + throw new RuntimeException("Incorrect audio format returned."); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/GetFrameLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/GetFrameLength.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream getFrameLength method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetFrameLength { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + if(getStream1().getFrameLength() != 1024L) + throw new RuntimeException("Incorrect frame length returned."); + if(getStream2().getFrameLength() != 1024L) + throw new RuntimeException("Incorrect frame length returned."); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/MarkSupported.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/MarkSupported.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream markSupported method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class MarkSupported { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + if(!getStream1().markSupported()) + throw new RuntimeException("Mark not supported."); + if(!getStream2().markSupported()) + throw new RuntimeException("Mark not supported."); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Read.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Read.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream read method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Read { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float v = 0; + stream.skip(512); + v = stream.read(); + if(!(Math.abs(v - test_float_array[512]) < 0.0001)) + { + throw new RuntimeException("Read returned unexpected value."); + } + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/ReadFloatArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/ReadFloatArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream read(float[]) method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadFloatArray { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float[] buff = new float[1024]; + stream.read(buff); + for (int j = 0; j < buff.length; j++) + if(!(Math.abs(buff[j] - test_float_array[j]) < 0.0001)) + throw new RuntimeException("Incorrect data in buffer."); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/ReadFloatArrayIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/ReadFloatArrayIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream read(float[], int, int) method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadFloatArrayIntInt { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float[] buff = new float[1024]; + stream.read(buff,0,512); + stream.read(buff,512,512); + for (int j = 0; j < buff.length; j++) + if(!(Math.abs(buff[j] - test_float_array[j]) < 0.0001)) + throw new RuntimeException("Incorrect data in buffer."); + + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Reset.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Reset.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream reset method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Reset { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float[] buff = new float[512]; + float[] buff2 = new float[512]; + stream.read(buff); + stream.mark(512); + stream.read(buff); + stream.reset(); + stream.read(buff2); + for (int j = 0; j < buff2.length; j++) + if(!(Math.abs(buff[j] - buff2[j]) < 0.0001)) + throw new RuntimeException("Incorrect data in buffer."); + + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Skip.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/AudioFloatInputStream/Skip.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test AudioFloatInputStream skip method */ + +import java.io.*; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Skip { + + static float[] test_float_array; + static byte[] test_byte_array; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static AudioFloatInputStream getStream1() + { + return AudioFloatInputStream.getInputStream(format, test_byte_array, 0, test_byte_array.length); + } + + static AudioFloatInputStream getStream2() + { + AudioInputStream strm = new AudioInputStream(new ByteArrayInputStream(test_byte_array), format, 1024); + return AudioFloatInputStream.getInputStream(strm); + } + + static void setUp() throws Exception { + test_float_array = new float[1024]; + test_byte_array = new byte[1024*format.getFrameSize()]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + test_float_array[i] = (float)Math.sin(10*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + test_float_array[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + test_float_array[i] *= 0.3; + } + AudioFloatConverter.getConverter(format).toByteArray(test_float_array, test_byte_array); + } + + public static void main(String[] args) throws Exception { + setUp(); + + for (int i = 0; i < 2; i++) { + AudioFloatInputStream stream = null; + if(i == 0) stream = getStream1(); + if(i == 1) stream = getStream2(); + float[] buff = new float[512]; + stream.skip(512); + stream.read(buff); + for (int j = 0; j < buff.length; j++) + if(!(Math.abs(buff[j] - test_float_array[j+512]) < 0.0001)) + throw new RuntimeException("Incorrect data in buffer."); + + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/GetInputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/GetInputStream.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer getInputStream method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetInputStream { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + for (int i = 0; i < 2; i++) { + ModelByteBuffer buff; + if(i == 0) + buff = new ModelByteBuffer(test_file); + else + buff = new ModelByteBuffer(test_byte_array); + + byte[] b = new byte[test_byte_array.length]; + buff.getInputStream().read(b); + for (int j = 0; j < b.length; j++) + if(b[i] != test_byte_array[i]) + throw new RuntimeException("Byte array compare fails!"); + } + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/GetRoot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/GetRoot.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer getRoot method */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetRoot { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file); + ModelByteBuffer buff2 = buff.subbuffer(10, 10); + ModelByteBuffer buff3 = buff2.subbuffer(2, 2); + if(buff != buff3.getRoot()) + throw new RuntimeException("ModelByteBuffer doesn't return correct root!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/Load.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/Load.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer load method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file); + + buff.load(); + if(buff.array() == null) + throw new RuntimeException("buf is null!"); + if(buff.array().length != test_byte_array.length) + throw new RuntimeException("buff.array().length length is incorrect!"); + byte[] b = buff.array(); + for (int i = 0; i < b.length; i++) + if(test_byte_array[i] != b[i]) + throw new RuntimeException("buff.array() incorrect!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/LoadAll.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/LoadAll.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,93 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer loadAll method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class LoadAll { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file); + List col = new ArrayList(); + col.add(buff); + ModelByteBuffer.loadAll(col); + if(buff.array() == null) + throw new RuntimeException("buf is null!"); + if(buff.array().length != test_byte_array.length) + throw new RuntimeException("buff.array().length length is incorrect!"); + byte[] b = buff.array(); + for (int i = 0; i < b.length; i++) + if(test_byte_array[i] != b[i]) + throw new RuntimeException("buff.array() incorrect!"); + + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferByteArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferByteArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer(byte[]) constructor */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferByteArray { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_byte_array); + if(buff.array() != test_byte_array) + throw new RuntimeException("buff.bytearray incorrect!"); + if(buff.capacity() != test_byte_array.length) + throw new RuntimeException("buff.capacity() incorrect!"); + if(buff.arrayOffset() != 0) + throw new RuntimeException("buff.arrayOffset not 0!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferByteArrayIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferByteArrayIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer(byte[],int,int) constructor */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferByteArrayIntInt { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_byte_array,10,20); + if(buff.array() != test_byte_array) + throw new RuntimeException("buff.array() incorrect!"); + if(buff.capacity() != 20) + throw new RuntimeException("buff.capacity() not 20!"); + if(buff.arrayOffset() != 10) + throw new RuntimeException("buff.arrayOffset() not 10!"); + if(buff.getFile() != null) + throw new RuntimeException("buff.getFile() not null!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferFile.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer(File) constructor */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferFile { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file); + if(buff.array() != null) + throw new RuntimeException("buff.array() not null!"); + if(buff.capacity() != test_file.length()) + throw new RuntimeException("buff.capacity() incorrect!"); + if(buff.arrayOffset() != 0) + throw new RuntimeException("buff.arrayOffset() not 0!"); + if(buff.getFile() != test_file) + throw new RuntimeException("buff.getFile() incorrect!"); + if(buff.getFilePointer() != 0) + throw new RuntimeException("buff.getFilePointer() not 0!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferFileLongLong.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/NewModelByteBufferFileLongLong.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,88 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer(File,long,long) constructor */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferFileLongLong { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file,10,20); + if(buff.array() != null) + throw new RuntimeException("buff.array() not null!"); + if(buff.capacity() != 20) + throw new RuntimeException("buff.capacity() not 20!"); + if(buff.arrayOffset() != 0) + throw new RuntimeException("buff.arrayOffset() not 0!"); + if(buff.getFile() != test_file) + throw new RuntimeException("buff.getFile incorrect!"); + if(buff.getFilePointer() != 10) + throw new RuntimeException("buff.getFilePointer not 10!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLong.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLong.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer subbuffer(long) method */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SubbufferLong { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + for (int i = 0; i < 2; i++) { + ModelByteBuffer buff; + if(i == 0) + buff = new ModelByteBuffer(test_file); + else + buff = new ModelByteBuffer(test_byte_array); + + ModelByteBuffer buff2 = buff.subbuffer(10); + if(buff2.getFilePointer() != buff.getFilePointer()) + throw new RuntimeException("buff2.getFilePointer() incorreect!"); + if(buff2.arrayOffset() != 10) + throw new RuntimeException("buff2.arrayOffset() not 10!"); + if(buff2.capacity() != buff.capacity()-10) + throw new RuntimeException("buff2.capacity() not correct!"); + } + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLongLong.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLongLong.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer subbuffer(long,long) method */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SubbufferLongLong { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + for (int i = 0; i < 2; i++) { + ModelByteBuffer buff; + if(i == 0) + buff = new ModelByteBuffer(test_file); + else + buff = new ModelByteBuffer(test_byte_array); + + ModelByteBuffer buff2 = buff.subbuffer(10,21); + if(buff2.getFilePointer() != buff.getFilePointer()) + throw new RuntimeException("buff2.getFilePointer() incorrect!"); + if(buff2.arrayOffset() != 10) + throw new RuntimeException("buff2.arrayOffset() not 10!"); + if(buff2.capacity() != 11) + throw new RuntimeException("buff2.capacity() not 11!"); + } + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLongLongBoolean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/SubbufferLongLongBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer subbuffer(long,long,boolean) method */ + +import java.io.File; +import java.io.FileOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SubbufferLongLongBoolean { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + for (int i = 0; i < 2; i++) { + ModelByteBuffer buff; + if(i == 0) + buff = new ModelByteBuffer(test_file); + else + buff = new ModelByteBuffer(test_byte_array); + + ModelByteBuffer buff2 = buff.subbuffer(10,21,true); + if(buff2.getRoot() != buff2); + if(buff2.capacity() != 11); + if(i == 0) + { + if(buff2.getFilePointer() != buff.getFilePointer()+10) + throw new RuntimeException("buff2.getFilePointer() incorrect!"); + } + else + { + if(buff2.arrayOffset() != 10) + throw new RuntimeException("buff2.arrayOffset() not 10!"); + } + } + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/Unload.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/Unload.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer unload method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Unload { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + ModelByteBuffer buff = new ModelByteBuffer(test_file); + buff.load(); + buff.unload(); + if(buff.array() != null) + throw new RuntimeException("buff.array() not null!"); + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/WriteTo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBuffer/WriteTo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBuffer writeTo method */ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class WriteTo { + + static float[] testarray; + static byte[] test_byte_array; + static File test_file; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + test_file = File.createTempFile("test", ".raw"); + FileOutputStream fos = new FileOutputStream(test_file); + fos.write(test_byte_array); + } + + static void tearDown() throws Exception { + if(!test_file.delete()) + test_file.deleteOnExit(); + } + + public static void main(String[] args) throws Exception { + try + { + setUp(); + + for (int i = 0; i < 2; i++) { + ModelByteBuffer buff; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if(i == 0) + buff = new ModelByteBuffer(test_file); + else + buff = new ModelByteBuffer(test_byte_array); + buff.writeTo(baos); + byte[] b = baos.toByteArray(); + for (int j = 0; j < b.length; j++) + if(b[i] != test_byte_array[i]) + throw new RuntimeException("baos.toByteArray() incorrect!"); + } + } + finally + { + tearDown(); + } + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetAttenuation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetAttenuation.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable getAttenuation method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetAttenuation { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + wavetable.setAttenuation(10f); + if(wavetable.getAttenuation() != 10f) + throw new RuntimeException("wavetable.getAttenuation() not 10!"); + wavetable.setAttenuation(20f); + if(wavetable.getAttenuation() != 20f) + throw new RuntimeException("wavetable.getAttenuation() not 20!"); + + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetChannels.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetChannels.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable getChannels method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetChannels { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + AudioFormat format1 = new AudioFormat(44100, 16, 1, true, false); + AudioFormat format2 = new AudioFormat(44100, 16, 2, true, false); + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format1,10f); + if(wavetable.getChannels() != 1) + throw new RuntimeException("wavetable.getChannels() not 1!"); + wavetable = new ModelByteBufferWavetable(buffer,format2,10f); + if(wavetable.getChannels() != 2) + throw new RuntimeException("wavetable.getChannels() not 2!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetLoopLength.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetLoopLength.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable getLoopLength method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetLoopLength { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + wavetable.setLoopLength(10f); + if(wavetable.getLoopLength() != 10f) + throw new RuntimeException("wavetable.getLoopLength() not 10!"); + wavetable.setLoopLength(20f); + if(wavetable.getLoopLength() != 20f) + throw new RuntimeException("wavetable.getLoopLength() not 20!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetLoopStart.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetLoopStart.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable getLoopStart method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetLoopStart { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + wavetable.setLoopStart(10f); + if(wavetable.getLoopStart() != 10f) + throw new RuntimeException("wavetable.getLoopStart() not 10!"); + wavetable.setLoopStart(20f); + if(wavetable.getLoopStart() != 20f) + throw new RuntimeException("wavetable.getLoopStart() not 20!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetPitchCorrection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/GetPitchCorrection.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable getPitchCorrect method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetPitchCorrection { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + wavetable.setPitchcorrection(10f); + if(wavetable.getPitchcorrection() != 10f) + throw new RuntimeException("wavetable.getPitchcorrection() not 10!"); + wavetable.setPitchcorrection(20f); + if(wavetable.getPitchcorrection() != 20f) + throw new RuntimeException("wavetable.getPitchcorrection() not 20!"); + + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable(ModelByteBuffer) method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferWavetableModelByteBuffer { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer_wave); + if(wavetable.getBuffer() != buffer_wave) + throw new RuntimeException("wavetable.getBuffer() incorrect!"); + if(!wavetable.getFormat().matches(format)) + throw new RuntimeException("wavetable.getFormat() incorrect!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferAudioFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferAudioFormat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable(ModelByteBuffer, AudioFormat) method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferWavetableModelByteBufferAudioFormat { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + if(wavetable.getBuffer() != buffer) + throw new RuntimeException("wavetable.getBuffer() incorrect!"); + if(wavetable.getFormat() != format) + throw new RuntimeException("wavetable.getFormat() incorrect!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferAudioFormatFloat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferAudioFormatFloat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable(ModelByteBuffer, AudioFormat) method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferWavetableModelByteBufferAudioFormatFloat { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + if(wavetable.getBuffer() != buffer) + throw new RuntimeException("wavetable.getBuffer() incorrect!"); + if(!wavetable.getFormat().matches(format)) + throw new RuntimeException("wavetable.getFormat() incorrect!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferFloat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/NewModelByteBufferWavetableModelByteBufferFloat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable(ModelByteBuffer, AudioFormat, float) method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelByteBufferWavetableModelByteBufferFloat { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format,10f); + if(wavetable.getBuffer() != buffer) + throw new RuntimeException("wavetable.getBuffer() incorrect!"); + if(!wavetable.getFormat().matches(format)) + throw new RuntimeException("wavetable.getFormat() incorrect!"); + if(wavetable.getPitchcorrection() != 10f) + throw new RuntimeException("wavetable.getPitchcorrection() not 10!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/Open.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/Open.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,92 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable open method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Open { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + if(wavetable.open(44100) != null) + throw new RuntimeException("wavetable.open(44100) doesn't return null!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/Set8BitExtensionBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/Set8BitExtensionBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,119 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable set8BitExtensionBuffer method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Set8BitExtensionBuffer { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + static float compare(float[] a, float[] b) + { + float ac_error = 0; + int counter = 0; + for (int i = 0; i < a.length; i++) { + ac_error += Math.abs(a[i] - b[i]); + counter++; + } + return ac_error / ((float)counter); + + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer16_8,format,10f); + float[] f1 = new float[testarray.length]; + float[] f2 = new float[testarray.length]; + wavetable.openStream().read(f1); + wavetable.set8BitExtensionBuffer(buffer8); + if(wavetable.get8BitExtensionBuffer() != buffer8) + throw new RuntimeException("wavetable.get8BitExtensionBuffer() incorrect!"); + wavetable.openStream().read(f2); + // f2 should have more accurity than f1, + // about 256 times more, or 8 bits + float spec1 = compare(f1, testarray); + float spec2 = compare(f2, testarray); + if((spec1/spec2) <= 200) + throw new RuntimeException("(spec1/spec2) <= 200!"); + + + } + + + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/SetLoopType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelByteBufferWavetable/SetLoopType.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable SetLoopType method */ + +import java.io.ByteArrayOutputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetLoopType { + + static float[] testarray; + static byte[] test_byte_array; + static byte[] test_byte_array_8ext; + static AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + static AudioFormat format24 = new AudioFormat(44100, 24, 1, true, false); + static ModelByteBuffer buffer; + static ModelByteBuffer buffer_wave; + static ModelByteBuffer buffer8; + static ModelByteBuffer buffer16_8; + static ModelByteBuffer buffer24; + + static void setUp() throws Exception { + testarray = new float[1024]; + for (int i = 0; i < 1024; i++) { + double ii = i / 1024.0; + ii = ii * ii; + testarray[i] = (float)Math.sin(10*ii*2*Math.PI); + testarray[i] += (float)Math.sin(1.731 + 2*ii*2*Math.PI); + testarray[i] += (float)Math.sin(0.231 + 6.3*ii*2*Math.PI); + testarray[i] *= 0.3; + } + test_byte_array = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format).toByteArray(testarray, test_byte_array); + buffer = new ModelByteBuffer(test_byte_array); + + byte[] test_byte_array2 = new byte[testarray.length*3]; + buffer24 = new ModelByteBuffer(test_byte_array2); + test_byte_array_8ext = new byte[testarray.length]; + byte[] test_byte_array_8_16 = new byte[testarray.length*2]; + AudioFloatConverter.getConverter(format24).toByteArray(testarray, test_byte_array2); + int ix = 0; + int x = 0; + for (int i = 0; i < test_byte_array_8ext.length; i++) { + test_byte_array_8ext[i] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + test_byte_array_8_16[x++] = test_byte_array2[ix++]; + } + buffer16_8 = new ModelByteBuffer(test_byte_array_8_16); + buffer8 = new ModelByteBuffer(test_byte_array_8ext); + + AudioInputStream ais = new AudioInputStream(buffer.getInputStream(), format, testarray.length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + AudioSystem.write(ais, AudioFileFormat.Type.WAVE, baos); + buffer_wave = new ModelByteBuffer(baos.toByteArray()); + } + + public static void main(String[] args) throws Exception { + + setUp(); + + ModelByteBufferWavetable wavetable = new ModelByteBufferWavetable(buffer,format); + wavetable.setLoopType(1); + if(wavetable.getLoopType() != 1) + throw new RuntimeException("wavetable.getLoopType() not 1!"); + wavetable.setLoopType(2); + if(wavetable.getLoopType() != 2) + throw new RuntimeException("wavetable.getLoopType() not 2!"); + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelDestination/NewModelDestination.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelDestination/NewModelDestination.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelDestination constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelDestination { + + public static void main(String[] args) throws Exception { + ModelDestination dest = new ModelDestination(); + if(dest.getIdentifier() != ModelDestination.DESTINATION_NONE) + throw new RuntimeException("dest.getIdentifier() is not equals ModelDestination.DESTINATION_NONE!"); + if(!(dest.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("dest.getTransform() is not instancoef ModelStandardTransform!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelDestination/NewModelDestinationModelIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelDestination/NewModelDestinationModelIdentifier.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelDestination(ModelIdentifier) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelDestinationModelIdentifier { + + public static void main(String[] args) throws Exception { + ModelDestination dest = new ModelDestination(ModelDestination.DESTINATION_EG1_ATTACK); + if(dest.getIdentifier() != ModelDestination.DESTINATION_EG1_ATTACK) + throw new RuntimeException("dest.getIdentifier() is not equals ModelDestination.DESTINATION_EG1_ATTACK!"); + if(!(dest.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("dest.getTransform() is not instancoef ModelStandardTransform!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelDestination/SetIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelDestination/SetIdentifier.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable setIdentifier(ModelIdentifier) method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetIdentifier { + + public static void main(String[] args) throws Exception { + ModelDestination dest = new ModelDestination(); + dest.setIdentifier(ModelDestination.DESTINATION_EG1_ATTACK); + if(dest.getIdentifier() != ModelDestination.DESTINATION_EG1_ATTACK) + throw new RuntimeException("dest.getIdentifier() is not equals ModelDestination.DESTINATION_EG1_ATTACK!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelDestination/SetTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelDestination/SetTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelByteBufferWavetable setTransform(ModelTransform) method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetTransform{ + + public static void main(String[] args) throws Exception { + ModelDestination dest = new ModelDestination(); + ModelStandardTransform newtransform = new ModelStandardTransform(); + dest.setTransform(newtransform); + if(dest.getTransform() != newtransform) + throw new RuntimeException("dest.getTransform() is incorrect!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/EqualsObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/EqualsObject.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier equals method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class EqualsObject { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a",1); + ModelIdentifier id2 = new ModelIdentifier("test","a",1); + ModelIdentifier id3 = new ModelIdentifier("test","a",2); + ModelIdentifier id4 = new ModelIdentifier("test","b",1); + ModelIdentifier id5 = new ModelIdentifier("hello","a",1); + if(!id.equals(id2)) + throw new RuntimeException("Compare failed!"); + if(id.equals(id3)) + throw new RuntimeException("Compare failed!"); + if(id.equals(id4)) + throw new RuntimeException("Compare failed!"); + if(id.equals(id5)) + throw new RuntimeException("Compare failed!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierString.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier(String) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelIdentifierString { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test"); + if(!id.getObject().equals("test")) + throw new RuntimeException("id.getObject() doesn't return \"test\"!"); + if(id.getVariable() != null) + throw new RuntimeException("id.getVariable() doesn't return null!"); + if(id.getInstance() != 0) + throw new RuntimeException("id.getInstance() doesn't return 0!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier(String, integer) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelIdentifierStringInt { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test",1); + if(!id.getObject().equals("test")) + throw new RuntimeException("id.getObject() doesn't return \"test\"!"); + if(id.getVariable() != null) + throw new RuntimeException("id.getVariable() doesn't return null!"); + if(id.getInstance() != 1) + throw new RuntimeException("id.getInstance() doesn't return 1!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringString.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier(String,String) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelIdentifierStringString { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a"); + if(!id.getObject().equals("test")) + throw new RuntimeException("id.getObject() doesn't return \"test\"!"); + if(!id.getVariable().equals("a")) + throw new RuntimeException("id.getVariable() doesn't return \"a\"!"); + if(id.getInstance() != 0) + throw new RuntimeException("id.getInstance() doesn't return 0!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/NewModelIdentifierStringStringInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier(String,String,int) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelIdentifierStringStringInt { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a",1);; + if(!id.getObject().equals("test")) + throw new RuntimeException("id.getObject() doesn't return \"test\"!"); + if(!id.getVariable().equals("a")) + throw new RuntimeException("id.getVariable() doesn't return \"a\"!"); + if(id.getInstance() != 1) + throw new RuntimeException("id.getInstance() doesn't return 1!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetInstance.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier setInstance method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetInstance { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a",1); + id.setInstance(2); + if(id.getInstance() != 2) + throw new RuntimeException("id.getInstance() doesn't return 2!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetObject.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier setObject method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetObject { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a",1); + id.setObject("hello"); + if(!id.getObject().equals("hello")) + throw new RuntimeException("id.getObject() does't return \"hello\"!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetVariable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelIdentifier/SetVariable.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelIdentifier setVariable method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetVariable { + + public static void main(String[] args) throws Exception { + ModelIdentifier id = new ModelIdentifier("test","a",1); + id.setVariable("b"); + if(!id.getVariable().equals("b")) + throw new RuntimeException("id.getVariable() does't return \"b\"!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/GetOscillators.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/GetOscillators.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer getOscillators method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetOscillators { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + if(performer.getOscillators() == null) + throw new RuntimeException("performer.getOscillators() returned null!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetConnectionBlocks.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetConnectionBlocks.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setConnectionBlocks method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetConnectionBlocks { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + List newlist = new ArrayList(); + performer.setConnectionBlocks(newlist); + if(performer.getConnectionBlocks() != newlist) + throw new RuntimeException("performer.getConnectionBlocks() returned incorrect data!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetDefaultConnectionsEnabled.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetDefaultConnectionsEnabled.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setDefaultConnectionsEnabled method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetDefaultConnectionsEnabled { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setDefaultConnectionsEnabled(true); + if(performer.isDefaultConnectionsEnabled() != true) + throw new RuntimeException("performer.isAddDefaultConnectionsEnabled() didn't return true!"); + performer.setDefaultConnectionsEnabled(false); + if(performer.isDefaultConnectionsEnabled() != false) + throw new RuntimeException("performer.isAddDefaultConnectionsEnabled() didn't return false!"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetExclusiveClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetExclusiveClass.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setExclusiveClass method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetExclusiveClass { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setExclusiveClass(10); + if(performer.getExclusiveClass() != 10) + throw new RuntimeException("performer.getExclusiveClass() didn't return 10!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetKeyFrom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetKeyFrom.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setKeyFrom method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetKeyFrom { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setKeyFrom(10); + if(performer.getKeyFrom() != 10) + throw new RuntimeException("performer.getKeyFrom() didn't return 10!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetKeyTo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetKeyTo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setKeyTo method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetKeyTo { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setKeyTo(10); + if(performer.getKeyTo() != 10) + throw new RuntimeException("performer.getKeyTo() didn't return 10!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetName.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setName method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetName { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setName("hello"); + if(!performer.getName().equals("hello")) + throw new RuntimeException("performer.getName() didn't return \"hello\"!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetSelfNonExclusive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetSelfNonExclusive.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setSelfNonExclusive method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetSelfNonExclusive { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setSelfNonExclusive(true); + if(performer.isSelfNonExclusive() != true) + throw new RuntimeException("performer.isSelfNonExclusive() didn't return true!"); + performer.setSelfNonExclusive(false); + if(performer.isSelfNonExclusive() != false) + throw new RuntimeException("performer.isSelfNonExclusive() didn't return false!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetVelFrom.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetVelFrom.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setVelFrom method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetVelFrom { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setVelFrom(10); + if(performer.getVelFrom() != 10) + throw new RuntimeException("performer.getVelFrom() didn't return 10!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetVelTo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelPerformer/SetVelTo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelPerformer setVelTo method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetVelTo { + + public static void main(String[] args) throws Exception { + ModelPerformer performer = new ModelPerformer(); + performer.setVelTo(10); + if(performer.getVelTo() != 10) + throw new RuntimeException("performer.getVelTo() didn't return 10!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSource.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource() constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSource { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(); + if(src.getIdentifier() != ModelSource.SOURCE_NONE) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NONE!"); + if(!(src.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("src.getTransform() doesn't return object which is instance of ModelStandardTransform!"); + + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifier.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource(ModelIdentifier) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSourceModelIdentifier { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(ModelSource.SOURCE_NOTEON_KEYNUMBER); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + if(!(src.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("src.getTransform() doesn't return object which is instance of ModelStandardTransform!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBoolean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,49 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource(ModelIdentifier,boolean) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSourceModelIdentifierBoolean { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(ModelSource.SOURCE_NOTEON_KEYNUMBER,ModelStandardTransform.DIRECTION_MAX2MIN); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + if(!(src.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("src.getTransform() doesn't return object which is instance of ModelStandardTransform!"); + ModelStandardTransform trans = (ModelStandardTransform)src.getTransform(); + if(trans.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("trans.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBooleanBoolean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBooleanBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource(ModelIdentifier,boolean,boolean) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSourceModelIdentifierBooleanBoolean { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(ModelSource.SOURCE_NOTEON_KEYNUMBER,ModelStandardTransform.DIRECTION_MAX2MIN,ModelStandardTransform.POLARITY_BIPOLAR); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + if(!(src.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("src.getTransform() doesn't return object which is instance of ModelStandardTransform!"); + ModelStandardTransform trans = (ModelStandardTransform)src.getTransform(); + if(trans.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("trans.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + if(trans.getPolarity() != ModelStandardTransform.POLARITY_BIPOLAR) + throw new RuntimeException("trans.getPolarity() doesn't return ModelStandardTransform.POLARITY_BIPOLAR!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBooleanBooleanInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierBooleanBooleanInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource(ModelIdentifier,boolean,boolean,int) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSourceModelIdentifierBooleanBooleanInt { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(ModelSource.SOURCE_NOTEON_KEYNUMBER, + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_CONCAVE); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + if(!(src.getTransform() instanceof ModelStandardTransform)) + throw new RuntimeException("src.getTransform() doesn't return object which is instance of ModelStandardTransform!"); + ModelStandardTransform trans = (ModelStandardTransform)src.getTransform(); + if(trans.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("trans.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + if(trans.getPolarity() != ModelStandardTransform.POLARITY_BIPOLAR) + throw new RuntimeException("trans.getPolarity() doesn't return ModelStandardTransform.POLARITY_BIPOLAR!"); + if(trans.getTransform() != ModelStandardTransform.TRANSFORM_CONCAVE) + throw new RuntimeException("trans.getTransform() doesn't return ModelStandardTransform.TRANSFORM_CONCAVE!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierModelTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/NewModelSourceModelIdentifierModelTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource(ModelIdentifier,ModelTransform) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelSourceModelIdentifierModelTransform { + + public static void main(String[] args) throws Exception { + ModelStandardTransform trans = new ModelStandardTransform(); + ModelSource src = new ModelSource(ModelSource.SOURCE_NOTEON_KEYNUMBER, trans); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + if(src.getTransform() != trans) + throw new RuntimeException("src.getTransform() doesn't return trans!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/SetIdentifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/SetIdentifier.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource setIdentifier method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetIdentifier { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(); + src.setIdentifier(ModelSource.SOURCE_NOTEON_KEYNUMBER); + if(src.getIdentifier() != ModelSource.SOURCE_NOTEON_KEYNUMBER) + throw new RuntimeException("src.getIdentifier() doesn't return ModelSource.SOURCE_NOTEON_KEYNUMBER!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelSource/SetTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelSource/SetTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelSource setTransform method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetTransform { + + public static void main(String[] args) throws Exception { + ModelSource src = new ModelSource(); + ModelStandardTransform trans = new ModelStandardTransform(); + src.setTransform(trans); + if(src.getTransform() != trans) + throw new RuntimeException("src.getTransform() doesn't return trans!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelStandardTransform { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + if(transform.getDirection() != ModelStandardTransform.DIRECTION_MIN2MAX) + throw new RuntimeException("transform.getDirection() doesn't return ModelStandardTransform.DIRECTION_MIN2MAX!"); + if(transform.getPolarity() != ModelStandardTransform.POLARITY_UNIPOLAR) + throw new RuntimeException("transform.getPolarity() doesn't return ModelStandardTransform.POLARITY_UNIPOLAR!"); + if(transform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR) + throw new RuntimeException("transform.getTransform() doesn't return ModelStandardTransform.TRANSFORM_LINEAR!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBoolean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform(boolean) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelStandardTransformBoolean { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(ModelStandardTransform.DIRECTION_MAX2MIN); + if(transform.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("transform.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + if(transform.getPolarity() != ModelStandardTransform.POLARITY_UNIPOLAR) + throw new RuntimeException("transform.getPolarity() doesn't return ModelStandardTransform.POLARITY_UNIPOLAR!"); + if(transform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR) + throw new RuntimeException("transform.getTransform() doesn't return ModelStandardTransform.TRANSFORM_LINEAR!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBooleanBoolean.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBooleanBoolean.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform(boolean,boolean) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelStandardTransformBooleanBoolean { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform( + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_BIPOLAR); + if(transform.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("transform.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + if(transform.getPolarity() != ModelStandardTransform.POLARITY_BIPOLAR) + throw new RuntimeException("transform.getPolarity() doesn't return ModelStandardTransform.POLARITY_BIPOLAR!"); + if(transform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR) + throw new RuntimeException("transform.getTransform() doesn't return ModelStandardTransform.TRANSFORM_LINEAR!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBooleanBooleanInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/NewModelStandardTransformBooleanBooleanInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform(boolean,boolean,int) constructor */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewModelStandardTransformBooleanBooleanInt { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform( + ModelStandardTransform.DIRECTION_MAX2MIN, + ModelStandardTransform.POLARITY_BIPOLAR, + ModelStandardTransform.TRANSFORM_CONVEX); + if(transform.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("transform.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + if(transform.getPolarity() != ModelStandardTransform.POLARITY_BIPOLAR) + throw new RuntimeException("transform.getPolarity() doesn't return ModelStandardTransform.POLARITY_BIPOLAR!"); + if(transform.getTransform() != ModelStandardTransform.TRANSFORM_CONVEX) + throw new RuntimeException("transform.getTransform() doesn't return ModelStandardTransform.TRANSFORM_CONVEX!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetDirection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetDirection.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform setDirection method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetDirection { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + if(transform.getDirection() != ModelStandardTransform.DIRECTION_MAX2MIN) + throw new RuntimeException("transform.getDirection() doesn't return ModelStandardTransform.DIRECTION_MAX2MIN!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetPolarity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetPolarity.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform setPolarity method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetPolarity { + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(transform.getPolarity() != ModelStandardTransform.POLARITY_BIPOLAR) + throw new RuntimeException("transform.getPolarity() doesn't return ModelStandardTransform.POLARITY_BIPOLAR!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetTransform.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/SetTransform.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform setTransform method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetTransform { + + + private static boolean checkLinearity(ModelStandardTransform transform) + { + double lastx = 0; + for (int p = 0; p < 2; p++) + for (int d = 0; d < 2; d++) + for (double i = 0; i < 1.0; i+=0.001) { + if(p == 0) + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(d == 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + double x = transform.transform(i); + if(i == 0) + lastx = x; + else + { + if(lastx - x > 0.2) return false; + lastx = x; + } + } + return true; + } + + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX); + if(transform.getTransform() != ModelStandardTransform.TRANSFORM_CONVEX) + throw new RuntimeException("transform.getTransform() doesn't return ModelStandardTransform.TRANSFORM_CONVEX!"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformAbsolute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformAbsolute.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform transform method */ + +import com.sun.media.sound.ModelStandardTransform; + +public class TransformAbsolute { + + private static boolean checkLinearity(ModelStandardTransform transform) + { + double lastx = 0; + for (int p = 0; p < 2; p++) + for (int d = 0; d < 2; d++) + for (double i = 0; i < 1.0; i+=0.001) { + if(p == 0) + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(d == 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + double x = transform.transform(i); + if(i == 0) + lastx = x; + else + { + if(lastx - x > 0.2) return false; + lastx = x; + } + } + return true; + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + + } + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_ABSOLUTE); + assertTrue(Math.abs(transform.transform(0.2f) - 0.2f) < 0.0001f); + assertTrue(Math.abs(transform.transform(-0.8f) - 0.8f) < 0.0001f); + assertTrue(checkLinearity(transform)); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformConcave.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformConcave.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform transform method */ + +import com.sun.media.sound.ModelStandardTransform; + +public class TransformConcave { + + private static boolean checkLinearity(ModelStandardTransform transform) + { + double lastx = 0; + for (int p = 0; p < 2; p++) + for (int d = 0; d < 2; d++) + for (double i = 0; i < 1.0; i+=0.001) { + if(p == 0) + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(d == 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + double x = transform.transform(i); + if(i == 0) + lastx = x; + else + { + if(lastx - x > 0.2) return false; + lastx = x; + } + } + return true; + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_CONCAVE); + assertTrue(checkLinearity(transform)); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.0f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.5f) < 0.5f); + assertTrue(Math.abs(transform.transform(1.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(1.0f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.5f) < 0.5f); + assertTrue(Math.abs(transform.transform(0.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.0f) + 1.0f) < 0.0001f); + assertTrue(transform.transform(0.25f) > -0.5f); + assertTrue(Math.abs(transform.transform(0.5f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.75f) < 0.5f); + assertTrue(Math.abs(transform.transform(1.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(1.0f) + 1.0f) < 0.0001f); + assertTrue(transform.transform(0.75f) > -0.5f); + assertTrue(Math.abs(transform.transform(0.50f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.25f) < 0.5f); + assertTrue(Math.abs(transform.transform(0.0f) - 1.0f) < 0.0001f); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformConvex.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformConvex.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform transform method */ + +import com.sun.media.sound.ModelStandardTransform; + +public class TransformConvex { + + private static boolean checkLinearity(ModelStandardTransform transform) + { + double lastx = 0; + for (int p = 0; p < 2; p++) + for (int d = 0; d < 2; d++) + for (double i = 0; i < 1.0; i+=0.001) { + if(p == 0) + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(d == 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + double x = transform.transform(i); + if(i == 0) + lastx = x; + else + { + if(lastx - x > 0.2) return false; + lastx = x; + } + } + return true; + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX); + assertTrue(checkLinearity(transform)); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.0f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.5f) > 0.5f); + assertTrue(Math.abs(transform.transform(1.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(1.0f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.5f) > 0.5f); + assertTrue(Math.abs(transform.transform(0.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.0f) + 1.0f) < 0.0001f); + assertTrue(transform.transform(0.25f) < -0.5f); + assertTrue(Math.abs(transform.transform(0.5f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.75f) > 0.5f); + assertTrue(Math.abs(transform.transform(1.0f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(1.0f) + 1.0f) < 0.0001f); + assertTrue(transform.transform(0.75f) < -0.5f); + assertTrue(Math.abs(transform.transform(0.50f) - 0.0f) < 0.0001f); + assertTrue(transform.transform(0.25f) > 0.5f); + assertTrue(Math.abs(transform.transform(0.0f) - 1.0f) < 0.0001f); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformLinear.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformLinear.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,90 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform transform method */ + +import com.sun.media.sound.ModelStandardTransform; + +public class TransformLinear { + + private static boolean checkLinearity(ModelStandardTransform transform) + { + double lastx = 0; + for (int p = 0; p < 2; p++) + for (int d = 0; d < 2; d++) + for (double i = 0; i < 1.0; i+=0.001) { + if(p == 0) + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + else + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + if(d == 0) + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + else + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + double x = transform.transform(i); + if(i == 0) + lastx = x; + else + { + if(lastx - x > 0.2) return false; + lastx = x; + } + } + return true; + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_LINEAR); + assertTrue(checkLinearity(transform)); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - 0.2f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - 0.8f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - 0.8f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - 0.2f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - (-0.6f)) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - (0.6f)) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - (0.6f)) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - (-0.6f)) < 0.0001f); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformSwitch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/ModelStandardTransform/TransformSwitch.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test ModelStandardTransform transform method */ + +import com.sun.media.sound.ModelStandardTransform; + +public class TransformSwitch { + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + ModelStandardTransform transform = new ModelStandardTransform(); + transform.setTransform(ModelStandardTransform.TRANSFORM_SWITCH); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - 0.0f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - 1.0f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - 0.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) + 1.0f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) - 1.0f) < 0.0001f); + + transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN); + transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR); + assertTrue(Math.abs(transform.transform(0.2f) - 1.0f) < 0.0001f); + assertTrue(Math.abs(transform.transform(0.8f) + 1.0f) < 0.0001f); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Available.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Available.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader available method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Available { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeByte(10); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + RIFFReader readchunk = reader.nextChunk(); + int avail = readchunk.available(); + readchunk.readByte(); + assertEquals(avail - 1,readchunk.available()); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Close.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Close.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader close method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Close { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + reader.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/GetFilePointer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/GetFilePointer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader getFilePointer method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetFilePointer { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeByte(10); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + RIFFReader readchunk = reader.nextChunk(); + long p = readchunk.getFilePointer(); + readchunk.readByte(); + assertEquals(p+1,readchunk.getFilePointer()); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/GetSize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/GetSize.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader getSize method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetSize { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeByte(10); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getSize(), (long)readchunk.available()); + readchunk.readByte(); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/HasNextChunk.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/HasNextChunk.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,85 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader hasNextChunk method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class HasNextChunk { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean a) throws Exception + { + if(!a) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeByte(10); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertTrue(reader.hasNextChunk()); + RIFFReader readchunk = reader.nextChunk(); + readchunk.readByte(); + readchunk.close(); + assertTrue(!reader.hasNextChunk()); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Read.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Read.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader read method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Read { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.write((byte)33); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(readchunk.read(), 33); + fis.close(); + reader = null; + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadByte.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadByte.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader read(byte) method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadByte { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeByte((byte)33); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals((int)reader.readByte(), 33); + fis.close(); + reader = null; + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadByteArrayIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadByteArrayIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader read(byte[], int, int) method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadByteArrayIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.write(new byte[] {1,2,3}); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(readchunk.read(), 1); + assertEquals(readchunk.read(), 2); + assertEquals(readchunk.read(), 3); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readInt method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeInt(133); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readInt(), 133); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadLong.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadLong.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readLong method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadLong { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeLong(133L); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readLong(), 133L); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadShort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadShort.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readShort method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadShort { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeShort((short)133); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readShort(), (short)133); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadString.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadString.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readString method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadString { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeString("HELLO",5); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readString(5), "HELLO"); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedByte.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedByte.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readUnsignedByte method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadUnsignedByte { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeUnsignedByte(77); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readUnsignedByte(), 77); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readUnsignedInt method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadUnsignedInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeUnsignedInt(55377); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readUnsignedInt(), 55377L); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedShort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/ReadUnsignedShort.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader readUnsignedShort method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ReadUnsignedShort { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.writeUnsignedShort(377); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(reader.readUnsignedShort(), 377); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Skip.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/Skip.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffReader skip method */ + +import java.io.File; +import java.io.FileInputStream; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Skip { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + writer = new RIFFWriter(tempfile, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.write((byte)33); + chunk.write((byte)44); + writer.close(); + writer = null; + FileInputStream fis = new FileInputStream(tempfile); + reader = new RIFFReader(fis); + RIFFReader readchunk = reader.nextChunk(); + reader.skip(1); + assertEquals(readchunk.read(), 44); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/WriteOutputStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/RiffReaderWriter/WriteOutputStream.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test RiffWriter(OutputStream) constructor */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class WriteOutputStream { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + RIFFWriter writer = null; + RIFFReader reader = null; + File tempfile = File.createTempFile("test",".riff"); + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + writer = new RIFFWriter(baos, "TEST"); + RIFFWriter chunk = writer.writeChunk("TSCH"); + chunk.write((byte)33); + writer.close(); + writer = null; + ByteArrayInputStream fis = new ByteArrayInputStream(baos.toByteArray()); + reader = new RIFFReader(fis); + assertEquals(reader.getFormat(), "RIFF"); + assertEquals(reader.getType(), "TEST"); + RIFFReader readchunk = reader.nextChunk(); + assertEquals(readchunk.getFormat(), "TSCH"); + assertEquals(readchunk.read(), 33); + fis.close(); + reader = null; + + + } + finally + { + if(writer != null) + writer.close(); + if(reader != null) + reader.close(); + + if(tempfile.exists()) + if(!tempfile.delete()) + tempfile.deleteOnExit(); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelInstrument) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + SimpleInstrument subins = new SimpleInstrument(); + subins.add(performers[0]); + instrument.add(subins); + instrument.add(performers[1]); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelInstrument,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelInstrumentIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + SimpleInstrument subins = new SimpleInstrument(); + subins.add(performers[0]); + instrument.add(subins, 18, 40); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelInstrument,int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelInstrumentIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + SimpleInstrument subins = new SimpleInstrument(); + subins.add(performers[0]); + instrument.add(subins,18,40,20,75); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelInstrumentIntIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,97 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelInstrument,int,int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelInstrumentIntIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + SimpleInstrument subins = new SimpleInstrument(); + subins.add(performers[0]); + instrument.add(subins,18,40,20,75,12); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(12, performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformer { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers[0]); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer[]) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerArray { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer[],int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerArrayIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers,18,40); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer[],int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerArrayIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers,18,40,20,75); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerArrayIntIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer[],int,int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerArrayIntIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers,18,40,20,75,12); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(12, performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers[0],18,40); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer,int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers[0],18,40,20,75); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(performers[i].getExclusiveClass(), performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntIntIntIntInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/AddModelPerformerIntIntIntIntInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument add(ModelPerformer,int,int,int,int,int) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddModelPerformerIntIntIntIntInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers[0],18,40,20,75,12); + ModelPerformer[] performers2 = instrument.getPerformers(); + for (int i = 0; i < performers2.length; i++) { + assertEquals(performers[i].getConnectionBlocks(), performers2[i].getConnectionBlocks()); + assertEquals(12, performers2[i].getExclusiveClass()); + if(performers[i].getKeyFrom() < 18) + assertEquals(18, performers2[i].getKeyFrom()); + else + assertEquals(performers[i].getKeyFrom(), performers2[i].getKeyFrom()); + if(performers[i].getKeyTo() > 40) + assertEquals(40, performers2[i].getKeyTo()); + else + assertEquals(performers[i].getKeyTo(), performers2[i].getKeyTo()); + if(performers[i].getVelFrom() < 20) + assertEquals(20, performers2[i].getVelFrom()); + else + assertEquals(performers[i].getVelFrom(), performers2[i].getVelFrom()); + if(performers[i].getVelTo() > 75) + assertEquals(75, performers2[i].getVelTo()); + else + assertEquals(performers[i].getVelTo(), performers2[i].getVelTo()); + assertEquals(performers[i].getOscillators(), performers2[i].getOscillators()); + assertEquals(performers[i].isSelfNonExclusive(), performers2[i].isSelfNonExclusive()); + assertEquals(performers[i].isDefaultConnectionsEnabled(), performers2[i].isDefaultConnectionsEnabled()); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/Clear.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/Clear.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument clear method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Clear { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.add(performers[0]); + instrument.clear(); + assertEquals(instrument.getPerformers().length, 0); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/SetName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/SetName.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument setName(String) method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetName { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + instrument.setName("hello"); + assertEquals(instrument.getName(), "hello"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleInstrument/SetPatch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleInstrument/SetPatch.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleInstrument setPatch(Patch) method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetPatch { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + + SimpleInstrument instrument = new SimpleInstrument(); + + ModelPerformer[] performers = new ModelPerformer[2]; + + performers[0] = new ModelPerformer(); + performers[0].setExclusiveClass(1); + performers[0].setKeyFrom(36); + performers[0].setKeyTo(48); + performers[0].setVelFrom(16); + performers[0].setVelTo(80); + performers[0].setSelfNonExclusive(true); + performers[0].setDefaultConnectionsEnabled(false); + performers[0].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[0].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + performers[1] = new ModelPerformer(); + performers[1].setExclusiveClass(0); + performers[1].setKeyFrom(12); + performers[1].setKeyTo(24); + performers[1].setVelFrom(20); + performers[1].setVelTo(90); + performers[1].setSelfNonExclusive(false); + performers[0].setDefaultConnectionsEnabled(true); + performers[1].getConnectionBlocks().add(new ModelConnectionBlock()); + performers[1].getOscillators().add(new ModelByteBufferWavetable(new ModelByteBuffer(new byte[] {1,2,3}))); + + Patch patch = new Patch(0,36); + instrument.setPatch(patch); + assertEquals(instrument.getPatch().getProgram(), patch.getProgram()); + assertEquals(instrument.getPatch().getBank(), patch.getBank()); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/AddInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/AddInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank addInstrument method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(3,7)); + soundbank.addInstrument(ins); + assertEquals(soundbank.getInstruments().length, 1); + assertEquals(soundbank.getInstruments()[0], ins); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/AddResource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/AddResource.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,52 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank addResource method */ + +import javax.sound.midi.SoundbankResource; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AddResource { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + SoundbankResource res = new SoundbankResource(soundbank, "test", null) { + public Object getData() { + return null; + }}; + soundbank.addResource(res); + assertEquals(soundbank.getResources().length, 1); + assertEquals(soundbank.getResources()[0], res); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/GetInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/GetInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank getInstrument method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(3,7)); + soundbank.addInstrument(ins); + assertEquals(soundbank.getInstrument(new Patch(3,7)), ins); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/RemoveInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/RemoveInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank removeInstrument method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class RemoveInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean a) throws Exception + { + if(!a) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(3,7)); + soundbank.addInstrument(ins); + soundbank.removeInstrument(ins); + assertEquals(soundbank.getInstruments().length, 0); + assertTrue(soundbank.getInstrument(new Patch(3,7)) == null); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetDescription.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetDescription.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank setDescription method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetDescription { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + soundbank.setDescription("hello"); + assertEquals(soundbank.getDescription(), "hello"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetName.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank setName method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetName { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + soundbank.setName("hello"); + assertEquals(soundbank.getName(), "hello"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetVendor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetVendor.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank setVendor method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetVendor { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + soundbank.setVendor("hello"); + assertEquals(soundbank.getVendor(), "hello"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetVersion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SimpleSoundbank/SetVersion.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SimpleSoundbank setVersion method */ + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SetVersion { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + public static void main(String[] args) throws Exception { + SimpleSoundbank soundbank = new SimpleSoundbank(); + soundbank.setVersion("hello"); + assertEquals(soundbank.getVersion(), "hello"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Array.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Array.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioBuffer array method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Array { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioFormat frm = new AudioFormat(8000, 8, 1, true, false); + SoftAudioBuffer buff = new SoftAudioBuffer(377, frm); + float[] ar = buff.array(); + assertEquals(ar.length, 377); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Clear.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Clear.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioBuffer clear method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Clear { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioFormat frm = new AudioFormat(8000, 8, 1, true, false); + SoftAudioBuffer buff = new SoftAudioBuffer(377, frm); + buff.array(); + assertTrue(!buff.isSilent()); + buff.clear(); + assertTrue(buff.isSilent()); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Get.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/Get.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioBuffer get method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Get { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioFormat frm = new AudioFormat(8000, 16, 1, true, false); + SoftAudioBuffer buff = new SoftAudioBuffer(100, frm); + float[] ar = buff.array(); + for (int i = 0; i < ar.length; i++) { + if(i % 2 == 0) + ar[i] = 1; + if(i % 2 == 0) + ar[i] = -0.5f; + } + + byte[] bbuff = new byte[ar.length*frm.getFrameSize()]; + buff.get(bbuff, 0); + float[] ar2 = new float[ar.length]; + AudioFloatConverter.getConverter(frm).toFloatArray(bbuff, ar2); + + for (int i = 0; i < ar2.length; i++) + if(Math.abs(ar[i] - ar2[i]) > 0.001) + throw new Exception("conversion failure!"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/NewSoftAudioBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioBuffer/NewSoftAudioBuffer.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,55 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioBuffer constructor */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewSoftAudioBuffer { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioFormat frm = new AudioFormat(8000, 8, 1, true, false); + SoftAudioBuffer buff = new SoftAudioBuffer(377, frm); + assertEquals(buff.getSize(), 377); + assertEquals(buff.getFormat(), frm); + assertTrue(buff.isSilent()); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/GetFormat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/GetFormat.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioSynthesizer getFormat method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetFormat { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + AudioFormat defformat = synth.getFormat(); + assertTrue(defformat != null); + synth.openStream(null, null); + assertTrue(synth.getFormat().toString().equals(defformat.toString())); + synth.close(); + AudioFormat custformat = new AudioFormat(8000, 16, 1, true, false); + synth.openStream(custformat, null); + assertTrue(synth.getFormat().toString().equals(custformat.toString())); + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/GetPropertyInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/GetPropertyInfo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioSynthesizer getPropertyInfo method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetPropertyInfo { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + AudioSynthesizerPropertyInfo[] info = synth.getPropertyInfo(null); + assertTrue(info != null); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/Open.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/Open.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioSynthesizer open method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Open { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + SourceDataLine line = AudioSystem.getSourceDataLine(new AudioFormat(44100, 16, 2, true, false)); + synth.open(line, null); + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/OpenStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftAudioSynthesizer/OpenStream.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftAudioSynthesizer openStream method */ + +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class OpenStream { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.isOpen()); + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/AllNotesOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/AllNotesOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel allNotesOff method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AllNotesOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.noteOn(60, 64); + soft.read(1); + VoiceStatus[] v = soft.synth.getVoiceStatus(); + assertEquals(v[0].note, 60); + assertEquals(v[0].active, true); + channel.allNotesOff(); + soft.read(1); + v = soft.synth.getVoiceStatus(); + assertEquals(v[0].active, false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/AllSoundOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/AllSoundOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel allSoundOff method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class AllSoundOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.noteOn(60, 64); + soft.read(1); + VoiceStatus[] v = soft.synth.getVoiceStatus(); + assertEquals(v[0].note, 60); + assertEquals(v[0].active, true); + channel.allSoundOff(); + soft.read(1); + v = soft.synth.getVoiceStatus(); + assertEquals(v[0].active, false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/ChannelPressure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/ChannelPressure.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel channelPressure method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ChannelPressure { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setChannelPressure(10); + assertEquals(channel.getChannelPressure(), 10); + channel.setChannelPressure(90); + assertEquals(channel.getChannelPressure(), 90); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/Controller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/Controller.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel controller method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Controller { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + for (int i = 0; i < 128; i++) { + if(i == 0 || i == 32) continue; + channel.controlChange(i, 10); + assertEquals(channel.getController(i), 10); + channel.controlChange(i, 100); + assertEquals(channel.getController(i), 100); + } + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/LocalControl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/LocalControl.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,60 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel localControl method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class LocalControl { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + // Local control not supported + // because this is a software synthesizer + // localControl() should always return false + assertEquals(channel.localControl(true), false); + assertEquals(channel.localControl(false), false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/Mono.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/Mono.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel mono method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Mono { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setMono(true); + assertEquals(channel.getMono(), true); + channel.setMono(false); + assertEquals(channel.getMono(), false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/Mute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/Mute.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel mute method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Mute { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setMute(true); + assertEquals(channel.getMute(), true); + channel.setMute(false); + assertEquals(channel.getMute(), false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel noteOff method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NoteOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.noteOn(60, 64); + soft.read(1); + VoiceStatus[] v = soft.synth.getVoiceStatus(); + assertEquals(v[0].note, 60); + assertEquals(v[0].active, true); + channel.noteOff(60); + soft.read(1); + v = soft.synth.getVoiceStatus();; + assertEquals(v[0].active, false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOff2.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel noteOff method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NoteOff2 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.noteOn(60, 64); + soft.read(1); + VoiceStatus[] v = soft.synth.getVoiceStatus(); + assertEquals(v[0].note, 60); + assertEquals(v[0].active, true); + channel.noteOff(60); + soft.read(1); + v = soft.synth.getVoiceStatus();; + assertEquals(v[0].active, false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOn.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/NoteOn.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel noteOn method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NoteOn { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.noteOn(60, 64); + soft.read(1); + VoiceStatus[] v = soft.synth.getVoiceStatus(); + assertEquals(v[0].note, 60); + assertEquals(v[0].active, true); + channel.noteOn(60, 0); + soft.read(1); + v = soft.synth.getVoiceStatus(); + assertEquals(v[0].active, false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/Omni.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/Omni.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel omni method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Omni { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setOmni(true); + // Poly or Omni not supported by GM2 + // getOmni() should always return false + assertEquals(channel.getOmni(), false); + channel.setOmni(false); + assertEquals(channel.getOmni(), false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/PitchBend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/PitchBend.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel pitchBend method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class PitchBend { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setPitchBend(10); + assertEquals(channel.getPitchBend(), 10); + channel.setPitchBend(9000); + assertEquals(channel.getPitchBend(), 9000); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/PolyPressure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/PolyPressure.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel polyPressure method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class PolyPressure { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + for (int i = 0; i < 128; i++) { + channel.setPolyPressure(i, 10); + assertEquals(channel.getPolyPressure(i),10); + channel.setPolyPressure(i, 100); + assertEquals(channel.getPolyPressure(i),100); + } + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/ProgramChange.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/ProgramChange.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel programChange method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProgramChange { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.programChange(36); + assertEquals(channel.getProgram(), 36); + channel.programChange(48); + assertEquals(channel.getProgram(), 48); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/ResetAllControllers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/ResetAllControllers.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,132 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel resetAllControllers method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ResetAllControllers { + + public static boolean[] dontResetControls = new boolean[128]; + static { + for (int i = 0; i < dontResetControls.length; i++) + dontResetControls[i] = false; + + dontResetControls[0] = true; // Bank Select (MSB) + dontResetControls[32] = true; // Bank Select (LSB) + dontResetControls[7] = true; // Channel Volume (MSB) + dontResetControls[8] = true; // Balance (MSB) + dontResetControls[10] = true; // Pan (MSB) + dontResetControls[11] = true; // Expression (MSB) + dontResetControls[91] = true; // Effects 1 Depth (default: Reverb Send) + dontResetControls[92] = true; // Effects 2 Depth (default: Tremolo Depth) + dontResetControls[93] = true; // Effects 3 Depth (default: Chorus Send) + dontResetControls[94] = true; // Effects 4 Depth (default: Celeste [Detune] Depth) + dontResetControls[95] = true; // Effects 5 Depth (default: Phaser Depth) + dontResetControls[70] = true; // Sound Controller 1 (default: Sound Variation) + dontResetControls[71] = true; // Sound Controller 2 (default: Timbre / Harmonic Quality) + dontResetControls[72] = true; // Sound Controller 3 (default: Release Time) + dontResetControls[73] = true; // Sound Controller 4 (default: Attack Time) + dontResetControls[74] = true; // Sound Controller 5 (default: Brightness) + dontResetControls[75] = true; // Sound Controller 6 (GM2 default: Decay Time) + dontResetControls[76] = true; // Sound Controller 7 (GM2 default: Vibrato Rate) + dontResetControls[77] = true; // Sound Controller 8 (GM2 default: Vibrato Depth) + dontResetControls[78] = true; // Sound Controller 9 (GM2 default: Vibrato Delay) + dontResetControls[79] = true; // Sound Controller 10 (GM2 default: Undefined) + dontResetControls[120] = true; // All Sound Off + dontResetControls[121] = true; // Reset All Controllers + dontResetControls[122] = true; // Local Control On/Off + dontResetControls[123] = true; // All Notes Off + dontResetControls[124] = true; // Omni Mode Off + dontResetControls[125] = true; // Omni Mode On + dontResetControls[126] = true; // Poly Mode Off + dontResetControls[127] = true; // Poly Mode On + + dontResetControls[6] = true; // Data Entry (MSB) + dontResetControls[38] = true; // Data Entry (LSB) + dontResetControls[96] = true; // Data Increment + dontResetControls[97] = true; // Data Decrement + dontResetControls[98] = true; // Non-Registered Parameter Number (LSB) + dontResetControls[99] = true; // Non-Registered Parameter Number(MSB) + dontResetControls[100] = true; // RPN = Null + dontResetControls[101] = true; // RPN = Null + } + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + // First let all controls contain non-default values + for (int i = 0; i < 128; i++) + channel.setPolyPressure(i, 10); + channel.setChannelPressure(10); + channel.setPitchBend(2192); + for (int i = 0; i < 120; i++) + channel.controlChange(i, 1); + channel.resetAllControllers(); + + // Now check if resetAllControllers did what it was suppose to do + + for (int i = 0; i < 128; i++) + assertEquals(channel.getPolyPressure(i), 0); + assertEquals(channel.getChannelPressure(), 0); + assertEquals(channel.getPitchBend(),8192); + for (int i = 0; i < 120; i++) + if(!dontResetControls[i]) + assertEquals(channel.getController(i), 0); + assertEquals(channel.getController(71), 64); // Filter Resonance + assertEquals(channel.getController(72), 64); // Release Time + assertEquals(channel.getController(73), 64); // Attack Time + assertEquals(channel.getController(74), 64); // Brightness + assertEquals(channel.getController(75), 64); // Decay Time + assertEquals(channel.getController(76), 64); // Vibrato Rate + assertEquals(channel.getController(77), 64); // Vibrato Depth + assertEquals(channel.getController(78), 64); // Vibrato Delay + assertEquals(channel.getController(8), 64); // Balance + assertEquals(channel.getController(11), 127); // Expression + assertEquals(channel.getController(98), 127); // NRPN Null + assertEquals(channel.getController(99), 127); // NRPN Null + assertEquals(channel.getController(100), 127); // RPN = Null + assertEquals(channel.getController(101), 127); // RPN = Null + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/SoftTestUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/SoftTestUtils.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.IOException; + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SoftTestUtils { + + public AudioSynthesizer synth = new SoftSynthesizer(); + public AudioInputStream stream; + public byte[] tmpbuffer = new byte[1024]; + + public static SF2Soundbank createTestSoundBank() + { + SF2Soundbank sf2 = new SF2Soundbank(); + AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + float[] data = new float[44100+1000]; + float fr = 440/format.getSampleRate(); + for (int i = 0; i < data.length; i++) + data[i] = (float)Math.sin(i*fr*2*Math.PI); + byte[] bdata = new byte[data.length*format.getFrameSize()]; + AudioFloatConverter.getConverter(format).toByteArray(data, bdata); + SF2Sample sample = new SF2Sample(sf2); + sample.setName("Test Sample"); + sample.setData(bdata); + sample.setStartLoop(500); + sample.setEndLoop(data.length - 500); + sample.setSampleRate((long) format.getSampleRate()); + sample.setOriginalPitch(69); + sf2.addResource(sample); + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Test Layer"); + sf2.addResource(layer); + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.setSample(sample); + layer.getRegions().add(region); + SF2Instrument ins = new SF2Instrument(sf2); + ins.setName("Test Instrument"); + sf2.addInstrument(ins); + SF2InstrumentRegion insregion = new SF2InstrumentRegion(); + insregion.setLayer(layer); + ins.getRegions().add(insregion); + + return sf2; + } + + public SoftTestUtils() throws Exception { + stream = synth.openStream(null, null); + synth.unloadAllInstruments(synth.getDefaultSoundbank()); + synth.loadAllInstruments(createTestSoundBank()); + } + + public void close() throws Exception { + stream.close(); + stream = null; + synth.close(); + synth = null; + } + + public void read(double seconds) throws IOException + { + int bufflen = + stream.getFormat().getFrameSize() * + (int)(stream.getFormat().getFrameRate() * seconds); + while(bufflen != 0) + { + if(bufflen > 1024) + bufflen -= stream.read(tmpbuffer,0,1024); + else + bufflen -= stream.read(tmpbuffer,0, bufflen); + } + } + + public VoiceStatus findVoice(int channel, int note) { + VoiceStatus[] v = synth.getVoiceStatus(); + for (int k = 0; k < v.length; k++) + if(v[k].active) + if(v[k].channel == channel) + if(v[k].note == note) + return v[k]; + return null; + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftChannel/Solo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftChannel/Solo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftChannel solo method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Solo { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + + channel.setSolo(true); + assertEquals(channel.getSolo(), true); + channel.setSolo(false); + assertEquals(channel.getSolo(), false); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftCubicResampler/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftCubicResampler/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftCubicResampler interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftCubicResampler resampler = new SoftCubicResampler(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.005) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.005) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.005) + fail("Interpolation failed, error="+max); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLanczosResampler/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLanczosResampler/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLanczosResampler interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftLanczosResampler resampler = new SoftLanczosResampler(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.01) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.01) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.01) + fail("Interpolation failed, error="+max); + } +} \ No newline at end of file diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_mix { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer in2 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out2 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] testdata2 = new float[in2.getSize()]; + float[] n1a = in1.array(); + float[] n2a = in2.array(); + float[] out1a = out1.array(); + float[] out2a = out2.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*0.9f; + testdata2[i] = (float)Math.sin(i*0.4)*0.9f; + n1a[i] = testdata1[i]; + n2a[i] = testdata2[i]; + out1a[i] = 1; + out2a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(true); + limiter.setInput(0, in1); + limiter.setInput(1, in2); + limiter.setOutput(0, out1); + limiter.setOutput(1, out2); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i] - testdata1[i] - 1) > 0.00001) + throw new Exception("input != output"); + if(Math.abs(out2a[i] - testdata2[i] - 1) > 0.00001) + throw new Exception("input != output"); + } + + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_mono.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_mono.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_mix_mono { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(new AudioFormat(44100, 16, 1, true, false), null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] n1a = in1.array(); + float[] out1a = out1.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*0.9f; + n1a[i] = testdata1[i]; + out1a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(true); + limiter.setInput(0, in1); + limiter.setOutput(0, out1); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i] - testdata1[i] - 1) > 0.00001) + throw new Exception("input != output"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_mono_overdrive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_mono_overdrive.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_mix_mono_overdrive { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(new AudioFormat(44100, 16, 1, true, false), null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] n1a = in1.array(); + float[] out1a = out1.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*2.5f; + n1a[i] = testdata1[i]; + out1a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(true); + limiter.setInput(0, in1); + limiter.setOutput(0, out1); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i]-1) > 1.0) + throw new Exception("abs(output)>1"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_overdrive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_mix_overdrive.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_mix_overdrive { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer in2 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out2 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] testdata2 = new float[in2.getSize()]; + float[] n1a = in1.array(); + float[] n2a = in2.array(); + float[] out1a = out1.array(); + float[] out2a = out2.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*2.5f; + testdata2[i] = (float)Math.sin(i*0.4)*2.5f; + n1a[i] = testdata1[i]; + n2a[i] = testdata2[i]; + out1a[i] = 1; + out2a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(true); + limiter.setInput(0, in1); + limiter.setInput(1, in2); + limiter.setOutput(0, out1); + limiter.setOutput(1, out2); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i]-1) > 1.0) + throw new Exception("abs(output)>1"); + if(Math.abs(out2a[i]-1) > 1.0) + throw new Exception("abs(output)>1"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_normal.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_normal.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_normal { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer in2 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out2 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] testdata2 = new float[in2.getSize()]; + float[] n1a = in1.array(); + float[] n2a = in2.array(); + float[] out1a = out1.array(); + float[] out2a = out2.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*0.9f; + testdata2[i] = (float)Math.sin(i*0.4)*0.9f; + n1a[i] = testdata1[i]; + n2a[i] = testdata2[i]; + out1a[i] = 1; + out2a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(false); + limiter.setInput(0, in1); + limiter.setInput(1, in2); + limiter.setOutput(0, out1); + limiter.setOutput(1, out2); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i] - testdata1[i]) > 0.00001) + throw new Exception("input != output"); + if(Math.abs(out2a[i] - testdata2[i]) > 0.00001) + throw new Exception("input != output"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_normal_mono.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_normal_mono.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_normal_mono { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(new AudioFormat(44100, 16, 1, true, false), null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] n1a = in1.array(); + float[] out1a = out1.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*0.9f; + n1a[i] = testdata1[i]; + out1a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(false); + limiter.setInput(0, in1); + limiter.setOutput(0, out1); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i] - testdata1[i]) > 0.00001) + throw new Exception("input != output"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_overdrive.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_overdrive.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_overdrive { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer in2 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out2 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] testdata2 = new float[in2.getSize()]; + float[] n1a = in1.array(); + float[] n2a = in2.array(); + float[] out1a = out1.array(); + float[] out2a = out2.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*2.5f; + testdata2[i] = (float)Math.sin(i*0.4)*2.5f; + n1a[i] = testdata1[i]; + n2a[i] = testdata2[i]; + out1a[i] = 1; + out2a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(false); + limiter.setInput(0, in1); + limiter.setInput(1, in2); + limiter.setOutput(0, out1); + limiter.setOutput(1, out2); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i]) > 1.0) + throw new Exception("abs(output)>1"); + if(Math.abs(out2a[i]) > 1.0) + throw new Exception("abs(output)>1"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_overdrive_mono.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLimiter/ProcessAudio_replace_overdrive_mono.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,83 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLimiter processAudio method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class ProcessAudio_replace_overdrive_mono { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftSynthesizer synth = new SoftSynthesizer(); + synth.openStream(new AudioFormat(44100, 16, 1, true, false), null); + + SoftAudioBuffer in1 = new SoftAudioBuffer(250, synth.getFormat()); + SoftAudioBuffer out1 = new SoftAudioBuffer(250, synth.getFormat()); + + float[] testdata1 = new float[in1.getSize()]; + float[] n1a = in1.array(); + float[] out1a = out1.array(); + for (int i = 0; i < n1a.length; i++) { + testdata1[i] = (float)Math.sin(i*0.3)*2.5f; + n1a[i] = testdata1[i]; + out1a[i] = 1; + } + + SoftLimiter limiter = new SoftLimiter(); + limiter.init(synth); + limiter.setMixMode(false); + limiter.setInput(0, in1); + limiter.setOutput(0, out1); + limiter.processControlLogic(); + limiter.processAudio(); + limiter.processControlLogic(); + limiter.processAudio(); + // Limiter should delay audio by one buffer, + // and there should almost no different in output v.s. input + for (int i = 0; i < n1a.length; i++) { + if(Math.abs(out1a[i]) > 1.0) + throw new Exception("abs(output)>1"); + } + + synth.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLinearResampler/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLinearResampler/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLinearResampler interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftLinearResampler resampler = new SoftLinearResampler(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.001) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.001) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.001) + fail("Interpolation failed, error="+max); + } +} \ No newline at end of file diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftLinearResampler2/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftLinearResampler2/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftLinearResampler2 interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftLinearResampler2 resampler = new SoftLinearResampler2(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + } +} \ No newline at end of file diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftPointResampler/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftPointResampler/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftPointResampler interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftPointResampler resampler = new SoftPointResampler(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.2) + fail("Interpolation failed, error="+max); + } +} \ No newline at end of file diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftProvider/GetDevice.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftProvider/GetDevice.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,70 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftProvider getDevice method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetDevice { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + + private static class FakeInfo extends Info { + public FakeInfo() { + super("a", "b", "c", "d"); + } + } + + public static void main(String[] args) throws Exception { + SoftProvider provider = new SoftProvider(); + Info[] infos = provider.getDeviceInfo(); + assertTrue(infos.length > 0); + for (int i = 0; i < infos.length; i++) { + assertTrue(infos[i] != null); + MidiDevice d = provider.getDevice(infos[i]); + assertTrue(d instanceof SoftSynthesizer); + } + assertTrue(provider.getDevice(new FakeInfo()) == null); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Close.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Close.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver close method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Close { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + assertEquals(soft.synth.getReceivers().size(), 1); + receiver.close(); + assertEquals(soft.synth.getReceivers().size(), 0); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ActiveSense.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ActiveSense.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_ActiveSense { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void sendActiveSens(Receiver r) throws Exception + { + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.ACTIVE_SENSING); + r.send(smsg, -1); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + sendActiveSens(receiver); + + // 1. Check if notes are keept active + // if send active sens every 200-300 msec + + sendActiveSens(receiver); + channel.noteOn(60, 64); + assertTrue(soft.findVoice(0,60) != null); + for (int i = 0; i < 10; i++) { + soft.read(0.2); // read 200 msec + sendActiveSens(receiver); + assertTrue(soft.findVoice(0,60) != null); + } + // 2. Now we stop send active sense message + // and the note should be killed off + soft.read(2); + assertTrue(soft.findVoice(0,60) == null); + + + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_AllNotesOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_AllNotesOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_AllNotesOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + channel.noteOn(60, 64); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 123,0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_AllSoundOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_AllSoundOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_AllSoundOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + channel.noteOn(60, 64); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 120,0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ChannelPressure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ChannelPressure.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_ChannelPressure { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CHANNEL_PRESSURE,0, 10,0); + receiver.send(smsg, -1); + assertEquals(channel.getChannelPressure(), 10); + smsg.setMessage(ShortMessage.CHANNEL_PRESSURE,0, 90,0); + receiver.send(smsg, -1); + assertEquals(channel.getChannelPressure(), 90); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Controller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Controller.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,66 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_Controller { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + for (int i = 0; i < 128; i++) { + if(i == 0 || i == 32) continue; + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, i,10); + receiver.send(smsg, -1); + assertEquals(channel.getController(i), 10); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, i,100); + receiver.send(smsg, -1); + assertEquals(channel.getController(i), 100); + } + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Mono.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Mono.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_Mono { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 126,100); + receiver.send(smsg, -1); + assertEquals(channel.getMono(), false); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 126,1); + receiver.send(smsg, -1); + assertEquals(channel.getMono(), true); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 127,0); + receiver.send(smsg, -1); + assertEquals(channel.getMono(), false); + + // Check if send mono triggers AllNotesOff + channel.noteOn(60, 64); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 127,0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOff.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOff.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_NoteOff { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 64); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + smsg.setMessage(ShortMessage.NOTE_OFF,0, 60, 0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_NoteOn { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 64); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_AllChannels.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_AllChannels.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_NoteOn_AllChannels { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + for (int i = 0; i < 15; i++) { + if(i == 9) i++; + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.NOTE_ON,i, 60, 64); + receiver.send(smsg, -1); + soft.read(1); + VoiceStatus voice = soft.findVoice(i,60); + assertTrue(voice != null); + smsg.setMessage(ShortMessage.NOTE_ON,i, 60, 0); + receiver.send(smsg, -1); + soft.read(1); + voice = soft.findVoice(i,60); + assertTrue(voice == null); + soft.read(1); + } + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_Delayed.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_Delayed.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_NoteOn_Delayed { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 64); + receiver.send(smsg, 2000000); // Delay sending note for 2 sec + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + soft.read(2); + assertTrue(soft.findVoice(0,60) != null); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_Multiple.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_NoteOn_Multiple.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_NoteOn_Multiple { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 64); + receiver.send(smsg, -1); + smsg.setMessage(ShortMessage.NOTE_ON,0, 61, 64); + receiver.send(smsg, -1); + smsg.setMessage(ShortMessage.NOTE_ON,0, 62, 64); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + assertTrue(soft.findVoice(0,61) != null); + assertTrue(soft.findVoice(0,62) != null); + + smsg.setMessage(ShortMessage.NOTE_ON,0, 60, 0); + receiver.send(smsg, -1); + smsg.setMessage(ShortMessage.NOTE_ON,0, 61, 0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + assertTrue(soft.findVoice(0,61) == null); + assertTrue(soft.findVoice(0,62) != null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Omni.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_Omni.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_Omni { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 125,0); + receiver.send(smsg, -1); + // Poly or Omni not supported by GM2 + // getOmni() should always return false + assertEquals(channel.getOmni(), false); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 124,0); + receiver.send(smsg, -1); + assertEquals(channel.getOmni(), false); + + // Check if send omni triggers AllNotesOff + channel.noteOn(60, 64); + soft.read(1); + assertTrue(soft.findVoice(0,60) != null); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 124,0); + receiver.send(smsg, -1); + soft.read(1); + assertTrue(soft.findVoice(0,60) == null); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_PitchBend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_PitchBend.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_PitchBend { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.PITCH_BEND,0, 10,0); + receiver.send(smsg, -1); + assertEquals(channel.getPitchBend(), 10); + smsg.setMessage(ShortMessage.PITCH_BEND,0, 9000%128,9000/128); + receiver.send(smsg, -1); + assertEquals(channel.getPitchBend(), 9000); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_PolyPressure.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_PolyPressure.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_PolyPressure { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + for (int i = 0; i < 128; i++) { + smsg.setMessage(ShortMessage.POLY_PRESSURE,0, i, 10); + receiver.send(smsg, -1); + assertEquals(channel.getPolyPressure(i),10); + smsg.setMessage(ShortMessage.POLY_PRESSURE,0, i, 100); + receiver.send(smsg, -1); + assertEquals(channel.getPolyPressure(i),100); + } + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ProgramChange.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ProgramChange.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_ProgramChange { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.PROGRAM_CHANGE,0, 36,0); + receiver.send(smsg, -1); + assertEquals(channel.getProgram(), 36); + smsg.setMessage(ShortMessage.PROGRAM_CHANGE,0, 48,0); + receiver.send(smsg, -1); + assertEquals(channel.getProgram(), 48); + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ResetAllControllers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/Send_ResetAllControllers.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,136 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftReceiver send method */ + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Send_ResetAllControllers { + + public static boolean[] dontResetControls = new boolean[128]; + static { + for (int i = 0; i < dontResetControls.length; i++) + dontResetControls[i] = false; + + dontResetControls[0] = true; // Bank Select (MSB) + dontResetControls[32] = true; // Bank Select (LSB) + dontResetControls[7] = true; // Channel Volume (MSB) + dontResetControls[8] = true; // Balance (MSB) + dontResetControls[10] = true; // Pan (MSB) + dontResetControls[11] = true; // Expression (MSB) + dontResetControls[91] = true; // Effects 1 Depth (default: Reverb Send) + dontResetControls[92] = true; // Effects 2 Depth (default: Tremolo Depth) + dontResetControls[93] = true; // Effects 3 Depth (default: Chorus Send) + dontResetControls[94] = true; // Effects 4 Depth (default: Celeste [Detune] Depth) + dontResetControls[95] = true; // Effects 5 Depth (default: Phaser Depth) + dontResetControls[70] = true; // Sound Controller 1 (default: Sound Variation) + dontResetControls[71] = true; // Sound Controller 2 (default: Timbre / Harmonic Quality) + dontResetControls[72] = true; // Sound Controller 3 (default: Release Time) + dontResetControls[73] = true; // Sound Controller 4 (default: Attack Time) + dontResetControls[74] = true; // Sound Controller 5 (default: Brightness) + dontResetControls[75] = true; // Sound Controller 6 (GM2 default: Decay Time) + dontResetControls[76] = true; // Sound Controller 7 (GM2 default: Vibrato Rate) + dontResetControls[77] = true; // Sound Controller 8 (GM2 default: Vibrato Depth) + dontResetControls[78] = true; // Sound Controller 9 (GM2 default: Vibrato Delay) + dontResetControls[79] = true; // Sound Controller 10 (GM2 default: Undefined) + dontResetControls[120] = true; // All Sound Off + dontResetControls[121] = true; // Reset All Controllers + dontResetControls[122] = true; // Local Control On/Off + dontResetControls[123] = true; // All Notes Off + dontResetControls[124] = true; // Omni Mode Off + dontResetControls[125] = true; // Omni Mode On + dontResetControls[126] = true; // Poly Mode Off + dontResetControls[127] = true; // Poly Mode On + + dontResetControls[6] = true; // Data Entry (MSB) + dontResetControls[38] = true; // Data Entry (LSB) + dontResetControls[96] = true; // Data Increment + dontResetControls[97] = true; // Data Decrement + dontResetControls[98] = true; // Non-Registered Parameter Number (LSB) + dontResetControls[99] = true; // Non-Registered Parameter Number(MSB) + dontResetControls[100] = true; // RPN = Null + dontResetControls[101] = true; // RPN = Null + } + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTestUtils soft = new SoftTestUtils(); + MidiChannel channel = soft.synth.getChannels()[0]; + Receiver receiver = soft.synth.getReceiver(); + + // First let all controls contain non-default values + for (int i = 0; i < 128; i++) + channel.setPolyPressure(i, 10); + channel.setChannelPressure(10); + channel.setPitchBend(2192); + for (int i = 0; i < 120; i++) + channel.controlChange(i, 1); + + ShortMessage smsg = new ShortMessage(); + smsg.setMessage(ShortMessage.CONTROL_CHANGE,0, 121,0); + receiver.send(smsg, -1); + + // Now check if resetAllControllers did what it was suppose to do + + for (int i = 0; i < 128; i++) + assertEquals(channel.getPolyPressure(i), 0); + assertEquals(channel.getChannelPressure(), 0); + assertEquals(channel.getPitchBend(),8192); + for (int i = 0; i < 120; i++) + if(!dontResetControls[i]) + assertEquals(channel.getController(i), 0); + assertEquals(channel.getController(71), 64); // Filter Resonance + assertEquals(channel.getController(72), 64); // Release Time + assertEquals(channel.getController(73), 64); // Attack Time + assertEquals(channel.getController(74), 64); // Brightness + assertEquals(channel.getController(75), 64); // Decay Time + assertEquals(channel.getController(76), 64); // Vibrato Rate + assertEquals(channel.getController(77), 64); // Vibrato Depth + assertEquals(channel.getController(78), 64); // Vibrato Delay + assertEquals(channel.getController(8), 64); // Balance + assertEquals(channel.getController(11), 127); // Expression + assertEquals(channel.getController(98), 127); // NRPN Null + assertEquals(channel.getController(99), 127); // NRPN Null + assertEquals(channel.getController(100), 127); // RPN = Null + assertEquals(channel.getController(101), 127); // RPN = Null + + soft.close(); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftReceiver/SoftTestUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftReceiver/SoftTestUtils.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.IOException; + +import javax.sound.midi.*; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class SoftTestUtils { + + public AudioSynthesizer synth = new SoftSynthesizer(); + public AudioInputStream stream; + public byte[] tmpbuffer = new byte[1024]; + + public static SF2Soundbank createTestSoundBank() + { + SF2Soundbank sf2 = new SF2Soundbank(); + AudioFormat format = new AudioFormat(44100, 16, 1, true, false); + float[] data = new float[44100+1000]; + float fr = 440/format.getSampleRate(); + for (int i = 0; i < data.length; i++) + data[i] = (float)Math.sin(i*fr*2*Math.PI); + byte[] bdata = new byte[data.length*format.getFrameSize()]; + AudioFloatConverter.getConverter(format).toByteArray(data, bdata); + SF2Sample sample = new SF2Sample(sf2); + sample.setName("Test Sample"); + sample.setData(bdata); + sample.setStartLoop(500); + sample.setEndLoop(data.length - 500); + sample.setSampleRate((long) format.getSampleRate()); + sample.setOriginalPitch(69); + sf2.addResource(sample); + SF2Layer layer = new SF2Layer(sf2); + layer.setName("Test Layer"); + sf2.addResource(layer); + SF2LayerRegion region = new SF2LayerRegion(); + region.putInteger(SF2Region.GENERATOR_SAMPLEMODES, 1); + region.setSample(sample); + layer.getRegions().add(region); + SF2Instrument ins = new SF2Instrument(sf2); + ins.setName("Test Instrument"); + sf2.addInstrument(ins); + SF2InstrumentRegion insregion = new SF2InstrumentRegion(); + insregion.setLayer(layer); + ins.getRegions().add(insregion); + + return sf2; + } + + public SoftTestUtils() throws Exception { + stream = synth.openStream(null, null); + synth.unloadAllInstruments(synth.getDefaultSoundbank()); + synth.loadAllInstruments(createTestSoundBank()); + } + + public void close() throws Exception { + stream.close(); + stream = null; + synth.close(); + synth = null; + } + + public void read(double seconds) throws IOException + { + int bufflen = + stream.getFormat().getFrameSize() * + (int)(stream.getFormat().getFrameRate() * seconds); + while(bufflen != 0) + { + if(bufflen > 1024) + bufflen -= stream.read(tmpbuffer,0,1024); + else + bufflen -= stream.read(tmpbuffer,0, bufflen); + } + } + + public VoiceStatus findVoice(int channel, int note) { + VoiceStatus[] v = synth.getVoiceStatus(); + for (int k = 0; k < v.length; k++) + if(v[k].active) + if(v[k].channel == channel) + if(v[k].note == note) + return v[k]; + return null; + } + +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSincResampler/Interpolate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSincResampler/Interpolate.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,113 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSincResampler interpolate method */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Interpolate { + + private static float getResamplerTestValue(double i) + { + return (float)Math.sin(i / 10.0); + } + + private static void perfectInterpolation(float[] in_offset, float in_end, + float[] startpitch, float pitchstep, float[] out, int[] out_offset, + int out_end) { + + float pitch = startpitch[0]; + float ix = in_offset[0]; + int ox = out_offset[0]; + float ix_end = in_end; + int ox_end = out_end; + if (pitchstep == 0f) { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + } + } else { + while (ix < ix_end && ox < ox_end) { + out[ox++] = getResamplerTestValue(ix); + ix += pitch; + pitch += pitchstep; + } + } + in_offset[0] = ix; + out_offset[0] = ox; + startpitch[0] = pitch; + + } + + private static float testResampler(SoftAbstractResampler resampler, float p_pitch, float p_pitch2) + { + float[] testbuffer = new float[4096]; + float[] testbuffer2 = new float[1024]; + float[] testbuffer3 = new float[1024]; + for (int i = 0; i < testbuffer.length; i++) + testbuffer[i] = getResamplerTestValue(i); + int pads = resampler.getPadding(); + float pitchstep = (p_pitch2 - p_pitch)/1024f; + int[] out_offset2 = {0}; + int[] out_offset3 = {0}; + resampler.interpolate(testbuffer, new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer2, out_offset2, testbuffer2.length); + perfectInterpolation(new float[] {pads}, testbuffer.length - pads, new float[] {p_pitch}, pitchstep, testbuffer3, out_offset3, testbuffer3.length); + int out_off = out_offset2[0]; + if(out_offset3[0] < out_off) + out_off = out_offset3[0]; + float ac_error = 0; + int counter = 0; + for (int i = pads; i < out_off; i++) { + ac_error += Math.abs(testbuffer2[i] - testbuffer3[i]); + counter++; + } + return ac_error / ((float)counter); + } + + private static void fail(String error) throws Exception + { + throw new RuntimeException(error); + } + + public static void main(String[] args) throws Exception { + SoftSincResampler resampler = new SoftSincResampler(); + float max = testResampler(resampler, 0.3f, 0.3f); + if(max > 0.0001) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 0.3f, 0.01f); + if(max > 0.0001) + fail("Interpolation failed, error="+max); + max = testResampler(resampler, 1.0f, 0.00f); + if(max > 0.0001) + fail("Interpolation failed, error="+max); + } +} \ No newline at end of file diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Close.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Close.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer close method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class Close { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + synth.close(); + assertTrue(!synth.isOpen()); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetAvailableInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetAvailableInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getAvailableInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetAvailableInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(defsbk.getInstruments().length == synth.getAvailableInstruments().length); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetChannels.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetChannels.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getChannels method */ + +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetChannels { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.getChannels() != null); + assertTrue(synth.getChannels().length == 16); + MidiChannel[] channels = synth.getChannels(); + for (int i = 0; i < channels.length; i++) { + assertTrue(channels[i] != null); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetDefaultSoundbank.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetDefaultSoundbank.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getDefaultSoundbank method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetDefaultSoundbank { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.getDefaultSoundbank() != null); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetDeviceInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetDeviceInfo.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getDeviceInfo method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetDeviceInfo { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + assertTrue(synth.getDeviceInfo() != null); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetLatency.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetLatency.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getLatency method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetLatency { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(); + assertTrue(synth.getLatency() != -1); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetLoadedInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetLoadedInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getLoadedInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetLoadedInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + synth.unloadAllInstruments(defsbk); + synth.loadAllInstruments(defsbk); + assertTrue(synth.getLoadedInstruments().length != 0); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxPolyphony.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxPolyphony.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getMaxPolyphony method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetMaxPolyphony { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.getMaxPolyphony() != -1); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxReceivers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxReceivers.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getMaxReceivers method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetMaxReceivers { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + assertTrue(synth.getMaxReceivers() == -1); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxTransmitters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMaxTransmitters.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getMaxTransmitters method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetMaxTransmitters { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + assertTrue(synth.getMaxTransmitters() == 0); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMicrosecondPosition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetMicrosecondPosition.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getMicrosecondPosition method */ + +import java.io.IOException; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetMicrosecondPosition { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + AudioInputStream stream = synth.openStream(null, null); + assertTrue(synth.getMicrosecondPosition() == 0); + AudioFormat format = stream.getFormat(); + byte[] buff = new byte[((int)format.getFrameRate())*format.getFrameSize()];; + stream.read(buff); + assertTrue(Math.abs(synth.getMicrosecondPosition()-1000000) < 10000); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceiver.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getReceiver method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetReceiver { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(null,null); + Receiver recv = synth.getReceiver(); + assertTrue(recv != null); + Receiver recv2 = synth.getReceiver(); + assertTrue(recv2 != null); + assertTrue(recv2 != recv); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceiver2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceiver2.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getReceiver method */ + +import javax.sound.midi.Receiver; +import javax.sound.midi.ShortMessage; + +import com.sun.media.sound.AudioSynthesizer; +import com.sun.media.sound.SoftSynthesizer; + +public class GetReceiver2 { + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + Receiver recv = synth.getReceiver(); + assertTrue(recv != null); + ShortMessage sm = new ShortMessage(); + sm.setMessage(ShortMessage.NOTE_OFF, 0, 64, 64); + synth.open(null,null); + recv.send(sm, -1); + synth.close(); + try + { + recv.send(sm, -1); + throw new RuntimeException("Exception not thrown!"); + } + catch(Exception e) + { + // Just checking if exception is thrown + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceivers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetReceivers.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getReceivers method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetReceivers { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(null,null); + assertTrue(synth.getReceivers().size() == 0); + Receiver recv = synth.getReceiver(); + assertTrue(synth.getReceivers().size() == 1); + recv.close(); + assertTrue(synth.getReceivers().size() == 0); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetTransmitter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetTransmitter.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getTransmitter method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetTransmitter { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(null,null); + try + { + synth.getTransmitter(); + throw new Exception("MidiUnavailableException not thrown!"); + } catch (MidiUnavailableException e) { + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetTransmitters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetTransmitters.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getTransmitters method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetTransmitters { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(null,null); + assertTrue(synth.getTransmitters().size() == 0); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetVoiceStatus.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/GetVoiceStatus.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,61 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer getVoiceStatus method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.VoiceStatus; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class GetVoiceStatus { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + VoiceStatus[] v = synth.getVoiceStatus(); + assertTrue(v != null); + assertTrue(synth.getChannels().length != synth.getMaxPolyphony()); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,99 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer implicit open/close using getReceiver. */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.midi.Synthesizer; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class ImplicitOpenClose { + + public static void main(String[] args) throws Exception { + Synthesizer synth = new SoftSynthesizer(); + + ReferenceCountingDevice rcd = (ReferenceCountingDevice)synth; + + // Test single open/close cycle + + Receiver recv = rcd.getReceiverReferenceCounting(); + if(!synth.isOpen()) + throw new Exception("Synthesizer not open!"); + recv.close(); + if(synth.isOpen()) + throw new Exception("Synthesizer not closed!"); + + // Test using 2 receiver cycle + + Receiver recv1 = rcd.getReceiverReferenceCounting(); + if(!synth.isOpen()) + throw new Exception("Synthesizer not open!"); + Receiver recv2 = rcd.getReceiverReferenceCounting(); + if(!synth.isOpen()) + throw new Exception("Synthesizer not open!"); + + recv2.close(); + if(!synth.isOpen()) + throw new Exception("Synthesizer was closed!"); + recv1.close(); + if(synth.isOpen()) + throw new Exception("Synthesizer not closed!"); + + // Test for explicit,implicit conflict + + synth.open(); + Receiver recv3 = rcd.getReceiverReferenceCounting(); + if(!synth.isOpen()) + throw new Exception("Synthesizer not open!"); + recv3.close(); + if(!synth.isOpen()) + throw new Exception("Synthesizer was closed!"); + synth.close(); + if(synth.isOpen()) + throw new Exception("Synthesizer not closed!"); + + // Test for implicit,explicit conflict + + recv3 = rcd.getReceiverReferenceCounting(); + synth.open(); + if(!synth.isOpen()) + throw new Exception("Synthesizer not open!"); + recv3.close(); + if(!synth.isOpen()) + throw new Exception("Synthesizer was closed!"); + synth.close(); + if(synth.isOpen()) + throw new Exception("Synthesizer not closed!"); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/IsOpen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/IsOpen.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer isOpen method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class IsOpen { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.isOpen()); + synth.close(); + assertTrue(!synth.isOpen()); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/IsSoundbankSupported.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/IsSoundbankSupported.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer isSoundbankSupported method */ + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class IsSoundbankSupported { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + sbk.addInstrument(ins); + assertTrue(synth.isSoundbankSupported(sbk)); + Soundbank dummysbk = new Soundbank() + { + public String getName() { + return null; + } + public String getVersion() { + return null; + } + public String getVendor() { + return null; + } + public String getDescription() { + return null; + } + public SoundbankResource[] getResources() { + return null; + } + public Instrument[] getInstruments() { + Instrument ins = new Instrument(null, null, null, null) + { + public Object getData() { + return null; + } + }; + return new Instrument[] {ins}; + } + public Instrument getInstrument(Patch patch) { + return null; + } + }; + assertTrue(!synth.isSoundbankSupported(dummysbk)); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadAllInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadAllInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer loadAllInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class LoadAllInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(0,1)); + sbk.addInstrument(ins); + SimpleInstrument ins2 = new SimpleInstrument(); + ins2.setPatch(new Patch(0,2)); + sbk.addInstrument(ins2); + synth.loadAllInstruments(sbk); + assertTrue(synth.getLoadedInstruments().length == 2); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer loadAllInstrument method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class LoadInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(0,1)); + sbk.addInstrument(ins); + SimpleInstrument ins2 = new SimpleInstrument(); + ins2.setPatch(new Patch(0,2)); + sbk.addInstrument(ins2); + synth.loadInstrument(ins2); + assertTrue(synth.getLoadedInstruments().length == 1); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/LoadInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer loadAllInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class LoadInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(0,1)); + sbk.addInstrument(ins); + SimpleInstrument ins2 = new SimpleInstrument(); + ins2.setPatch(new Patch(0,2)); + sbk.addInstrument(ins2); + synth.loadInstruments(sbk, new Patch[] {ins2.getPatch()}); + assertTrue(synth.getLoadedInstruments().length == 1); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer open method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class Open { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.open(); + assertTrue(synth.isOpen()); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/OpenStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/OpenStream.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,58 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer openStream method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class OpenStream { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + assertTrue(synth.isOpen()); + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/RemapInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/RemapInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,76 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer remapInstrument method */ + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class RemapInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + Instrument ins0 = defsbk.getInstrument(new Patch(0,0)); + Instrument ins10 = defsbk.getInstrument(new Patch(0,10)); + assertTrue(synth.remapInstrument(ins0, ins10)); + Instrument[] loaded = synth.getLoadedInstruments(); + for (int i = 0; i < loaded.length; i++) { + if(loaded[i].getPatch().getBank() == 0) + if(loaded[i].getPatch().getProgram() == 10) + { + assertEquals(loaded[i].getName(), ins0.getName()); + break; + } + } + + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/TestRender1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/TestRender1.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,206 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer simple note rendering in many settings */ + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.*; +import javax.sound.midi.*; + +import com.sun.media.sound.*; + +public class TestRender1 { + + public static double send(Sequence seq, Receiver recv) { + float divtype = seq.getDivisionType(); + assert (seq.getDivisionType() == Sequence.PPQ); + Track[] tracks = seq.getTracks(); + int[] trackspos = new int[tracks.length]; + int mpq = 60000000 / 100; + int seqres = seq.getResolution(); + long lasttick = 0; + long curtime = 0; + while (true) { + MidiEvent selevent = null; + int seltrack = -1; + for (int i = 0; i < tracks.length; i++) { + int trackpos = trackspos[i]; + Track track = tracks[i]; + if (trackpos < track.size()) { + MidiEvent event = track.get(trackpos); + if (selevent == null + || event.getTick() < selevent.getTick()) { + selevent = event; + seltrack = i; + } + } + } + if (seltrack == -1) + break; + trackspos[seltrack]++; + long tick = selevent.getTick(); + if (divtype == Sequence.PPQ) + curtime += ((tick - lasttick) * mpq) / seqres; + else + curtime = (long) ((tick * 1000000.0 * divtype) / seqres); + lasttick = tick; + MidiMessage msg = selevent.getMessage(); + if (msg instanceof MetaMessage) { + if (divtype == Sequence.PPQ) + if (((MetaMessage) msg).getType() == 0x51) { + byte[] data = ((MetaMessage) msg).getData(); + mpq = ((data[0] & 0xff) << 16) + | ((data[1] & 0xff) << 8) | (data[2] & 0xff); + } + } else { + if (recv != null) + recv.send(msg, curtime); + } + } + + return curtime / 1000000.0; + } + + public static void test(AudioFormat format, Map info) + throws Exception { + OutputStream nullout = new OutputStream() { + public void write(int b) throws IOException { + } + + public void write(byte[] b, int off, int len) throws IOException { + } + + public void write(byte[] b) throws IOException { + } + }; + render(nullout, format, info); + } + + public static void render(OutputStream os, AudioFormat format, + Map info) throws Exception { + AudioSynthesizer synth = (AudioSynthesizer) new SoftSynthesizer(); + AudioInputStream stream = synth.openStream(format, info); + Receiver recv = synth.getReceiver(); + Soundbank defsbk = synth.getDefaultSoundbank(); + if (defsbk != null) + synth.unloadAllInstruments(defsbk); + synth.loadAllInstruments(soundbank); + + double totalTime = 5; + send(sequence, recv); + + long len = (long) (stream.getFormat().getFrameRate() * (totalTime + 4)); + stream = new AudioInputStream(stream, stream.getFormat(), len); + + long t = System.currentTimeMillis(); + AudioSystem.write(stream, AudioFileFormat.Type.WAVE, os); + t = System.currentTimeMillis() - t; + stream.close(); + } + + + static Soundbank soundbank; + + static Sequence sequence; + + public static void main(String[] args) throws Exception { + + InputStream sb = new BufferedInputStream(TestRender1.class + .getResourceAsStream("/ding.sf2")); + soundbank = MidiSystem.getSoundbank(sb); + sb.close(); + + InputStream si = new BufferedInputStream(TestRender1.class + .getResourceAsStream("/expresso.mid")); + sequence = MidiSystem.getSequence(si); + si.close(); + + AudioFormat format; + Map info = new HashMap(); + { + format = new AudioFormat(22050, 16, 2, true, false); + test(format, info); + format = new AudioFormat(44100, 16, 2, true, false); + test(format, info); + } + { + format = new AudioFormat(44100, 8, 2, true, false); + test(format, info); + format = new AudioFormat(44100, 16, 2, true, false); + test(format, info); + format = new AudioFormat(44100, 24, 2, true, false); + test(format, info); + } + { + format = new AudioFormat(44100, 16, 1, true, false); + test(format, info); + format = new AudioFormat(44100, 16, 2, true, false); + test(format, info); + } + { + format = new AudioFormat(44100, 16, 2, true, false); + + info.clear(); + info.put("control rate", 100f); + test(format, info); + info.clear(); + info.put("control rate", 147f); + test(format, info); + + } + { + format = new AudioFormat(44100, 16, 2, true, false); + + info.clear(); + info.put("interpolation", "point"); + test(format, info); + info.clear(); + info.put("interpolation", "linear"); + test(format, info); + info.clear(); + info.put("interpolation", "cubic"); + test(format, info); + } + { + format = new AudioFormat(44100, 16, 2, true, false); + info.clear(); + info.put("max polyphony", 4); + test(format, info); + info.clear(); + info.put("max polyphony", 16); + test(format, info); + info.clear(); + + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadAllInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadAllInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer unloadAllInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class UnloadAllInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + assertTrue(synth.getAvailableInstruments().length == 0); + synth.loadAllInstruments(defsbk); + assertTrue(synth.getLoadedInstruments().length != 0); + synth.unloadAllInstruments(defsbk); + assertTrue(synth.getLoadedInstruments().length == 0); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadInstrument.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadInstrument.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer unloadInstrument method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class UnloadInstrument { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(0,1)); + sbk.addInstrument(ins); + SimpleInstrument ins2 = new SimpleInstrument(); + ins2.setPatch(new Patch(0,2)); + sbk.addInstrument(ins2); + synth.loadInstrument(ins2); + assertTrue(synth.getLoadedInstruments().length == 1); + synth.unloadInstrument(ins2); + assertTrue(synth.getLoadedInstruments().length == 0); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadInstruments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/UnloadInstruments.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftSynthesizer unloadInstruments method */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Soundbank; +import javax.sound.sampled.*; +import javax.sound.midi.MidiDevice.Info; + +import com.sun.media.sound.*; + +public class UnloadInstruments { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + AudioSynthesizer synth = new SoftSynthesizer(); + synth.openStream(null, null); + Soundbank defsbk = synth.getDefaultSoundbank(); + if(defsbk != null) + { + assertTrue(synth.getLoadedInstruments().length == 0); + synth.unloadAllInstruments(defsbk); + SimpleSoundbank sbk = new SimpleSoundbank(); + SimpleInstrument ins = new SimpleInstrument(); + ins.setPatch(new Patch(0,1)); + sbk.addInstrument(ins); + SimpleInstrument ins2 = new SimpleInstrument(); + ins2.setPatch(new Patch(0,2)); + sbk.addInstrument(ins2); + synth.loadInstrument(ins2); + assertTrue(synth.getLoadedInstruments().length == 1); + synth.unloadInstruments(sbk, new Patch[] {ins2.getPatch()}); + assertTrue(synth.getLoadedInstruments().length == 0); + } + synth.close(); + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ding.sf2 Binary file jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ding.sf2 has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/expresso.mid Binary file jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/expresso.mid has changed diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/GetName.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/GetName.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning getName method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetName { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTuning tuning = new SoftTuning(); + tuning.setName("custom"); + assertEquals(tuning.getName(), "custom"); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/GetTuning.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/GetTuning.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning getTuning method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetTuning { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTuning tuning = new SoftTuning(); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) { + assertTrue(Math.abs(tunings[i]-i*100) < 0.00001); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/GetTuningInt.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/GetTuningInt.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,53 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning getTuning(int) method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class GetTuningInt { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTuning tuning = new SoftTuning(); + assertTrue(Math.abs(tuning.getTuning(36)-3600) < 0.00001); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load1.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import java.io.UnsupportedEncodingException; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load1 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning.shtml + // 0x01 BULK TUNING DUMP + SoftTuning tuning = new SoftTuning(); + byte[] name; + name = "Testing123 ".getBytes("ascii"); + + int[] msg = new int[24+3*128]; + int[] head = {0xf0,0x7e,0x7f,0x08,0x01,0x00}; + int ox = 0; + for (int i = 0; i < head.length; i++) + msg[ox++] = head[i]; + for (int i = 0; i < name.length; i++) + msg[ox++] = name[i]; + for (int i = 0; i < 128; i++) { + msg[ox++] = i; + msg[ox++] = 64; + msg[ox++] = 0; + } + + // Calc checksum + int x = msg[1] & 0xFF; // 7E + x = x ^ (msg[2] & 0xFF); // + x = x ^ (msg[4] & 0xFF); // nn + x = x ^ (msg[5] & 0xFF); // tt + for (int i = 22; i < msg.length - 2; i++) + x = x ^ (msg[i] & 0xFF); + msg[ox++] = (x & 127); + + msg[ox++] = 0xf7; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + + tuning.load(bmsg); + assertEquals(tuning.getName(), "Testing123 "); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + 50)) < 0.00001); + + // Check if tuning fails if checksum is wrong + /* + msg[msg.length - 2] += 10; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning = new SoftTuning(); + tuning.load(bmsg); + assertTrue(!tuning.getName().equals("Testing123 ")); + */ + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load2.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,71 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load2 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning.shtml + // 0x02 SINGLE NOTE TUNING CHANGE (REAL-TIME) + SoftTuning tuning = new SoftTuning(); + int[] msg = {0xf0,0x7f,0x7f,0x08,0x02,0x10,0x02, + 36,36,64,0, + 40,70,0,0, + 0xf7}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) { + if(i == 36) + assertTrue(Math.abs(tunings[i]-3650)< 0.00001); + else if(i == 40) + assertTrue(Math.abs(tunings[i]-7000) < 0.00001); + else + assertTrue(Math.abs(tunings[i]-i*100) < 0.00001); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load4.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load4.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,104 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import java.io.UnsupportedEncodingException; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load4 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning_extens.shtml + // 0x04 KEY-BASED TUNING DUMP + SoftTuning tuning = new SoftTuning(); + byte[] name; + name = "Testing123 ".getBytes("ascii"); + + int[] msg = new int[25+3*128]; + int[] head = {0xf0,0x7e,0x7f,0x08,0x04,0x00,0x00}; + int ox = 0; + for (int i = 0; i < head.length; i++) + msg[ox++] = head[i]; + for (int i = 0; i < name.length; i++) + msg[ox++] = name[i]; + for (int i = 0; i < 128; i++) { + msg[ox++] = i; + msg[ox++] = 64; + msg[ox++] = 0; + } + + // Calc checksum + int x = msg[1] & 0xFF; + for (int i = 2; i < msg.length - 2; i++) + x = x ^ (msg[i] & 0xFF); + msg[ox++] = (x & 127); + + msg[ox++] = 0xf7; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + + tuning.load(bmsg); + assertEquals(tuning.getName(), "Testing123 "); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + 50)) < 0.00001); + + // Check if tuning fails if checksum is wrong + msg[msg.length - 2] += 10; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning = new SoftTuning(); + tuning.load(bmsg); + assertTrue(!tuning.getName().equals("Testing123 ")); + + // Check if tuning fails if checksum is wrong + msg[msg.length - 2] += 10; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning = new SoftTuning(); + tuning.load(bmsg); + assertTrue(!tuning.getName().equals("Testing123 ")); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load5.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load5.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,87 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import java.io.UnsupportedEncodingException; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load5 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning_extens.shtml + // 0x05 SCALE/OCTAVE TUNING DUMP, 1 byte format + SoftTuning tuning = new SoftTuning(); + + byte[] name; + name = "Testing123 ".getBytes("ascii"); + int[] msg = {0xf0,0x7e,0x7f,0x08,0x05,0,0, + name[0],name[1],name[2],name[3],name[4],name[5],name[6], + name[7],name[8],name[9],name[10],name[11],name[12],name[13], + name[14],name[15], + 5,10,15,20,25,30,35,40,45,50,51,52,0, + 0xf7}; + // Calc checksum + int x = msg[1] & 0xFF; + for (int i = 2; i < msg.length - 2; i++) + x = x ^ (msg[i] & 0xFF); + msg[msg.length-2] = (x & 127); + + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + (oct[i%12]-64))) < 0.00001); + + // Check if tuning fails if checksum is wrong + msg[msg.length - 2] += 10; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning = new SoftTuning(); + tuning.load(bmsg); + assertTrue(!tuning.getName().equals("Testing123 ")); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load6.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load6.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import java.io.UnsupportedEncodingException; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load6 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning_extens.shtml + // 0x06 SCALE/OCTAVE TUNING DUMP, 2 byte format + SoftTuning tuning = new SoftTuning(); + + byte[] name; + name = "Testing123 ".getBytes("ascii"); + int[] msg = {0xf0,0x7e,0x7f,0x08,0x06,0,0, + name[0],name[1],name[2],name[3],name[4],name[5],name[6], + name[7],name[8],name[9],name[10],name[11],name[12],name[13], + name[14],name[15], + 5,10,15,20,25,30,35,40,45,50,51,52, + 5,10,15,20,25,30,35,40,45,50,51,52, + 0,0xf7}; + // Calc checksum + int x = msg[1] & 0xFF; + for (int i = 2; i < msg.length - 2; i++) + x = x ^ (msg[i] & 0xFF); + msg[msg.length-2] = (x & 127); + + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52,5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + { + double c = (oct[(i%12)*2]*128 + oct[(i%12)*2+1] -8192)*(100.0/8192.0); + assertTrue(Math.abs(tunings[i]-(i*100 + (c))) < 0.00001); + } + + // Check if tuning fails if checksum is wrong + msg[msg.length - 2] += 10; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning = new SoftTuning(); + tuning.load(bmsg); + assertTrue(!tuning.getName().equals("Testing123 ")); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load7.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load7.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,72 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load7 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning_extens.shtml + // 0x07 SINGLE NOTE TUNING CHANGE (NON REAL-TIME) (BANK) + SoftTuning tuning = new SoftTuning(); + int[] msg = {0xf0,0x7f,0x7f,0x08,0x07,0x00,0x00,0x02, + 36,36,64,0, + 40,70,0,0, + 0xf7}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) { + if(i == 36) + assertTrue(Math.abs(tunings[i]-3650)< 0.00001); + else if(i == 40) + assertTrue(Math.abs(tunings[i]-7000) < 0.00001); + else + assertTrue(Math.abs(tunings[i]-i*100) < 0.00001); + } + + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load8.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load8.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load8 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning-scale.shtml + // 0x08 scale/octave tuning 1-byte form (Non Real-Time/REAL-TIME) + SoftTuning tuning = new SoftTuning(); + int[] msg = {0xf0,0x7f,0x7f,0x08,0x08,0x03,0x7f,0x7f, + 5,10,15,20,25,30,35,40,45,50,51,52, + 0xf7}; + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + (oct[i%12]-64))) < 0.00001); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/Load9.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/Load9.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning load method */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class Load9 { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // http://www.midi.org/about-midi/tuning-scale.shtml + // 0x09 scale/octave tuning 2-byte form (Non Real-Time/REAL-TIME) + SoftTuning tuning = new SoftTuning(); + int[] msg = {0xf0,0x7f,0x7f,0x08,0x09,0x03,0x7f,0x7f, + 5,10,15,20,25,30,35,40,45,50,51,52, + 5,10,15,20,25,30,35,40,45,50,51,52, + 0xf7}; + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52,5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + tuning.load(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + { + double c = (oct[(i%12)*2]*128 + oct[(i%12)*2+1] -8192)*(100.0/8192.0); + assertTrue(Math.abs(tunings[i]-(i*100 + (c))) < 0.00001); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuning.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuning.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning constructor */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewSoftTuning { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTuning tuning = new SoftTuning(); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) { + assertTrue(Math.abs(tunings[i]-i*100) < 0.00001); + } + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningByteArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningByteArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,63 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning constructor */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewSoftTuningByteArray { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // RealTime: Scale/Octave tuning in 1-byte format + int[] msg = {0xf0,0x7f,0x7f,0x08,0x08,0x03,0x7f,0x7f, + 5,10,15,20,25,30,35,40,45,50,51,52, + 0xf7}; + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + SoftTuning tuning = new SoftTuning(bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + (oct[i%12]-64))) < 0.00001); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningPatch.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningPatch.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,54 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning constructor */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewSoftTuningPatch { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + SoftTuning tuning = new SoftTuning(new Patch(8,32)); + assertEquals(tuning.getPatch().getProgram(), 32); + assertEquals(tuning.getPatch().getBank(), 8); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningPatchByteArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/sound/midi/Gervill/SoftTuning/NewSoftTuningPatchByteArray.java Fri May 30 00:00:00 2008 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @summary Test SoftTuning constructor */ + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.sampled.*; + +import com.sun.media.sound.*; + +public class NewSoftTuningPatchByteArray { + + private static void assertEquals(Object a, Object b) throws Exception + { + if(!a.equals(b)) + throw new RuntimeException("assertEquals fails!"); + } + + private static void assertTrue(boolean value) throws Exception + { + if(!value) + throw new RuntimeException("assertTrue fails!"); + } + + public static void main(String[] args) throws Exception { + // RealTime: Scale/Octave tuning in 1-byte format + int[] msg = {0xf0,0x7f,0x7f,0x08,0x08,0x03,0x7f,0x7f, + 5,10,15,20,25,30,35,40,45,50,51,52, + 0xf7}; + int[] oct = {5,10,15,20,25,30,35,40,45,50,51,52}; + byte[] bmsg = new byte[msg.length]; + for (int i = 0; i < bmsg.length; i++) + bmsg[i] = (byte)msg[i]; + SoftTuning tuning = new SoftTuning(new Patch(8,32),bmsg); + double[] tunings = tuning.getTuning(); + for (int i = 0; i < tunings.length; i++) + assertTrue(Math.abs(tunings[i]-(i*100 + (oct[i%12]-64))) < 0.00001); + assertEquals(tuning.getPatch().getProgram(), 32); + assertEquals(tuning.getPatch().getBank(), 8); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/java2d/cmm/ProfileOp/ReadProfileTest.java --- a/jdk/test/sun/java2d/cmm/ProfileOp/ReadProfileTest.java Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadProfileTest.java Fri May 30 00:00:00 2008 +0200 @@ -23,7 +23,7 @@ /** * @test - * @bug 6476665 + * @bug 6476665 6523403 * @summary Verifies reading profiles of the standard color spaces * @run main ReadProfileTest */ diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/misc/CopyMemory.java --- a/jdk/test/sun/misc/CopyMemory.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* @test - * @bug 6565543 - * @summary Minimal test for unsafe.copyMemory() and unsafe.setMemory() - */ - -import java.util.*; -import java.lang.reflect.*; -import java.nio.*; - -import sun.misc.Unsafe; - -import sun.nio.ch.DirectBuffer; - -public class CopyMemory { - - private final static int BUFFER_SIZE = 1024; - private final static int N = 16 * 1024; - - private final static int FILLER = 0x55; - private final static int FILLER2 = 0x33; - - private final static Random random = new Random(); - - private static void set(byte[] b, int ofs, int len, int value) { - for (int i = 0; i < len; i++) { - b[ofs + i] = (byte)value; - } - } - - private static void check(byte[] b, int ofs, int len, int value) { - for (int i = 0; i < len; i++) { - int r = b[ofs + i] & 0xff; - if (r != value) { - throw new RuntimeException("mismatch"); - } - } - } - - private static void set(Unsafe unsafe, long addr, int ofs, int len, int value) { - for (int i = 0; i < len; i++) { - unsafe.putByte(null, addr + ofs + i, (byte)value); - } - } - - private static void check(Unsafe unsafe, long addr, int ofs, int len, int value) { - for (int i = 0; i < len; i++) { - int r = unsafe.getByte(null, addr + ofs + i) & 0xff; - if (r != value) { - throw new RuntimeException("mismatch"); - } - } - } - - private static final List buffers = new ArrayList(); - - private static long getMemory(int n) { - ByteBuffer b = ByteBuffer.allocateDirect(n); - if (b instanceof DirectBuffer == false) { - throw new RuntimeException("Not a direct buffer"); - } - buffers.add(b); // make sure the buffer does not get GCed - return ((DirectBuffer)b).address(); - } - - private static void testSetByteArray(Unsafe unsafe) throws Exception { - System.out.println("Testing setMemory() for byte[]..."); - byte[] b = new byte[BUFFER_SIZE]; - for (int i = 0; i < N; i++) { - set(b, 0, BUFFER_SIZE, FILLER); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - unsafe.setMemory(b, Unsafe.ARRAY_BYTE_BASE_OFFSET + ofs, len, (byte)val); - check(b, 0, ofs - 1, FILLER); - check(b, ofs, len, val); - check(b, ofs + len, BUFFER_SIZE - (ofs + len), FILLER); - } - } - - private static void testSetRawMemory(Unsafe unsafe) throws Exception { - System.out.println("Testing setMemory() for raw memory..."); - long b = getMemory(BUFFER_SIZE); - for (int i = 0; i < N; i++) { - set(unsafe, b, 0, BUFFER_SIZE, FILLER); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - unsafe.setMemory(null, b + ofs, len, (byte)val); - check(unsafe, b, 0, ofs - 1, FILLER); - check(unsafe, b, ofs, len, val); - check(unsafe, b, ofs + len, BUFFER_SIZE - (ofs + len), FILLER); - } - } - - private static void testCopyByteArrayToByteArray(Unsafe unsafe) throws Exception { - System.out.println("Testing copyMemory() for byte[] to byte[]..."); - byte[] b1 = new byte[BUFFER_SIZE]; - byte[] b2 = new byte[BUFFER_SIZE]; - for (int i = 0; i < N; i++) { - set(b1, 0, BUFFER_SIZE, FILLER); - set(b2, 0, BUFFER_SIZE, FILLER2); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - set(b1, ofs, len, val); - int ofs2 = random.nextInt(BUFFER_SIZE / 2); - unsafe.copyMemory(b1, Unsafe.ARRAY_BYTE_BASE_OFFSET + ofs, - b2, Unsafe.ARRAY_BYTE_BASE_OFFSET + ofs2, len); - check(b2, 0, ofs2 - 1, FILLER2); - check(b2, ofs2, len, val); - check(b2, ofs2 + len, BUFFER_SIZE - (ofs2 + len), FILLER2); - } - } - - private static void testCopyByteArrayToRawMemory(Unsafe unsafe) throws Exception { - System.out.println("Testing copyMemory() for byte[] to raw memory..."); - byte[] b1 = new byte[BUFFER_SIZE]; - long b2 = getMemory(BUFFER_SIZE); - for (int i = 0; i < N; i++) { - set(b1, 0, BUFFER_SIZE, FILLER); - set(unsafe, b2, 0, BUFFER_SIZE, FILLER2); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - set(b1, ofs, len, val); - int ofs2 = random.nextInt(BUFFER_SIZE / 2); - unsafe.copyMemory(b1, Unsafe.ARRAY_BYTE_BASE_OFFSET + ofs, - null, b2 + ofs2, len); - check(unsafe, b2, 0, ofs2 - 1, FILLER2); - check(unsafe, b2, ofs2, len, val); - check(unsafe, b2, ofs2 + len, BUFFER_SIZE - (ofs2 + len), FILLER2); - } - } - - private static void testCopyRawMemoryToByteArray(Unsafe unsafe) throws Exception { - System.out.println("Testing copyMemory() for raw memory to byte[]..."); - long b1 = getMemory(BUFFER_SIZE); - byte[] b2 = new byte[BUFFER_SIZE]; - for (int i = 0; i < N; i++) { - set(unsafe, b1, 0, BUFFER_SIZE, FILLER); - set(b2, 0, BUFFER_SIZE, FILLER2); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - set(unsafe, b1, ofs, len, val); - int ofs2 = random.nextInt(BUFFER_SIZE / 2); - unsafe.copyMemory(null, b1 + ofs, - b2, Unsafe.ARRAY_BYTE_BASE_OFFSET + ofs2, len); - check(b2, 0, ofs2 - 1, FILLER2); - check(b2, ofs2, len, val); - check(b2, ofs2 + len, BUFFER_SIZE - (ofs2 + len), FILLER2); - } - } - - private static void testCopyRawMemoryToRawMemory(Unsafe unsafe) throws Exception { - System.out.println("Testing copyMemory() for raw memory to raw memory..."); - long b1 = getMemory(BUFFER_SIZE); - long b2 = getMemory(BUFFER_SIZE); - for (int i = 0; i < N; i++) { - set(unsafe, b1, 0, BUFFER_SIZE, FILLER); - set(unsafe, b2, 0, BUFFER_SIZE, FILLER2); - int ofs = random.nextInt(BUFFER_SIZE / 2); - int len = random.nextInt(BUFFER_SIZE / 2); - int val = random.nextInt(256); - set(unsafe, b1, ofs, len, val); - int ofs2 = random.nextInt(BUFFER_SIZE / 2); - unsafe.copyMemory(null, b1 + ofs, - null, b2 + ofs2, len); - check(unsafe, b2, 0, ofs2 - 1, FILLER2); - check(unsafe, b2, ofs2, len, val); - check(unsafe, b2, ofs2 + len, BUFFER_SIZE - (ofs2 + len), FILLER2); - } - } - - private static Unsafe getUnsafe() throws Exception { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - return (Unsafe)f.get(null); - } - - public static void main(String[] args) throws Exception { - Unsafe unsafe = getUnsafe(); - - testSetByteArray(unsafe); - testSetRawMemory(unsafe); - testCopyByteArrayToByteArray(unsafe); - testCopyByteArrayToRawMemory(unsafe); - testCopyRawMemoryToByteArray(unsafe); - testCopyRawMemoryToRawMemory(unsafe); - - System.out.println("OK"); - } - -} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/misc/Version/VersionCheck.java --- a/jdk/test/sun/misc/Version/VersionCheck.java Fri Apr 11 00:00:00 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright 2005 Sun Microsystems, Inc. All Rights Reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -/* - * @test - * @bug 6272688 - * @summary Sanity test of Version methods to make sure JDK and JVM - * both have the same major, minor, and micro version. - * Update version and build number may be different when this - * test is run. - * @author Mandy Chung - * - * @run main VersionCheck - */ - -import sun.misc.Version; - -public class VersionCheck { - public static void main(String[] argv) { - if (Version.jvmMajorVersion() != Version.jdkMajorVersion()) { - throw new RuntimeException("Mismatched jvmMajorVersion = " + - Version.jvmMajorVersion() + " jdkMajorVersion = " + - Version.jdkMajorVersion()); - } - if (Version.jvmMinorVersion() != Version.jdkMinorVersion()) { - throw new RuntimeException("Mismatched jvmMinorVersion = " + - Version.jvmMinorVersion() + " jdkMinorVersion = " + - Version.jdkMinorVersion()); - } - if (Version.jvmMicroVersion() != Version.jdkMicroVersion()) { - throw new RuntimeException("Mismatched jvmMicroVersion = " + - Version.jvmMicroVersion() + " jdkMicroVersion = " + - Version.jdkMicroVersion()); - } - - System.out.printf("JVM version is %1$d.%2$d.%3$d_%4$02d%5$s-b%6$02d\n", - Version.jvmMajorVersion(), - Version.jvmMinorVersion(), - Version.jvmMicroVersion(), - Version.jvmUpdateVersion(), - Version.jvmSpecialVersion(), - Version.jvmBuildNumber()); - System.out.printf("JDK version is %1$d.%2$d.%3$d_%4$02d%5$s-b%6$02d\n", - Version.jdkMajorVersion(), - Version.jdkMinorVersion(), - Version.jdkMicroVersion(), - Version.jdkUpdateVersion(), - Version.jdkSpecialVersion(), - Version.jdkBuildNumber()); - } -} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/net/www/http/ChunkedInputStream/test.txt --- a/jdk/test/sun/net/www/http/ChunkedInputStream/test.txt Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/net/www/http/ChunkedInputStream/test.txt Fri May 30 00:00:00 2008 +0200 @@ -1,2 +1,2 @@ -Fo`kMsMr*sth,dr2oD]eg<N\U4KGXn2VQ,&'!;AW&I["@nZQJWPG$PpAl;1AZ@R:DZ4;<,C-&1H7ZAjAq7LN`NV[,YDa^JKW_!oW6>=tA9q;%*^5$1[C24!O=7p0LB8c6EQ:bpii++fSJsNl3$mN#K[2eL#%d>c<39pV55VfO? t5a5 >+g-X9Yc=es5sI-ts)A9R5TqE?/<M.C8Zl ^n"s`BDQp*W@oVW;]I'.h/b1:4!=.W%/01LcYF7=Um1(.GNWiH:Kp?Ch12Bg[5M`,TTE5TN\pba^I;oM2Z*KqR@#RqN\;Cb99`H0d5^K*=fJ<]%Sd>i1hpA>313bbb#MCtA</sM^aXko^.Z7+VJ+(EYJgJ;j*\%5@13(Wd^;PcjC44A  I$8,VM>Eg2T*ancMc.8]W(7%'g.#VpQC!2AZ(0oW12mIhnJ-G]D;Q6OF(eon*,UL_H'UE 4Y? 1?_,2ia$K^X?R hhS3!R5BC,T>@#rs1 gF*lPf8,*cCi:nAaE%*,qP_ofK]hZ@>cQ?A;,EH7fU]GR2p25#UA$.oE5/ETshg=9Vk_;RC#<^nK?)PKL(YCWdtBChB*T>[%;/@Rq[Alea)>Ib^QrKHG2KcbE0mD&/'eS*tX&\8+U,Q#Zm_`8?%In$FLme]D% ()6TEs4q.E.\S$= 7iO_5W?K\UA2:WSgk?-p@=SQU#E/1!4.@--8IW]kLr"j;$TCUr,R,s7OlD-(o#dlEef9VK?'53Xq]/3-s!3B?ZOk&d'a*X1TRs$(?O`DTmX3mPX,>=,![AO/gEO^,W^00>Aq\)M=a3:U`AVleR6-Y[4qdj1Nl,gEDi']t&><6n0#)'Z0Ci.pZY$d1A4E?FrX9Blka%LHWMd ilA@#'i'db3# ]+Mf4VRQn6'nXg#E)I(8<5I&(lT5Y$1s.5[0tYd]IbLkgGlt%?^MHq!k!h'FP18>%"oqn+V?WXAK,6JP\KYb5jIJZAG 7F"0a'"A"g<61lB:'^;idCr*82Z>MEOCeHqH^Se6;OgKSWR]"Kji7'1:VI)AC"nA7mhWM*okf"4,G7hm:c6B&$3CM.8fIbb[kPX',j^&K6"IoHXPQgY>@E=HE0-$10tpQ mXol_g,-rmo11C4F3b8t;@JINZ.t#TT7eG.+CjQ&NN)IqI3hE6EF'h)!f6spqV,fm4`Hirb'7+pr8Y,NqR^eF_23mt@C3@MGAHm0d;3rY&+tsK(BK30:V]"gTpI=$ms8j*+qddro#A(Y64/i!F2PA3<9/WQX?l6QV^V&)m!C]F$@ 468?JD8p``2c.;]3mkp)Bl'X2PpYSi+[t<UF\X)=EGfr K?A/;Dgq)qD4.4c)7Y&PKg>Es^%2h ,)YbjfMA5:dYE'1)rb]]/j1?:Iq37N8f.>+UQ "f5qFFYloKPQ`I#0ZFLrgQ1WQ\:)L-6\$Q1UDgI!d,_#),YE90K^EY0*0saQnl48<1`(@3L%LshoA?:5Gd0,6/b0!pIibT2UW9c()EH0.+>aoE%`]e[:.A!9^rMan?\peDIlNkjaJiX-=gYcFoXXbTYD8+Sp8US^t0cBf3@I?<7&f 2%n9!]t9rF_flN_U)74!ghb.I!'D4n5dim##5j:?GPH_3Q;gB$j'qNk[H,%n6dc0aBl&>PN-X3J.[pNK 2S'oEm_dsA1&+b`$3h32%m)"QNiJIWX9%*49_)I&ARkIm:gM(Vh!$bI1iSC/;/efNr_`sWbT'>T;fNIJ<%NW0%A)]npAdI>\KaA[.G-8An8&VN6)A$o4,@31\];&k4*=*?pasKksN1=1l-ISJEY/_`=U]j[Td-9;(OFh(IHp70H!2kN/9to//b/_ar&/Xe9CmaqX:`X,S\^A+AQes./s'F:2ZMY :m H+3XS)l35Y]AicKV"G?4XERT;gD?+)S.0?,8X=414C$hD`@?3"Sc/s>A[bFPR^]CnN8ml`[pD$q%M,aSCC$b$#D!JN=;^9VLl>P$8s).J7tC!^LQ,c4dPAoU,M7NmQk=90>$=:&_J;s?Y$/#I^h_`%2K$[^S[7f=Oa21sm+aM=G89g8RD:KQ)pRKLf'/>$ciA'Lr7+X'%1D+6hDh@8G#+B:/_"EaEc)VPU$kLC32rR-?HCm_QlA2Qlf[@n^K'OC7CDEFI]`;C5.EQ$V0,V.<E#;<.J8PiYa`M$FYCP[8$3Dif8K'RSc@r@MF XRPUqE?nmRhVE4D<^[%5D(^.>V.t4OQ_mqq37`53H)8rAGPldR>'1DEec?"2IGY,ane;V7C:K/__[:&<dboAG@@WqJZ:3<^.ffSXTgT(X./0T_"B06!]fejtX+?"dGC#nSP\JUSFU'mS22bI#WAp\83A2T(Mah,S`@56_B\r2.1Q9=f(-6K6YZ#Gf\;o,  7.cIAMP_(5X2O("&7fr`;lO2!5=W,8`9`s/6N!+6+A!PJfWK\A< XSr6gdpo=eE!e1jqMR"ptea0A+i[Qf<Y ,)YtQ4qA7e+#E6pcFs\c^_-Q(Y3DN39tKGiOML4ZJ/]jY*6K("f?j]d5Q`"(!a6^EnhMXs-4(YR2'J@A!hV_VYI.'P,/ct:aiY%I5X*@<Xt!%`[GkeOtZa[( XBpK2#?$1UiL2i!?t8SDQ]UBEW@5SN:$qlSg'CJ>p4G44h[U)U*4s.C'ieWRf:.VF]R(Q.iRPRAi0HUFmR8GAtnR1D&03T):Hpn+RlJa>:[U<*83'R8Fr%W$]?l)KANM[Ttj gKAfib:.oo,D?jMTW<3DIFMR\io*NBBA$.9'8A6g#(FsamZsV[>Ml`Y&<W"Tq)i8'ROHA9<4@#a56nIM,ME'>LJ18>52+]9pLqoAIWG##HMS2`^SX$'N0dP/)7*DVh;<llE__mo^GAHFXh+,nhg[,\S`oWd!dH+iUA)Cg@qlT jQ?8()W2`0RA9_i Y;!EBdA$_[IX'ERYmL[MkeMnHN0 R"8Nhn7>%)Hh\ e7F@VP61nAQm%^$@;fs\@mrNC5=Or32)c[O6G3#OrFN>k;m0oPe/]0!.i=5Qp+Is@bJ<-cLh_.Ia91f6M+7l;+\mH7V$Ai"4mAp-#Y(jDKCL:4Vr!h#k8R"*n88`WB?N)/o9KG\8A]PmSnj,=q=h!%(X+*%Z_/ApSK0`.L;*%@G22NlmG='pP%,JBl$WZ:AS)rlaK/^(J+B^6fW*E C37[ae^A]L@g$;/Ho)o)1:W6q>GbC42!!oDY5#cMQmK3-<)(m#=s%&K37[:CU-hm->V"/AM\ 2BfkNtlILl`fPWRG^+d_9rcNQFckrMM.!3jP2V<b(:QZiAo6XdK KD5-f95M&=Y$'1hV=]F?b6E"^W.I2<7kgnUQlj;YQ'W8NFe?Pc%[Z^BEnel*gUJ:gp`7lGRfg5_YboSY$].O r)#c8_"RFR#WEt(dQCYF8h;ngfPe^Ero9^bWGha"p"J]+f.<>A`G s^Xs9s%I&aF3k(BC@WZ"J9-425-K3884cC_#0Z2 >%o&UIrn.]!F8I#*Th=17cHo>^;_8dB:>NMm'XX<sZM8$3UsY(sJ-An`L0_.!/GhED.&$37=>@beT#@YdX3DFir7"Q'tVgC2$3="Ke9<0Z/i"]":tD-/nfkbdT_X/f)ka]=.l!c?IXTW,9!34IK/'*,/.8OA`8aoXCBI)SGDZdi3b?a`%bI;nNAAfg5KXSC8NdCa(!E:T*fIo2V)8Q;j q<42ACAa.4[Y@<OX&G&JJ[bW[3;Akj&&e!.;;=)abrA2*`5TQlbpi!?P,f_eV#Tt G!rd bi-Rf'-p%U@V7Q\/I?J+mR0m/p6VW4g26;7BUGfQscTe-Af]R9Z!B&f@3T2^G+NfGDgHPP!J,Qi5oCC\$B@I3Eg/6D3&MOfs$K9V),ESse*!h_BL_h-mA_19@P&s3i_0iHT+8#"? A)te`srfDN:Qjr =9Q5@m&S8U*eG`k+UC@Op]SVZp7bRqca5TaQ@_g,K"O>Mk8Tkh6K%[TeG=k1P'^k4`43Kp'N+A3+'>e M>-a!M@QEPf>BY.M^D#@!8RAn&" lZp*=gJD#>l.44)c8kJ0EjKn@q4]@Y"mKH\t@=Q!ISeN@[A=q`kl;K32M1r$LV+mb_ni\;IE,6>d$t)B ABH]7&-OK7"('Usf4U>;ZrgSANg+q7P8tFk0)r%3<-aN*%`ZUL-142$\*VD79cs,gWm0n+DS7bcA,c14[CZQn]kb/-$nM,K;F";E%4X[R#GGdpX"!h`j=A9_%pt4mZ]LJoOMh#$*nX57JktJ5HI?#ne/qIMd:?F9:q*_UG%ILCdH>fQ\f#>Y7OP(+"C'HD9a&F`'6ir+QkiB`,/EAT'IaBH$'gIAGL>;RtSL"1gO>XeX.L 1SZ+A]31S4W9T>4EJSpPk<4#("#CaOV>>iGftc7?5[?(T^qc:kl2I'#.t^6,`H4W!DfMI9oGt$p0>5f.Z>JO`^Be%q=/\eg]7MaOY:2_,]-,b!A;;_OR A5P.n%Z7YLIe^)1_$N$?&>oA6$59qS8"@VbD8bV:ON"!]`jC@4n:6eDT)3E=(orMJr+U/U-E%h*J> ]QinJS"Z`-9QP2rBF?g#8m PlBDJg^)p'Y4bRk OZ\`0<"p0#`FqLDRa_Md",AR>_7tqgAI6q>F\ rUP2h6P5Lf!WmaGeslT$$:km:"^b98>B@[58%Vk8o[4,3`i-j`:lG Jp3Z@RD+o"K;Oo`cgPBOm:XS[SO/hl\%V"K%rXTaOdA?!`KL0[jil< IE9'PaXf@/tA#eT'SBZ]es'ljk^/f?i^b`k`CeqsgEah1N^_qKFOQ:V,nH;?rWTWAh8@J)AJ-fdM.Ub'>9`Ht>[4A\. HEF2YA9)_X3L^H[B`)dO UYDPi]b&C`-AD`ettad@A#nG>L4c\Wcp"a%d1Bt4"atAn_#%3>VCJq$l$>O^!?$WB17E,NMQI9hqOM,Kl#0QC)5_M%B2E"K7Dt9XK[s@_HW( Xp8-1+,k\hs [i?3?4XCQ9R@I1c,D4?]8FU17BbSEg^J]H'(3&Hist50)n$_k1ZX=$.[:O6R_rL`V#&"GPi(Zk4\Tk?UAZ@,gt)S#c&n/KSYnFGZjs^cACm;+eP6F^)MAGhoqV4`@1%UMmfNba+"& 0sY!5$N>XYCnoO9^FI6'Y >U,i^S$3>sW3#itq3RnU@rgE1^8\UTrjTcUHbl$CFC%)UY[P:8'M'a6^1O4Y!kgi@n8:%j^P-cslBH*r,-Q"Psn4bKbHHAUVLl%F_fB\P<sD$^O&VU,5Xf';b#cibEC64s c(Wl+T+UE&N,[r6Z`Nk>h*jme`BI1EhITO9_gA%]A"i<37)\jY=sD8sYN^9XFA/Ml<+seGea<.6D^$UC[=X-4`tk@fIXG]%M_h:kVC\&C#1j,`E;2[CP_;_,SHb+MHJ][=@?Z\J[!ciZMSC=8T_P^+7+4 #0aMJB#M7+J9Y(TrprMRVhqp%6n6ph[#A1N=8i>Md4<b+GoT'>mPMB$b#AdB5bdamqKn6.so 1O2dscP,`V1#sAjYn-$).Ao3moshGH`Y^-a>1T?/^VeV aR(MfbU*_)lDiE%8OlO?pr$ZfBJj5#^-GX'h(lCVdm<9)q".PI$+*5j!p_'3#>\Il_VpFG6Zjia`Dtp+IWhr@EH#]l0o\`js?_);^=90%PE(m]hA-Vm/r)\W9ENd*Edn+NM,G^,U/n;tA^+RQIGfiB9s5o6`RjM[ALmTXqNm@Z:O<6NTbU`)NOr.a:gm^b_XYn-Va0`;P? RCFlYsq/5Pr%$G?r^AZAE&/d*X7AYM\AC,Mes7G -Hb0B\BfX6kcUaJ_5[W1+lp6<;T$WU=C&\hg6A^NeR%bIWE6ZjlN\:k&Kb+<V9boOA3We'Pp+PkF'h5^NrL(PC&SIg%Y$%fDpJA1Ol[+q!_>B7A6N4>?q&C-pLlqE@c)j/Ml\i'J'\/N4((UnMeLVG-?rc?_4]>TAn6!eU_:tUA?OYrAJ[:n>nrn>tOl]L,L3tb%q1"TKD_Ggo :+r<+/L<-QrHM<=)i1La%Yj*#]#`akcXI$cXUbL:=!nNd4$]flE;,Y4(i51saE!5.n97EkgA`IQUb$1s_<[*SpA1j/,IYK=$^.'*J;^U1Aa:r\*[5'BfPm5i\R:Y5N7XT*fJ;m"f<-*_ ePoqPlR7d4nX0[ZP'7CSd8!faj)#/6e[R+!^]L[R:N:TNV!(Kr]OV]a`% 'I-L hGX.orUtGE^39%Nio,O9MZ;+bHD?BJDBPVAk'SV%5rFKf"?[RX`W\t+Dp$)0NZ_IgY*9I"+GSj3NL[k%HI-fm9A]*9\;\>CTdiC02j0G04t_2C)XN&a6!NCi&_[W*E+K*."oe6R:Oj2/4rU6PtGm9X]s>ho)^1<44a0AT%ELqE/-UKgS#AB$kVBmie4$1Y`0JHGlRa#Xc:]60EN9KE:of(H;ElD[-b]C6hOqKdd#&8/Ct2<^WG->k1N._J]6)TUC2mWRXrPD"Y8'_,rqThCrN+A_oEMMkM5-rY2:3Xl1 @J)D=WVEo)paNT7\MYaD^:\WF6(/m:-oEQ98:]mn#U2rTqm7W07fcC6V&pFWgZ!A^-Ri>AAY?!!sY[:h8OB'o6t?3_]rM4^IfRmA$'mPB<X2,@j62V_BkPrr/6H*4NiF23S%(,EO!Q %$RLjP5X& dHpAUB h>9RjB34sA:CJ(R;lN6,kj1<ao`E3p[LNKFk4a!+V_Rh;;O>&;)P/*^g?AAiJ`@*k?1A%p<4%9L2R:C!fReCA[f#T1C6sYjI_D/H`IV@*N6LX'`m>\qeb %'3.)%;s#s!6/B#8dd`5di,iDPHo7MQ$AV=J+V0:(\<8fZa%E@Z7)"ZlWG4;b.0*S,<"K9#CihF83rBU(&mA&5EDV,'WJ=3NXeAW3@.j2/:!+an"I%3q(9(kqZgY9h]q,VK&![P9;J=D07JI_\6+/:21[RBq#4%?Fci'2V,<%6krSb@]jEo:YMGB7P87$W;76_U"nHlgO2 o>'[KdHeIl+n@'5[+Bd.^:\Jt&\Ap\RO2Fn5C&`omaZk:sGJj&_SIO0P-Cd;G3#j(I.Z=NCqc 2%(:[0hN1FV89i'a+ed49r,f\kNa@_KE*@ZZP\GFNRNQ;"+ghd]$LgM%3U05!U-$#I2.6 GM.Cq7P&WDYj$qd`V_755b9$K7,9(Sf=6>@J9pbr+RAf>A74AV_E>Fg]^+-0UtQi_m3+rkfFFEr'<%iHE/4B7N'sRWoRIc*U_qfZ(pFqp,^'0-ja;tcTHL5:+gJPb_qrZl.X(/0TeXTVZ"4AR/'lPAsqA<$@Ej%/0XV$:][.2mhWZ]lgQ?eD8q:t>_himc#`.>6[$mMSG)7CZBZ\e!QI7U=HDoP,3)B5C7Ulm`8l&?97]9bV$) c*11'-:+% f_[-8hncgs>Na[J (jUgspZ80?Ia_'AV;n/VQ0I`\QC$>`:PG6t >1!Z%s\a(FNgB;;HbsFWlOV93M8[Ut%f/AT2]4a@fo=&HiQ$Kkle-FYl a@C8F)*S;lU"VkdR9\LfU/TT!@.L'+ZhI,!?G3A!#@-h)^!B?)c>:O8cA4gUgeE#kH'\>E:`Rn#i!@2,*)H+HVeRB,cATD8U;RsNOXr*M;O+NTMJGe6$J,BI9'cg'=ei>U`gN41oN#SSV`o[8aOLPjsb0pL^G#MnmAgsb=(`-0T)4mP2A43]F!Uh\hA*V6 9#@Za_'IE2Ai;qk$JQY5>o;L)\]:h7Z)^G7#b'r-KqtTi'dWAC^g,"^i)abIli*HV@7rW#;[H.^HAVDU0)J:8sn2XK+LR._$[Vr,4Eb/7LT^MBL3gcWI7E?sZRn0YPA.\N%UqZT"H:5"Ha +4&mLinhZ%SHpLCjG@EpaTt]I+&VgLL6s%+epH56Rq<iMh6LE_Js\!*V6EAJ4"tQerAf'c/]icOeFc]>qJahlBP61.6Zn1e:I5 r78,#,F /3<;SFor=OJLpMlGrc$]/91SAq6(c[(Fle]DE#!/r\CdaCl)$0R$4B-4bm4dX ]0#T,5#9#(`J,Aj?&_%EcpA7_aQJCpFA*F[0r;.q*f0>3$$!_'tRVnR?Q$Q"0XT9?Tq+c_9!_^8eph%AR25K>)6T%F01e/>&b2f]l+nAgmQg8kHb psX3`)5MpE1O.Q!"DT'`;7A-tWqW@P20f$$T/a>PebHtn1!qZT'&JHqr[&'* =52"&7dpe?g.$o%-kKF7q,O0.i?lc698?&86,"NdI3_=M]nkAfAt(7"*tEfQ=-K#II_0q:N.0:K]80%4=JdT[F0n":o%VE& 7;;]E)'rAS_Nc-$P\NppVegCjTY>\lcF!%a:rq;9ndd'A:RY&IhG`p5>>Hj^/Wpn)7-f6$8A)=>0+* 7$4o63)&!i-YA,0;t\MkD(AgZah_<[k0o"0]af<(rDd%XfeBU#W/^QS!LTO[PV+8,jY_N*bApB[$!`-QWWA#H->hAJRlr$UQN(hAmmN\m!Y3R?nY'"`Rr4e))Ys@rQ6(FW9+m(8<6%1roR(^ERjQ>Aoab3a1MR=_]O/h4Irsl=W5+T3ZFSn`X0+r#O*iHD?bGj?I7m8IpjrFoa5J\97IJE66Ob[-4N_o,d-KP#PmqB;G=fXB8#]1AL7.HQoXm-[$A\\CQb)f*TfEH1Q()dJ?f&qZlmRo;a%-LnqtW3e&5PgT5d;Has=F2_VI@'FrHm,WN?2 *"=U `K'P$PchrWcdt L92Kj4;kTH=#?H"cf<@iiXjA_QN^rj4qLV";XPD9j:bV01]`34N1\%DX/Ff@#XBI/Lo#c QCoJ\IZ$g(1KG2#(:XDi8A.P"d,A_68DjmdT!hT<G[=Z0H@%j]'jQbkp"q)+)g_:[AYDW,K'LPY:rM4t>.V&m?$9OAM3$5kn+,%0o>W\pIXT`^5!6<K>k%@p]Ybdg-7nI"A9V]]2SWb!JA!k)D#W8R2B'ALHClX$++inHhl,8AXH!U j.7%W"Z6tNSf7STULk#,b=c2Y`\M8=j>!LA\i$qn8!`$El*4qXlSbfb3!aDY?2R%[1R5Ah"'$$j?8pp1qtA'Jl$%CW/KX#QcL%9a)['lmKB/(.BG]:TpH6$]M$P3\E,H=El.).V_g'G(SKG/>Z +7Sg  PKXjE]t+.WS^o8?G+9(9o@9@1c?LgS<$&?)tbb^'g(er+C2@fq_->mnAkE5cCn*<>AI/KAoGo>9TcH+h`Wd? FbbjTld6Hm+oYiT&XBq+Tb/Yf9BTIB^Ch`AZldmX'?0WT. @VSl&XcW:#(FW^.IAG(a&UF98DfaUc5>!o9$?$41o7OMdQN 'CCF=3n9,H-GV1:C2fre*/DfeAAgS<E.bQ^&4b7:#ChiO0/(Hq\S%DaH#T+7lYsIUS\"[Q60MRkTZpC29Uam&%?)2LniR"^$@&4Hta5=hQXj*M_EC.4DGJ0,V:>Cp#^OM0Us`WMg\KO4)#5VeCjJY-3Nn8Z+dM8HLr;&bU#`l<.J:+WdI9TALi7"Z.An&t-&SVX`XOY)D:7Cd+Ddfr!Y-0&jr9ie)OCg-)sqid!Q,>ghj*.<4]]ft=rY!g>i%M`] kX-bg;:*`c :*FpCB="6Cp?Ksn1E-$6*nP"]JM1==QSeI5@A"1AJ/Z_F%\AC')E3ZqSM3L2.IfClYbSGOb?aeeqJU!UH_2PI2IVoJ6q7pYVa71dJ%G/foptEZbhC#'i^4tPXI0= KDT Y-TRaHabpCCf="Bi`+t-V#dP>j"+FJN/KL',;Gpj3Q5Vfn6i?8El?H4p'?A"h)A'K%Sm^r%a7-\YgE9pLcSV!=?p%(7TIdC,UJ?]b+L0LJ3PEHeXZTr].8CR?b;,t4!C'>Z&UEGNT$PlIQW6DSsF;WeM2&o=mUA>cAhf-i$qW*KB I)9.1Ae%^ICbAe2h7.Z]$UQ!@G,pCLD1J>:A#U>hg/fathk5@GnFm"/:HW)V\+\*c)m2Jk8DoKPOBc7]fSih46G/\rq0&rm#,G3J;E-*rDh sS= *C%f.NATZooQ.modqS#(%dHm;?a4d&b!XWgOmKTf"q9I -2%%q,8R4,J#$5gBfZTYMm,tq2SA+ifSo/r[#P]T^7eX0(.?F6`%@`NXKL=PX\?XR7=GQRsCYK 0Q\S/ZOS`W`[9W)X7V_(iTHfR:`>AF:g>b LA3A@>8dj3,0ned.C9%JHBg&lDPd9#)n\@9&p)jY]=s!9 :qp)mJ3#7,;-Nm`e9lY@:m]"The#>be)i8Ahq]g 7#C_o&cdPH13j;Sp$)0sqL`Z.WA8[L%sSPF@E-(\S\9Y(fRCOm4p#A+/.-O(a11A$tQm_(R)NjCW(2f_' ofHL0$??.r'tB.`X]ZTY-740RoY&iN5STW5I Y>I!rPHtYX"Y/ ]m]QInX!&K`NQRU)A>OG5&En."WC4<;4;\=BB.gia@?>Y0'ASF+mY*2#Lb[9B#JZ%RhJ<>fc!Ae*daYAO6gYGjGl-!/h69M)#jlf86;rhHb)i)DV\@*_9T:__^KQ^l @<85s9 M6]?eA!#Cps.,Y$ e-f$32>G2bhqZA!B1LIA6@arX(5L&:e!eg0X=_bWcP-%",09!bEk^C&Y!irAW36XKqV6/MbI)Ak![%,TPZ/AKX0]*\WPq";OP*pa)Ki!,)$\1N-X$@M$b!8<;O`$8OZh_`N0mh_cs1/7&k3=["]tI-OGV.oYk Y2+.riBdRQ7k\d8GFpG/PVm.]tlq>RU!J_h'fVdeSAbW[^.iXN!f#;cO[m]U9NstB?Y`+Ab(IDE;'P.!Z\N@8!HZ>d>(@m"p(lS4/XIEKNZ5h:\YL>SWGK#]2OP.q;][.s$84/9FJeN')"(&q42g3SKpVUbifkn,mpIT- @XaW8j?_3AJT:Voh==X>+ ?1)iFM(aWV4]1_hI,\Slc#pWkThsicBRV[AhADB9KKPUJ`KL$eSSPC/['K8(hb?AE3^sJ7;;oEH6A8j$#1`AQXq]ps9,Ap08AYc/MO]IfN[.]7tD;U%6lh8;XH`s+'p4diRJ%oF_4b)cOH8 /J=sS"0kOl)4^H.]mP3:cCoJ8V1hl+)+2d7W Dt$0'FNfB&5PlW9$M]DJE_D:(;N(?$o&d,qGsnX ;1dOdm0c.Rl^Ct/GiDTs&^SYV.PW$"J@8 b,>I-<Gm&@`:[p6h-V:)e7A-96;h8:[364n4pA5C8I3WTj%5k)'[,&4>:#.aEXL8niGh;KrT F$=M/DjA'3s5/9@r1hqn@+HYf""RWe9Afnlh*\tg\T$X6dE9C#q[\0\:dFf4!-]NS4`VIJhs6-=6e2lT5cCT"24i5G$]2n^Bb$3$,R6:ZKjn@n.A;.MEscbH4 DdA?j8O`!mM#7p (Mb(4\qBrt!VG>>(BIRK#@Z:0AcaHk=6AL-/"R+&S!c-BagoA8,om0\!GWbeO<.R":,J>2aU0%PFdYd004$69J5;\tLU!5Ym$k)$!cm%OR%btd4g`bla;Q&(f`X3:4DeNTAmo=m*:p1]Al3O5H8,'4G6c-h3;7n>Fq/)Q'@lk!K[k0:eKGq8'^Hbjj*^%?XnWb)/soo."AmJq]dI[KZDV&75oA*F:"*VWY1d`DAUtYXFESlLQ:A9c_qNT^NYs.-:rZkgJ".PD:)-#CMDPjY3^/mi\s+r67s[c@V=;W6e*^PJO9`@2fPXRojZ9Z%1+:OLf?fGi)YF]!H %Bcbh!X*+F!)/)#Eg+Z;c*f^&2;tm2;slJSP2a+& \W;9)_LH`"+S$tAU MQ+dCr^ $1(AY!.b-2ce%n.dInA;#Vipko"dmU?'\qoV[ngS)K[\IhNC`)f:On)g3&qdb!?cQ&r,.UoSd%9KA8O!L([*H.!:j;cE7V65ae>>K)=('.65D3G;+]qYa4Nd;5l+PW ACE1@pAZ!9fj`ksP&cNdARrG dHjaQ5oVOYpEt>,V3SV /T)`t (A(e3UG*B:$*U%1qF'.Y&@4m;$i R!&GXLANqSP^N1$/D5SG9AP@nCAr=gHZ8G\FWrDbm\'IM:n4b!oXSa#UmqGQ(=UD*99GH#2FAcmitH0)]lAfKB;T<fbN'_q=TPt.AbP]s=6gRTsAZ#aJ&+`[3'.,nkmM(M)>S5Q$tR],lh]mC$AP;D@ULc0jXAAT>pBH_EDkoO7H2_oUJ!P@01V94VqMXTS"fUAS.Vq8W7*8jMn9>mJBQE0?C@1KW>E7_AGr\BQ+q/kpCe2B@)'1.3pE0P9NbKC$`5X^'*+[69n.gQDdk!6N`c(r5CV8O[#$Yh Ur$&Z?,6iif)l0lTtGi%Iq;+L3_U>Y#*78dKr,BH6An2gR5bcap^l)Y3!c&>n<VT:7o<)r>.ee4 aE5AcSdA>MPOSQK\#=r&1"0_S^@0*e--@bKC&1Nc"P;&2Z:GGifAL6]:t%t"Y$9O#GW]?-?>OCNKs A@-ekH0m`@*!+J>,/WJ9]kt5tQC6j+V'VG<.77h*g&)+G9nKA#5TAW\ti)&M3$k/7W?A%\=P*&&L]kY&rKk!kjTUl,N6R7-cPUHak5odkeHZH9A3V/]e/;fYF-<pP^Vka]?L%Wt!> 'JSsn/16VA/c,(-q T)"`=2JkBj^:aT8sTp_+2o%N:b%QTZ\gnq"t4D_1B<2AXOUM;O4*Ak@I\ENSP'eanE/Y^fL4TOAcV4an>(*-1fPMHG=)$j4j8tKb`59DFSA+QR?.;n<(j:3sr33Q-o]b5;j^l<-Ua&+5%1?7smY;jbUM/7"Zf70BdK@GnRNi%\2A+%S1J/`?(NH8JFjLeJ Z9$Mq986!Pn6H8E=Eg=k)e]>^Ad=?#rpK+J^5QQsb)oT1ch=rtJrj.c+XK;Mk_e_dc ^YG[aWPCZd!n,D+1F=_O\K:LU3"G'rFViOQO`B+PP`%XRnoQg9V:YCrJjl'rh5"HeFCLg:B.Ic7r:&F($UKC>8#C"lGT*p!A\3'_A*'.InVC1n8Z@F<O&B45YQ%bA*n<&r7.WlfF@>O;Iq7_7tWk:q")I#=4mK(56h45X,q,9s.lG#mPRAAfs2l/8MBX_na39RX1B$7LKc'&?bV/'g' k_D5I67WP!W/a'l%;ZWeAH"f7AQ;OA"^*oPXQ%;8;iU46BOD>lJO;8k,[Z1W`N'Bk^0Q_7P<#K%b*cpHlEFaJMNaHL>>J(p@9OVAOb8]Djdf+69iccX jG1Q9kqd*.,"lmC3"mYNY35[,2A=oIg#`S8OJ#be %49a81hN,bj1J-ZB9MYg,p*,1gKDe=>lr'+(fb:U#_eKBV(:H8\eY-Zs4bW5CLo:PZ]&V ]tV5`';2A@r:h;k(62p]F.ga5.r%EH)=f=AlBO-d;9*;n-=Ztn1@/-,7Nm%3t"^-?+sTCNYq)pZ[R#%BRe&5EM98USIRnH]R,Ij[aJ5#GcDL1P2'U%1U4B-0pLMZ:],^f*a)tYI6->6F]]rp*Fi! h2_=EaBn5D)(F?1amaLA4)UZ)\;;4B8F8PAa#XA\=$>RK>aPcH's.cHKk9o9Yc*7CO;(m<DreX]hQ>1f5^ZpkRf`5#?(],]V@j"JEi_U&+ec^F9L+o6S`$P;g':4%8ZIGG_$22bNQ589\KG%;CdqrRWd"f"GcNj&-$QNs2'2=j6AojYZakT>_KbC4HIT4.^o=ES8*5JZ1<(!\Fs8!r;!:!@U[/oA*I:AeFUE.UE$^[dbN6./B(o+&Khj";/-h7U]"6pb4W:3Gd^'+82&iV6L$oar/'MR?Wo,W"@YY&)#&_<%eETG(I??e'7cRH$>%H&b/BCF"pt+97)2YnSV3Mc#`m#smn^Y9jpKoO=e9j+fnJ+/V]Fq?:kpU(tq8hX\Zl2#ppK'X.Xa2UdC95c)8D?q!AQmHL.qh+?a.PN;ZHUmo&jm]dEnA] fin@9St "5i+L-4s,$sW Kt^;[K.q2QQO`?!m\?:*]-j;5\Te*TYd[R*#XE?R%JJRX*gELE/ZOMoP'"i-U[8We5H5qOj30C-lI1\#MAo36hPt.caONtgNM,:8aFnFomY<fHcg[Hl8P AV!IbYROa,4^dDX__$F5)S)b2e+73K [4#q_+mrX?'YC]N2RB0U(S&QQ hOgA,AZ0`qb3V'n35LNK?FZT]%o7_G4B)+dH!WFj;?`(OA0p<tr_D)-h+-XQ:Q9,UH[4R3M Xc7#T:Fe&#h<:H23V*WWo046t0IM*G9$@%ALWR2C?ADqS3e>4(g]IO/H0$Sc3nH@nd0n)lG;+$%`nilmb*S[gZE0_`Rm/T>RR%">8C$4 be`Y$@Bj$^Sdf4OY_N+C;K8]fi!4g3cF<58F-dat-XT:DkVSopo4.^ZhsjV/eX7AEPS2FVgB$'&Xh=VSM$Ik07PPW6ZO':)3Uf7)dOK8jh_f3?H(Jr=J.LgWnT1_eA=M1e,6f!4%<&&A2&DON;?=N_kWlt\Kag$9 26W#;7 crF(` K+M`V"PfX,K%Ul_d@0i!KWfX*OGp4i=EUbSAqBrLALs%[A.^,l0Al?QEaj(amk)]FBXCiYK--?0U(pfC?q!+_=@mSLkXrK'J*gge)^B-a6n'9Hs)75QM5+cQ_[B^[je,\&h0,L2:n3+V:eA6RKlQnAh^: #7oU(C74=K*?8a@iMN 6)?Y2imWkj)jL3t=2lo%-A%Gmm6AGXq_4!Ebb6`hLDF-N:dPU-j=o@5]'ibipCDlZg8,*CGk`A71c00>eW@`lpcN++U?e,n3\;Y#a($_>;^HrjD$XkV&[F,SB1n7gSqmnJZ[Id1g^sl*\E]lIB^ROG<^fcY4L[M^]n*O[R3GnNg9P/XAAM=16F,A^VM3/HLLO3#gZ!31(_R8kt:X2EhY\#6)+[`Q$B#C"A7-qpb/JiZ$eMFkn^MD ,TL4B?tXT&-c,/po271,` L:QjqT/q!K'EqA 6n#[#UY9n`TOWqC)=[A!8`QY#;#:fLP\"n+9hd&@S8&98>gA1=@,sIE$B1.F\m[c2-092XJD<`_R109#40(RH4j$j'(^%l%LaG[tiNdNZd*L1\p&tAXEZ$g?Z02SLek*3eor_IN&2ML+)kQAg3r8Y'\^UIW-h=C1`3]Rm:6]k..&0H*fa8l.nU@9a"kZS0BW6]KU9Y(_gF#p kT*6NY\(LoI+>=7e":1nOl4V"$!IZZY,B8hj6fhZ7>HA^rt'%q(_IeAAN#$#"8MFmA2qMckc cP)2Nn9;YF3LqeBr;(\kgkAfI0eR*@.h`&A+`ESKeNB"7q;S,6E/B'U'\'1FYW[5,sBM+KgV1A\l(q.oU7(!F0!T:g&.X(<$bD-DS]3Cr[2U?^/0_g%5=6=#cQt:]hj1O7-*[drWco:"b>R!sa"'8k_dU;QMV?:lSAcFDAaK\bO':MoAp_lAh`-" EqBL/@I)1Q -:'/=tR0A#;9N?(II?^7"Wr8-.@_*/KdAbk=Kb?6/5k /l5J:::)1cNJBbV/bC%Gf<"1r>kprV$Fat17n#07s,X$5"q5'M'%q%f6Y%r'\tr>+\UpOrS;&:N*0&?rVlQp*q:9LhNVteW"%&_0nP]CVWeWYb[mIOkkDfKdF9END]C>(/EUcC3'KtX3)- l^9"AmN>%a7htW0sKW>ko+-1p0A2NPU8ZpPV[sI'QOYe4+[F%aIY!jA `E?h[:=BrTgJ4p^1d7sAitnEHsfm)?\MJ1WA/Zim*4V-B3o'kMrct@h.>*OB-/7YG=)EW.tj!CpSYMa>CdEqFI@`1G#apQ/J4LV_VFO/PS]ZRV;s84(hSM.n8(`6LX.,jiGkF5,*UkI$H> /@ArY_7EOm)/2;6=EjTI&*#\e'#*2*>k.3T'0C*o0^#OHh[&"W6Eo2A]5GB6S,?"m$ER:Pi?aY4pH?Z; A,m!K+sF/-oB >-Xh?WQ'TI)L'mBJWWF>%mY!F&X8ZZ0)q2UfsSqZ[X:d0[4EWb!S7I(,FN3F)LdFX^3:`EhCO=U9>5.6\R;PF;)`^3M4EI/A b]Re\,*TD!C[T"iYIj^+l.tUG<0&ID.JdLFEF,lrZogh-JT-;a?2`HS7"eQ+Ng&icHUr[3kn'?nNUVD /b@7[cRe(U6BA?jmq>ToSn @6G03!ngRd&*ZKo'Ue,Ll)_2'- h1 98UTlo@LX@i7hgRUb\trHlfc\epd$Dd'=6=tm#:U]S;d(`ABONL L6q,6lVID;;TVbZb3oT?#!cjhA#S9'J =Iie<3KV%eXg9ST cf%hT!aZIG74l-^bP>18WA:NRE,1VQ>8n_d`II+&4Ume@SeS Q`+>dmTNhhU+8=+gc/Unj=\LBal9)>-cT7]Nh_,!'&2Oa;O_!p:NEnWnKsUke-I@`1=nB)N>[)qs_)>E2r3B@c%N0R7PVUEf['eeAnFZtesX'+o>$5Y<"i?6&_Fj*iY\Rr]5)>7/E\e?mp^dUAn]C3?#T'`oEe&3R5g7t[U21bj#^2t?>HAVAb)D]gf2B,esZ"shAWS=WN)5P.p+TZGN3\KAkAmHN2DbS[V@R1fS`Ti50@R0>UdFAK1)Zi*-J0D7j"/FE0RKgkB;0iln2Vh\<@,l5r]`W?D2+"Bt/6X 0L>3\066f+6tYoOA`?=e&r+4_C(F?pZZ_h]2V0&2bBhp(=3Q,]EGTePc&Co;lFKHts'mB>=OgZJ5rFRoEQ6$W?]j$BT@RHgO*82+a[@NRqTPYs:Ks+^NG+2"2jF(5!\ kq?M9_GhBC&']rj'Qj)AhgNs#OnOQBXPO!o0&=nZ!i%DX?:cOY,2Y8#2IALK1>:R^N+o6hfqpU f[O%m6lQ%_I0=>bgAG'%\7(4Tm+LtH]Q(f[KYjRnf`W0-B'*LL- s90UE*\Ks5< =BWFKc485lcUBk(R%gULHnT^KAPiWSR6 ?35O?dmV- ]mH45?&LV=EsoB]%)!*$'edIP"HG+V/A::SkJdA1k+@K%D:IB_ENml)0&r$NS`[IdK@Tg>Jq5]_0*/Q-KIb IWTFA!SDl%\-:M7ni6Aj9j[^!L?`ZS^T47j`e`*lc!hK=rb;UG! #CL$5c(3iTti:(pCpR34`];*shFF]-d>MAn59AF1a_E2>SbWX_0to6Q'":44aKk4,_OWN'WE+p9GES&eVmA!ZAWe;*qsL/ l"?l1kg2d9<5jgb5\#OmVf3WH4:$$ad*b>=G)U/n7dEeC([U<@`qL2iOVk(Dib2-K:K?Y*r+^A^,72qI)JQ>.VE SfW`"Qrg1`cJ!oAKC>O @CpG-A0t@M*]8=":inR=\NnGXpC1+]3lQO]i?5P-WsB0t^VOrZ8kQAhM+-/3'N7[h^&Rg#A%K\^9XV4Rl gZWEKgPEG;$^iRChYtWGPlp<8#\6OVm7h`lDL-V11E[4QN:,kH"\o(<)7`=*@tKW]66kb^#jiLt*/%]!)A1(Vt]%e;K0FREkVrC,XQJA'Foj:?I&Zb>^Z+4D4"A9)%`=J nAEL+q\'\F$kAP627_qJekh$gb:_FDj/*fM#1<(;qNmOX/:T&7B?EMGQ@QAs.O*o2ld' jcoHpC:/'!;`CX*#, 0M[`0HB[A5#]4&jDdoo' tf6e",o(9HXr,bVrfLCL0Aa.bjVFXVF5P>b%R(lpHU*'3XDQQWq-8MECG"t"'dj!OM[_N,FfE40OCHd6Z!'M&6f!PZ0t+@\2#)&%Pk45Vf#O#be?9I.6DkcS%rV/\^Te((c*l7+cDmMaFCFhGD$Lh\ID5;V0a7iRqdV)<],d-e>q<E[ (Zg7.D!\4EJ4[U(b@(AhmE`_OS9G&&pdj" q3PHR$me3_LRA`G[9poS)*7?L"2_qe3HXV^[%rTArKEAa:S-aOS](?hsJW_/7R\[+%;pe*kZC<@(q`<8!`&7#4.OoJfbpo3ig@50+m*eR53JRhqrU=H3GH@^KM2%<`pA;<7dUD]9FE$tYmlj:4&)lWpjoXje\L;nHsWBi%7Z8@%W2M>]WatN3e&Ya$P?d1_j+a6i$FGQe [Ho%f;j#Qt=QGoBobQN?lP1[f>fL:)H^SC9A[ ;\(Q=WAm6cp29%SZhY@(8TsDkq=l3_I,h(g?%q73K`h6-55Nigo3:!<3c4d]&(M/RC4(eIiBKW,oI1d4!(<;B >+HZ0)e.bs' II6_7LN#)q0a(AMn+>q59C$8oU0La]iI)[H9,gNXL4&:BUAfcT@[h'dlY4tBR90i9=:_bb?\QZ673eo0Ea?JZDAFnHn/UH6]C0 /t-;)e78-B$@6G%OBSL1a.\&FQb-+OUZWrW&1ecmcSTKW#ZdeT1+ApR'5DMSQ, 9Am& )+ e<2W.Wa?CO"X_l"lQ/Q<*[.hDltZ^6JjC[PiL2814O$?j/QC&AnOGmtW_ b]KA( 9LO*7FOICC/7dr)pPH!B?r[;`^d[\V2,^08jK/C[M3k,V78XZ@LoJf\HmZAko6>rTepb]iPgEQ!;4.c$ClmhP9 1T=6&0GBA*(Un49P<=BR:p2#p&bO!H74&n`98`_,VkA6]t dGYqeN"grDXBFk;-"dNOARN[5-%).(_NSa/RE::QKJnZG%f"PP=6#l'D'I48qT\;))GTV2K1E51o"_6-RH;:$cTB5"48AR<+U*>A7N?5J+iEFl=h2p+f6]h.fH!E0CtSO7t;SK_/h/-^ndjRX4$rfi7Onn#B$CE="L=nLG[]3HB=/ph65]@7dB7P#"MTBSV[P-60h'#NLG=klt'MR8q=d)fN])[O_`Ia-7BMX%eFAkcF6JT8MYV!)/cL3[cj3VnH$ &O"iJ_g2HosF.@ To@V7OK2"LsYYcAs5>M+d:Z1XW*e%Gm*K>tcI$W6Q:;KCW8U@LOlgU_)VE bAQRh6)apl,gr3^#@NbAij\=Sg_"teo$a WNJ s\q8+r@pKXeJ*sh/T'M=L+QaNK!gdrAe+n+FWDCZ"d73O&/!Sn/0.[9[> *,%SA'G#Dns-Q(RBA`aO7ehjH)t4Y>ad%^:]&QOX[M[-RS5W3846J>)6])AO>s&GdJcAMo[mJfU<>YkGoI%14nSCT:feac2KYL[-! Hm.Y7Q=:(&B9'$OVjb=d*e?S5Zdm'Ar!qIRLG soR`^Z:ee +eAt.Y.FKE>i*h$BGo)I4L)L;A(P!-]ofO(X1\m,kn4&;6HQO>TAD--L"8+>W$6m'Yod9bg_4 (a%XKa;;A)@t<"XXDf7j(g6/+W`o$%[@-c;ZRqq,9bkhLBa&X@(>sY^DS2fB`Aq]pm'8iB!RsL`MeG$atMf'^$hk"i[r`s^LS>(WP-?,oPj_BMIs_1gA$qsn?'oA1Z4Jf0BFg8n.[sf@=gm]33!6m8_IK6',"ZM[M>)ejl/M5S`7NlJr(^!dDiF[.n U%6S]nseSC8=_2>bcCgcoW!sAbgRfL!kgj%81")9\EUQiobP%Cd`[S%t/WV[A`T+_WFrsRlPS]gK0G?)-l)i*_X"4J,[Vl8mQb= 9Y(a^=%lViQp(feU]A`:-MU`^2tA#_mKUjSE*h,pKKl^n\bg5LBF6AiUAt tY,8kJ; B:*CQk]!fn4<&*&JQh^]rJ`k'j?PUQbR*dHaYWN`IqI5d'*L%2HmA?=HK>g73Ih#/Xke3&c^@O\rHG&A1&F!VPW^2'H.[9WD[;=#!Wk267l\ggd@B3(CnV"@!^C*Cm!@8dg6pIAiaVY`omHsisq:(]e_iW)(,.3 '_Y;bm&qQXO[_c2L*>=U)U@@V6QWjlsCA_(^TWdoAjC-6.^kp/8PVmW2pMq]*<[rB(-bHH34$OB\;86lq!,hgU*m&"",6e6`dNO<;S',0jLdrW/-I\P1IJV##$>:TEl=B"$WHA0]k*cVFE+#j,%ZID]KSV=&2S=<XD\h!tWF-.maP>L(qS-;P%%"9'*IqA5:E(-H-^IJo4-*9o]ogIIqd^G[U"P(ngM;AYL)a\+on0"$+A,iYLYIb]Ok8_fBRloV?h^>i?A;VM,5F5!O;mI)Dp(7"H4E+C8$M,K=ZHM3iaT?t;s*\4tZ*f-!dB\9UqF>siVD8lFn_eNf,5In:nD#h.;fF#M\P=*J,DKKM\,pq1^`=90Q!e=,@LU-4PFS(IJm/J$0mrDUEDlDZ/<>SUO"MSWAb 3ER:/YH*ab4%E-KC g>8dCgZT2$7/5Q?8)&MqjOj34>%m-^a8GG*P_fF?dA5rhNmWU`@XTe,O;S)EF%,0Aj@T#8(1A%1:!?bI?U_mGggnQe\\1 1cTr:Wbbg\b 4RGo#7Tm]\@0EaI]:G>4:2CR+IQdHmOsFBgo2;1g6@jt1pC'GAaa>/HM16?i(+/9=h'-[]OL4Q0&eTGc8GP:A'>O:1-$#.AdI0Bh9aALq^#XbS:^>me<*kQ*H&g\+oAO*#U;L=M;?#!"b[^K*?iL+1seV,e4]M?p3A(=L3ee/?D#p#)2ffq\lXn;"b N]1#GMBaGDTEk:[r(4ZF$j50M\K5W6NIMrpMI;E5X@I:nZH/sA8 3)#,l,1J`/8f/gJKP[h%Z5\"ir_WiH; Gi.-dF4UA+#(`EgB$!\CiV2nfHi8bde#CNHNg20q>KZh[O)2T2+'cUU'#L>iBnDJG]`*"i>:Ua<\bJcA,b&*i3Ct02M))Q$$3LAH90I7TA-$1SWpR3JmHQ<)ki([726n)#$LJV,] k[ZnXs")+P1EUfF--*kAWRgp(e%h^Asmq_EWK[CS,AN5U 'bgNLlUYn]A/FkZ]F9KU6OtVFV$>M*1!/q2pKO]8#:Q4'9BA@6#N/UWi@^,Bsq!R32;%Za_A-;;q+5&R4?8endVAd#"[O-?b$`E**Fk "Pl@d?3>T!taRl5"Q=GW"IE2?;81%s_b-n7jH!"VH[-Y8`^?[#8kBfN)oKgJ8?k8lA#0V]i'[dc'tcNEbaV9XT_85*(<5S_W!m^l;h`Z$`U;\rVKW:V8RA-ctGH7O9roE6;F0D*$C-(n&Do^tXcL3=$%@K3&An&/?/iFaHn6&7'X0!G0o5ng*#fHsl*_BQT`N$fgYGUC.Le]JG@NV!fAS0"WEGApT!R/^)#D]m`H'O*kPd?&kkAPrR\(3?X2lX1D'"*Q+,A!:&N_W,l!H_'PZIDVD:X%1j40E[>c#3l,j,.JdXlY&NsLrL!Xff8R;6#%K2R(p%O$rB")9tr3-FJd7EYgTS A(\!dgX4Vq_'_<0FJ%8V_0U>)jDSpRJU0K79LT2(C2*?NnnAIF9a\&AI['B$EkH,Tt8:JRd7bJ1BW6 imLcO27=Y)o%j4C/6;%[gAZ$k#`cWCil0[:sbU)Z9`f46@>X/\>MO)3kLnmtL^/4Q=^9a@N/n^D4sZi)R\]0\4Q9YE4VG,@d:V?\ jrTm)Ra).W^YAq]-=@8(kKhc7O_^CUdZ$3ZlC-ZAP0"s=^\Q7':=+X^r%*," OZQ M, l%oH2X7Z-1;/p,f%i!'Qg90ll9cE.]6)=J-71ClLUS*D?Phg.t,`^g6c`q#O/NtWP1dHAWYFIJL/;ZbrMd6Nl=UDrs:\9D?#YHFK\ BUhIJD#A`faf6"1X3g:bkS?4a 5dY`"A6Z]+jeU1QMhcQ6]@,e"3)oU<Ql59VhPq IO$3[=&)j] 6e!fY+9$Z;C)%p+csgdnAl;Ote]k !n9/`Wc`,9QV4F&Yq ?[pE_lG*nmem<mTPP'.2a2Q+6.BY0dmi-U$%.Jrt37@07jAjF/'6$!#taa;Z_f0[)2l"8L8Z(-+5*2s!PB9Z4K+dUcX@PA olt(IN]T3[r*q2O( gV,8 \5 pQAUq`ln#KObIiH$)Cm=\BaQ-[+WAEL@:j@A$niZoQp*\fOtI0/peWG0>OL?Z`B?s@i_?J9<$23sGI OA.(ZQ6hotT-KjOi4ai.T*27jrJ!jg$3WWE87=8\kBD`%53Pibf[jBAnKP)\XD*6Md-nrH Lk'o-Bmk6SO-l=d(Wj"Amp!VC ,iOF8IgAb7_0*XW3o`/eXiVN3q2k@p=+sSiPVs7$1hR4b@MA-'Oo_9\hcJV7AA#it^L&S$GV(m1FWq38)d\CY-Bq)\ZaHDdA%"5-IJ\=S(-)^BHEJm>Nt'fdfi-`6%+o(qa2o;j$$AN\K=I$'FEap4D6p8,#L-8%-oUFbgAWiG[nD.g5p<%0FM:ef*AtRh5jJE=N2'fciPam'd#\@*R>?2Kr3Yn'RA)($i%$,/eo_p!8^#<[%1Q\7p!i5eR9dr9jkE#NfPej$kW,&Ar3N;4ab-a-7a,qtrcArL^+7<6@aO_ph;C`j$TeL^UhfA-BjjQD>Xk]nEKF.?:ASU8\$A!@r+XLUlr?[a,@dfC_fN810! D!KYBtmVs5+#U"I0q_F^A2nfF0RE>t&P,`0V7._ajj^<>Q?tl^!#$O:tRlmHd!BejK]aqUCaJm0[Vjh/*iQ>D,-;S]XY$Pn2@3lh1(:AnX,,`4?'Z0 J)_` -Wr5?\r2PV_bA:h2HL'/?A1($g0?SG!"=:N+,8"hqI9VYfN4Y3?bS<;[p\3/qK:D80G$EUb]tgDU['[O)7Ht$c.7WT,dep*%&Ta_R,XT=n4G4M!/A.04d/>Y8'Z=Cm=,A'a!=bhRADYk9?sqics9TMQL_1?7:O6E:/^de,TXZ3A?enI)&@ir5U*9;HYV/nn$F"oJ#@a'%*,m6sHScVQFj/Hff/Nr ZP<'V6FaDYH4<8&i7ZTs/+FDH>2F,BP&BAM`9`$NTRCi7j*,a\S!>O?4rCV4]N1_$p>]E2eg aJ&sA^,T;n38Rj>U9,`mY@_kIsY[fbd%XmmD@p7A6^01L1XcG`&t+ISC\L^,7GYI>)'Z +t2.DPsGO!hae9L0Bt*U6D4g.edlmm;g(;=:h5:@d3k?@^!mnT%cjRpQPE8r8BA-70K6PS,#8mFp!^_lDl@kYfL#XtMEG]fe;d%%5:(>Q dF`cZ/\eA)^l.`3dPAi6(4VAf7jWV#6jfVD3.-7,$aT\ICYnB#et H#1SLfA?KNg6lPl`.0bdRp?Y!rl(JUm_?X)l>$/_!5]r.]f?M/B+HiL7Mf8P;A@iV:]'NX=K8]_^$, <4< qPK[gag.V7WHF@&ZKq01-"8g3E?]VK2ZLpmLgehF%SfQ"YM]W?FRJ4.V/G:jGpe\bjt^io$r<30]HJ"2n7H8Q\"o.=BsfZ\=+o)@B>S5.f]]Q'K4^bP3Tj0(q&)eP>

    6LjYG/,CVt3*DgB`+_q'9lK'-Tb+s)T27FJ[YR$Ot^!(W$beC?m[DgRN548N&LZ:/?sXs!F4]gFV*DnRMB`g8_X+a7qa^QAVgj.q0!rb/]OCp01ToFb%]qAHj,YTY2:PrfsO@?ajC$P(KShC T<[^'gO?!f#B]].HBS`3X#p"':.l^7m^,J1843Mah@-qe*)t0ZG2l3FI*f]EU8CldM29$WUD<2m-&'B;kGU\$gsib7(8d2@&-r b=Q1Uo^rGFmaO5?iK+A,A7">b#Z6GpJk-"*^VNlaY> qTlfc5K:mCT4t!Jk&1Y<*CU$'d5qL">s#F4@%W&+,[e&G(s3%Bdil_&+d=m#oR/j%1CBn,`;\:Xr-` &9a#/A`5`^e%V-iR4X+N;Tl?fAKpYV%kWL2P)'<tB?j2QS-4Hol\:8@&N[^?aG>eB=4P0)#T+B,Ll@Gr'XZ!^g7iF liLoAG#MX*kLKX:'A#.EP-b$ZDpdgQhP5A61n:&B r_=$g-4AR(IsV*9CbiWH7Gs+mA+o^sQ?4(p"B @?:B!'*kpj@'^:73Y[[P.WoRKeOm%066gH'6B558DqDXp6tOQSsD"c?6;"h,msOpSBYjLq(QAJZD;=Dgg@Nbl/ d_$0:fM==X2\=m"j][d/Z7K1[3aGS$p 0.6ED74l;g"3;7*C'c*7U8NpCZTr$^9FZ7AWf.EA<X==C-+F<:$oMa=k `=-7fS!_qfOJciIZE18f_e64JQU/lCF9Q`"1^qX=6iE)Pk@s=OPT) X&<$!i7Z%]alK'D Dl#VCl,h_c"I:^IPNUWi$dGM8@sSr@&%B'XcqA_@1a6eMZ,)ABFo< $hp]9!R_@1daHGd@)*KXpgHq2b6FV7>O1&aYi/!mVUmC1Ya`` ].M=JYJAX#q9F'k-#:.YAn!foVE7lb9AbBTX$LlFRR&Qj"%UdbQ(2CIQ"6W$NF4P\-e,<OsZa<.P#_aH&SXJd^G+rpNtIl-4#AFM1&m,Ja$GNfoh=e>CRGR;G72S1&rFhlAOQH#85[.Q0<_FNk+F\iUYK'Kg+,cYkkO!Ad6S\<9`n`*AL:MH*-NMo %1AQIYZB"lPft9$q.4K7$fiQfW@05*2M0Q,gaBYj4]Al#1EPUWAs)pd3/fM&;3C*le=YZF'sQ!pS7Tk1+hGA2b`A'cs*&&!#V2;*;Jd\7a@S/R$8mgLpcdf](QGWYAAF;O":QIe()+[::3&Xms,6G#7s04PXnp8T-Dor6bAZQ.i2VIC!BCm&,D5j!LJ?/+M*i_8t+s6:!pb^;qM#f:)k4&!rfLUQ/-GcDq9%?$qtNFe#4:"*"IQPBZc]61@(fT!7/.T7 -Vn $2>%%,jjIb,M$`L-82!q1&?%W0qpDCFWg@U18f*%::H%sRL#n/t.r!gg/?VeM"DHH6AI;+%a)h(ilYcP4B(lrq?$s3RpED3%\:o!((N)]]FrJrRO)"A)2i)t&LQh-l]WbUX=iP>l[Tf6MOoM7"f(:hfim0*@?Jio3=If%"H96(<8;7(M;/Zr!t?,=K"[aD:+6ak;,?&:;;me?f'7PGmT(B\`YmFqTaK7 :]4\Ap7$R:^?Xh0qGB$qQnjGaNR1]"Y9T4Z% T@pte3Q/??@4*p\^73Kr=s*FGJ5e!#/m33Arrl1]/1g6)jSIG:ah@9/aRR]To-!toL!hb0%I"1mJqi[H7@fT8+N:)"gCDr2\<AW`3q!)#6klf']q)P WODh:JMo!-AMX &s9ZA%:raO$)=,Sa[sBp*\`U.^^?J5nj3Z5Z*O>\Z)r([G.%e.QJ(DTm(TR(F\V^WqMk,^c$P=0^/noT/AncjC,c4>r5OrQOU#M6,e2U0YcW;*1$P"ZM/1Cbl0?dQ^\A6@3:Z+-^nph]2 2tc#>6&Z@6[*B7]fGA[cU&)Sk0UgUe.FFA,'Xd`6epPmXfSsT )-iT>MAi:\a5+gl/.pP@DE%'St*+r;51hk6,/4TCUejW %7e$D4pQKGFW"r=h=a8^s.hp!?.6lI_:h]fD:i5=@m"3>^XHa\R9KU?;Vs@_%3-3>$H4L">8ljV"O:4Wje3#D<b2:2(,`RX*qj_Bm_%sOoN/dqZ?,,N3`Y2NOt2.dW8U\?OLiMXHe R/m3QtI%f)qNU@U;sfUb*HQBKJXl?p*)lf[K"UWl@BeAHi/q=[hF-*`:JtCM)I7XD:,3%tZD(LV`d_>e@@>"LTS]ShI:!WRml\NG#cMosHE@t<1Z]"@JENC&=M7gW5t=D7Z'.KtN#r?fF/a[r-B20%J-,A&5A6N#K?;9k5Yg!:b=)Q,4jXh@>h$@g$GX"sH8]Wk$\qB"0*&3q,dE/a9g>*d^V8Rbrs&J[??YH"c9<@QAkj..T/nnaaPdQ ]s.-#&m/+,U0FA/lA[$O7;lW].`r;](S62JFttJS_!I')O4fZ\4AlMm:7d1'f@2ZE-O*Xjfho)O)/:*.aQeFAA,hiAFjV0mLH@tK5 '\F%m;g?AM]]&p%A7S&^ab7^5^%P^t?GKiYJ`"aBmcX7Z\Q_KN\oYJ%F[G'>Xre>-"9R\O\_J*Yh&0([Aq0OZ%c&RYCWJW[,.KEo;8/oUC2PRM6-\sAqF?TXll'2^$TlX2OdR*W7PX0$CmK:J\MD#C*O:^b!*+rm6/ 6HUi^hB8%AmmS=cPT>9e;EMLUrFY6rAL`Ni]UQetHfeE-9bo`Z>!]C;$k\mtSE!ndgq@2pL@ i`m`fk#OGRcTeUgCB.'b^>sm s:Ib(j`%Q#. 5T\IldJfhF^kdIAZ,*,;8dnT7Abkag,]"-nL$nb]JCWR9L$n85 [f3'd(WTmHGr>$XeM4p&fd+1bTqE_jfn% kMPkXk- (Q7V,m*VYdCEZQrda(r1>$A>;@a\/)=joY+?"$%AQs?J_0p4Q<Ihck5UXW>:([Wdq#;/>MKeH4kI@m30otpY[5jAI*4g'\f0qiJ5f6V-OmQ`B^LL@AIK$or:nOHa.N`;KEh*cQSNYD.8h9H%HAn#`=[Wk(?H)?[>6=LYJIbm"QDW-4c+ES6WKS^P.?Y^>1\O6Y44l5WdA;.=;(ZB";qm%i`^;mS?$6Crjg;;qR(Af\1ID\QE;cT^Bl:> `_ij_8>cK[Ut,)DhKX$NVGXl0RG`GKH+I/H'Mn#r?Y"67Pm+'3M7&FL\DFWN#qGIhK$N1>X\23%N#@ c4i$s,^>tNSrY&Oq@#N?*R%D$.!:QU^6B>pA^.Xd[i/Je+e+AKb>-=H(8jMiD2BWi%(72F>()`Te^1;b@]nKGrX1c!PjC"@q0f^\Ra;9r-CVIT2.XLQ\GK`/oQQZ<'WnA?@>P#*3INmY$R0N3-pAO"lRsDlts!8i0NAmC?lS"A>rdil+R?%WAg?/jT@L@@? ,3)P.J(*Ps6FHQ^lM<)J`B-K%Cr=fPLptLA'c?r.\Ji36@Tnmfb*"@gh_j*mN2EhM[]55neP1'#J[4fb!!j6eA!/jA]C]7]>mii%m=o/Y>,q^LSS9GUn$l@jn?`t98@ns`IbS:>mI^smC%qm&)ms:S1c?Laq4U:YlM[>bH.t7!14F d?pH[HPBtA%9E%7m]AK4-?q'r+eL b\ZZW%j@#BpRI#UhR:FNFBY,0 MX)UD.@V&bcVAB!`\Eq %Q74!Eg7O%CDk'-fK9/49\5_ bP*M6qTENeA[A5e[MDmk7Ncj,l]a&\T>WVPZ,>WJiK'_pS(i@HR":0-T0nI\pY_5f7\9]I(!&otDqY-MRSX+th4gU)pG0KRJ)V!VGpTDiU!:9MilXlsO9K?O.#Vt("0Rcq%UaAoM'l;E!a[Lko%C3qUa2/fgC%Ako9!#8Cs!X"!fOk*(.s12S9tn`,SFBF9#n%UVYKTo=+FR#@C"r`%rH1U*o.?Ee^YH `WRM-kSJg-80T8+$ofi&gJ.0SQbUcAm=pY63?SmfL.ZL:/rA RH`-&OtN:T$-4Iq@O.r$++jHcbd^kKr33*?KYbt,'e9\GBAJ2;sq-+]r$@St)O ,H_EFUaBX1MbN*f/1W\hjrDLK"R#ia?P(-an& <7g/@11^/Jf9%]6Pj[1)6o$i.Fc#q"5+gm-3HPQ9gbLp7FOlY[j12JE)[>Zl!Eo!F#.nSdm!s(;$VL2#W`P:.^L$0"c)/'G,H"H=08o_%^Q7J`4>Z17cX q9dWhZL:IFn5H@U,.-1;q%U)%cqFXQf^=[h5p*3C6_>OVcsm<$t#-(/g4o9 >U/T>>Le@?7D(P`R`Z)?+N`S+**I#1X5AA3IJEUa";l$>_G^4 G`\5ID8L$31/]a0V[qg+grWO*^sPAga>D6[hG,jX^W^:"!D'2WRQH+XA-AS+jOhS2nR@3b3ghn[,MH@sZQHis+d%A)=7$>IRVg+.r9.TT*ZSkmfMTg!':t7QUgk`b=(HD8ON?gf nOjj2^SPXoCV=HF_[P]cjPs,bH`r4]:2)7M[L*st%2Hlf&eq@ih+Fsop I(EV&oU.%";\0`@(;)V>2Oq3WQoh$F3:E6ai-spi^T$kjc+`rD!cWK($?kGN%?T(*]h?eO+T_E=)8B5ioL6W7<9)-r1cgW.XVf2Y3R[>+0]KiC8Bh>,C!$HAmQ1_8>2UTo._a[[qchmRnN2A^`BcgckQW]r(._m\g_gGt0C`e$GJ.r-^B"?75&4q*)2CE^$F!f.;M.]>LN7P]_(^:2DLhTWH,:)A7c2sJTbDF*e%K*OL]<9"O:tWeV%]V=h)>r3!]l"pb3;\&!Zk*iUn;"A&'Wnl!=ghSC608;A@;mj8!GgAUm&W./c$F+AkA1J-P*ma>Qoqbn\;2<1Hbp;/,V^(G'c%J!8WF76%+/='$FK)!Dt>Eg""2/4m"ok<#`,Y5pdE'$&>-K#1FnB@76/(D#(pp))6aN#*;)ro'7Eea6qGsg"6qln-An'9;TgLrhd;:d9#["e@<#'AY6PeE6DnRL+jL)A7jA.qGMNN)s,_\.6EjDZ?.W*.#S,9Nq-_Y+57LNA;qZrB+4"aOr4lAbLcEA:Md5qQ.QrTlnsYJ\TH';5^F\EZD`<$8sKonrr$J&2DZ@I%Ad:FF0I)g`13t,rgm.Y8nA[.T!+k;kjd.#Ps<2JCCb$ksm0732;Bp*XjA5F"2G-e3$rrAbc0sG0HbS$N)>L-Up?fbkQSjG9mr$f.,nZCYJ.o[S&YER?3 AV4&1-6#LKt7+C") \\@`B^Y:#i5gT0`(\E*Y!(.H%c9h1HkNC(>sV3XPgi$%.@YApoiOIm/=!4@,]9Y?p-5fN-f4@i.AIYK^QVgA0gI`W&*rI?X=Y?^/98'gIYnqVg[CkH>c-XL-/h]JSU_Wl^#C5I9GII;?YteE`t4M?f6'!T k]rUol25g1I^2k0/q6UXhV16b15[cqs]P=n];5plS6BZpITMN,$I4bm0aF'b:Tpmc^JL0/eg=Il\&:T 0JndFH$n%CUH6dCAa/+$SSGl?t/2YqPIooLf^_&/UtoL[WN/\,qn`TD\/k/-b$(!+2 TI[O@*1@h;scTFUIXHrN(+);jLZ9&oe'lo7eWcX8/ '6SQ3W4@bGC/N01^_Xh8b#Xi3rt^X1Co5OS]JrGQC!&V[bR\?++e@B:Kj:<\"#tDm*&?8bIY%;V1K,#E??rQEmr29fO!a1,hgIU)]U_6/X`6n)5rok"AXA`6,g;'p30]t$l!@.8M'XYZgAV4H%N\a1eG$Sg W!Q`WD!ga(r/tXFa3WA9mm5LMT"Xid&T.q.Q+VOrj#.(@.!hEYB*Ncq-et0bK+D1W_T2_Z-'r;d+df+7dNfC!To#[$RL3J[]\:3Ns+>?4J:Z4-if`L86=TD=M4ot8!7Q"N\+%\@`a5[0`DjbRiT/G2IkOpKZ`?)T8]a[ELKqFogA2P1ZGJd`(hA&A*':c8HM#3eE.sRcb#F&,r[B3$Q7lZ&IW%T[h;>R;qV04CHjhKr8/O8IAn;h>M:5(((d1J5?qAS']+."p[kK<n)a6A:t-08^X:TejmZp1E+%;Lg%lnDsAMt;)cqgRs.^1_W\YG>A:QH+1@H;\otrctFi96"EQF_m6E@W)S(oUA`pKfM@Y*o]Q3K5iCR.gec%4XOTf8e)<J+7=\<2Uo#IR!m::-% @%$;A:eqS)t( @RDj=GbAYn]%$H*;Ubhkm8eh\1fbKl4('*`05i1m"3%KGUS_G*0 _k,kTJ6X=?A\Y4Wdl]iTonCL:t)L.ptEB?Ab+:F?dRY[H=37M.JrRl"YAjj_T$dLtbc0Tkk4hRXTaAlFt/HcQ7HINZn;Qo?\P92q`si7W]WQtlC^`EN :akD;RZHn1-+WTX,h'0Z_s+<#2+_.4["s"tac_C-WhgA*gA4RGnO,2L&E8$Mf[mRiOj^!_Ec#cq_\TEH(>QsBk^J+A0rPl2=Q%1L+4j+TdUJ6)B!0IcqMfR&o`]Gsi@AgLV,-Kr-5l,*I9(==KW0CW-?Q"-WrnqM6"[%]NcPfP]nOkckft\Rj.?A;FbTC^MfgBhD- #;&rM$( ^b#)Y@;HJ#@2g@0pBj6PiOlX%A6A7R2hZPZk(8HfP+b1GB38&F=FO+%L+j +d:J#l\rl`nAbDEtdT/8@#s>l>f,t!.$L-XjP&Nf6Tqc h4eIsWcAEd:'E;:#6Js6sVS]eB9s)q`L,-1iNKq$F0[XXIE [#[mlZ5Rc06dfB>A:% nb[n;8kKDBN[HnaPpI;=+F*5n`Ttsr0^_&@ YOA:$[^t[#A=_QQ;VfHT=4Ir8\&" f#?QW>OiSEhrk @shHirk>9/berZoY>3bH*PtUN>nTp`Xs7[2hAJO[H,bbROhY:RFqsVN+WtV^Ai*Z_8P_D_j?f!4[X0GJk<6O&A5'/SCO;:P+1DDH;n2O1O AADT8l,d3-=Ar*V>*IFR6.jc8CN+]s*bZMR)d,iH#P33Bq1ABaQWr<>R*;-@jT><98-^5CnO>p8]-G))41BD$7M,-hCAc'.Gs_DRC!gk>HSIHHER,+0afJ#(%9jJ`@QF%L1V;GfpAM:`;<1@Of(UC$P@(2TSLo-g)M05)F&*b7Y9o5A(OP5R%WL8rJd9Wbc0L.enUZ1F&[;ac7"!K,,NW*5]>>,X[>%@Ei37q,ro5LRs$#eLU1j&YVO\@A%b^MK._QBm;4Z2.3X$U6RZ*eOA7$bPkMd37aQEma`YiOa*QU;G6KR3X*q1G0K-Q=m1Ok#lE/gI5$A+-of5>a4\^%)$)=4-stY;Cr/]T3AHqY*,W\_K5-U/'.I6@C_A$M%G<8FD X0-s%l.>p5c7/)89RL>$-P>gtP]!YoWh?LMM!Eqtg?a,o0mMrYkjrf8?\\N)A]k#5&@8-%)RlN-3-!R;P70oq_KlO;CAAP<3JOr^sV:24rt=(q= $oQ(1+l%AK55\P9?t;BKMV>5dFHb,iG#<>#X_DMQoEZ+H;WXd;G=0+ Ze&@M\A5C=B:r=1ULSDD]tHq$b2sYXAc#':I5 D"YR0=LWXee[s"f4O &-l4@8t^qL7l4UWlQ:5Opq%*_'b]j4Ik^_kH+K5(@Of_fhWAs`_D^2o]]=':KsmcPn99VoGCtCKP\73;K?l>O3gF-Ns`_O^l*e3h(FY=Ddt#M?Rhg^@`o>-OSSO&(G0Xa :Zk')4ATV0/&##cWpG(AWj ?*kd5sqG/9.H]e%GKb*bi'Yg>K2bEcb6;fR'j=Pg1rnSL<!.=h.H2QJl\M_qD,J6g^6>fT)a?@3pMXLprO>^Uo4`ba_"i#tt'CAP*NP'Xt6tan_SpOq/Hs/N3V/PR9Y.>h(#njXVjDNmDSLEJtA$\V@C[>fcWN>3(Y9/(\,]Vf; 2p(b@$72V; )\$s*HdfHp@j>DLD%N@gf?:_8[RU/O"Q[1jALA"[='/OAA)-i=@'636!el8[YdW/V(-d3>T;S2Oc\PR3QZ+7YGG6#d$ mS`#CnW9iANsQEoRP3ZU2q(@/AGF$8MWB:bObcRSOR'/;6iOD@iWh_M=/Q;fQ@^ P*ipN=7GDGqTC],@t(@%+1_LjGq"%HbLc9/IJ@Zl8sBP`Mc8C0\m5:s4Mj"gZ&Y3LhKI7+`m#(@r-R59\/I\$0$X!e p7W>""D(/k8OIt#3s;/0*7bYoik[F]4"6@,2'" WP@c5?l' J?J[TFE*d-oOSOTVGq:a%giE%Flg.bE626m-2i1h06BnFJULW#!20?:C(7D^9E0%hrZE&H^Ve4#j-W68M\.!SdPG<,UA;M)Q -$[7gT;j,N\08e"\,;`6X4<^2AAbe0HZ`Jl]\8tN1P]-HI7pV:Q6DD7$k(pQZY7#OP-G %3co4:Bj.A`A5_iJrljh"J><-ZK^Gm.b3[QcPripbVm/EU0Fj:Dq$D`/*hJ\*8F8)'&O>YHQn6MSkmMdT^gd-NqPt m=$6iY6M7;l!l4CB>Rq2N=O;YSUi&bA8>)R9A&KJJ,A\sBCm< "'#!!I[*Vm;a4Nh2^f10r!.p:LjdF77_rg@V*XU%!t+`#/elU\2\lk.@Uf>0tR8$?qQJ_:kWKJpe['.iiP'G/,Z-L8pFOqo`KHFDsWdbG0n5aiC?><Ha\cmVls(RBdo[KpER8%FWZ)gJ(4GKPZ7;6h\daAa?j$AA>`bVT_&"A+H\hW2"p!4E6CrV$*#N9.LL:5tM.KT#i;\bJdqR]B94)i0;I9)/;_5_SR"G4T/Uq?_3WmY*Yq%6K^dt:d59p`jeK A7Z^U=OOjHR2FeG0OT>S=mT-A#'Yc7s s,@_p"Cb#T>.jI/9:8;cS5=jsSXE5H?(.VlG3CVaNG(*CBam!?S5B-Oen)\\p>"\/!i)ka$m0i,8S6no/o-glcW&PAcA![7-A3DVSAA9js5H_.%CH=XT83\Yq^+er tWe,P:FIFHiE=1K&;&5+@jj&N!]%i\Fq0sD;9cR ZO0P$4:?VT.;hFi_??dcI"pDeF4U.(BS>`oqn]VA:TksLA\OW18p^FJhqX,/F&MDPFm1GfAd_sUVC2P DUC rMl@APAG9J8+r*(JjR;!7Ddh:nN#'BH7"Apd,iKd(&LW^Q*A'W5$=/H)Mn\2a'h]OXO["oUSI"$;c]YhdsU82dWk'L.ic o"Wk+<:X"N)e_DdrW1_OL0#ap []DiN\JjPe"lRaZM8r4+ag'7=*4tNbea=?;2HK)6%?tD982!sdEd*VDh,gqGpD=$j;q\mq]c=r@ .\Zo+Gj"FWL(@/4[T%TQ@=!b*! )TK$!Ih8)i&iP1HbDk!G@s5A;RAKR+JPgi\Y1jK1l&5^50S?LMPUI]rfD&^6>LAf5[7MmdRNp?/!:!`3@ @m=/9C3*c'&=Jlb8^?o:`YhO-5GrBbqW0S_*:D6G'AcGjrds#LI!^7&RT9A>"[=bOJN`4oW7f^p`S^J[<(iA^7.$q0Ad9s=6-AcK4r?h`EXp9(`g59GJjHSm%LIU+)O` +05ZHsoZN=h`'"FOc:T;@_7CPD-TWFg/7UUAQl^&,_)IAt(7^3g?X"1']/&b>FMD5p%bgqDHd'+a`\*88*$BeHJt K jm.: VL)cF_=R<IK^\8Pa-)mPR,n3bNE["S8>^<&hV'B <.p0\F'E;Ze?3+C/g@2-^LPA%-Wt%Mn?%PoB[r:=U48X49Tl7jDQ-WC!LC:%#5l[3b]>e0TDkC/Kqs->A2$7HgDU\Ob=*= a(%j89@-bhMa9GMka%/')S`S0@2kgA9MS!rtX65JBEmS?h7WqqkJToGc@S^qK7S0Mi.@^WI'Lf1NZ(%hA^))K*%mlBs7VE9M tNi@9SNk4F1ah3?<`WWX!^:b("rKN1`qT&[))Pa%h#?\O?s<IT_`'M'^tB9+grJ3'/<]d&Z]O.n1A WUBlaE-n-2TDK1h+)ig8g[K <]]R4(#9fM)C<]\HCZ1YdaJjX?+K2#mGha3>2#YYOVBE#jcI7CHR__T9Qd?/Gm5[tRf8tW8U'id fS@_5?".$I9)1Ve?9J/?hL:rHa>f<>qAn`Ug?i^R=2IOYq> Q-WJa_S&]S*=VhPS`-%pWptKBhe.?IMc/G3B/#m9lI?p8e>FFpt]bT6hP,(b6o6=''.p&rYZ]niT?L(JV.1*I#qm$qGU+@1a@cLdC+IF"Af(l1J6PA(O?[RbhZIp0IFooE-%j...DOF&]^l 7J;6pC2CJ,dd[#W1cA'0Xl!nH:a24**!%kF6\S[cp!PhCgTLWWPsr9lV.r_:HUD"PWti<@6R_W)LCkM<kp0cnA> `fcTl.;1+rhbXX5^=(Ke@^b')g,WcdX]c'j)@KIc\Ng'-G1@[:J%MJ0E<*&"f3MT*$fVTQ4=:5l#pAIm+ns-,:R(0q,.ibo*21jq`5Mn5"UXX_n/J<cg6c7j82V\$H1!mlYnj7M0AA[8X#)=UG+;Qm5G=`5g4*;j6q#q/hiOATs`oLIBa.p7][34AJe_r/q,N(CUMO4Seg%:(9s:FqBnHLm;Sp^HNf%fAs6/DL@GS,=F2<lY+b+4r."IEdri4J3-e$?ZCl-W c`+sdl8-'."@;dIr>l0H53.1=>IWA?Ac3_th=HtF?p-i^VFsC]c)4E!>+AQN@@\?IH*tN:NBt$^Ab=?jj;lm;Cl[>DV.MJjpeXd19lD4k28tCO)^Zm7kZ'bOjG-Jnd"A">-m;hHB@g)p8ZW.j4k^0/k7DRD=Yn0=-PD#]%5kU@eK.\H;H59XF[(hm]qV"R@"iOA1M"]MQR5, 'c2=Ph.2sbD+HmOZAp?_c]5mOg]OM;1:$_QkaS$csUnd/)e2iN4>IN9UAJ(J 0Md^]/dB3N8"^q.j'bfCjOSs-!rCKYUj#;_o$54D,Lq3H0MB?ZCI*C6.%P>ng>EW#9h("sMP8(B4l;!oe4)'&&,Vbd;P-%VH8&q:=/e_(4#4/:nNho\*6BbMqG6)56F>gpEgZK!nEWS,T?r>,ApAKD9E lr/1E_Tk5o#XUdGYft`5194^WV[Q@;jA)Za1NOQ-a"5;LZ'YB!6RfA#sZVIf(\6B\irp/KYVa[N*8m8O(MK9+JD=m;iF4VF@`7?mhKA>bdE50AVVJ6Xt_#pgZ7,U"B#=]*?mrF3MAYRfA"- N7ZDanqj(hK3T``#mfi,0 0tGA(LbPL0k0DWJ8XS82,b+*YF;#;_&6-&Q]tFMafcfC/\r_QIdc kd0.o#^clX.E=3'B]78%oRLUbCd8Cdit^GnMsE#pR:=qV0% skgZGnOK:scEd30<*f'dem[/$!B!jSRZah// SC29rRbrk"!A.i%[!Zlg:&O6%iWnM9 8^e)K$` .G-."W,QN2rnGm(V'LEF*IUT1pmH=iC$@jp!D@&C!nDr>5FOj^N!5%Q<(jF@5<1N7^scFZ"ZpkQ=UKL`QqZH&"6Cp'(Q,H8ooqZc.\WEl1 a<GHjI%;4#!Of%KUc\T2o ,))^fP#[OhPE$(3N.hBU(Op0'?$1*B7"I)R^IA\8_G<*j6h>UR`><5 Y^l,ld/f28MJXjV&$I&T>$9g c[K"d\mc7OV#Z*Y$M?`Q(QY\,_\/@r5H \McYaaR#CV=JK(A*.LI_aRAArY?AjK+R= Pn%t'3dX&ZJ-YA9p(q')@2F:GVe9V+7j.]pdMrT QF1V:$*`@.?atU6Yi;0+;oNA_'Va0A38-sf6#YZn_J3WIfF Fsh(TE64S5-=Z/L)#J7S.Hg_oYN_e--jU2oaK=peMh`Q[$D)dI5q3tA7VDD+,?iG=f*bs])J/8;qOam0mcO$FXp4jQqN!iMM'KIE:l+He=U[8o/9/sLtd[c3oJ%:Z5hVVZ"dO1$;idosNDg,(A'F!NfeY^O!akMYg*SM??f73PL6.lfHY`r_I]-`V;.\A9j8h0*Y73ZUQkqo!Io%i*+hO.G@,/d_%'FO9dP@^D"l&Qe*-[$!^=X)tKAH$:TAK4KQ"MFTAk818%GnKgdSG]J4p\8K2ZN".1om'PN+i5)lI1lhK8ik#m3jVY'W(+!%_n*W@.KUQ+Tq0-JE -7G#gd:ARilZh9/>]0,_:kTKm!F_oHrV8Y<*]D4'tSieR&AOkf_?J'/o:qPdReU)LmpB j?;In4k?[tAOi+DZ_7&<2GMK76BM`qMUc#1#^Xi%(H1J^OkS;a/^ANh8e.=-"J.f0\P$,h"s/,sW"Oser6QcaCK[D<^:pbTZB_$q;0FT//eqJj-%KFO37,%`6kg6B%`]M?"8cte0V\*W#&WL9:5a+,-(h8`;;D*I@:ZoS%9(oJoYfGoSgUJN,N15"(I/G?G$G.t#nspAmaV4KoAIEQbi-\4R?t>Aq6kVE>3X"XFVNn;<:;]r%'p_N[pjjeJ]^W :(&NdMqg"(!'F*PoO^!\f2q!S]\Thf+s;9AI_3-SA@k>p/[Ah'WtN7=#f-+k(+p5]e\^jQB6-rDWMAb,+K0d=WmR.><:Xsg(fR\tMOkh!5'L5@BsTsGMd4A+[ZSZIp%/$aPAAc*A>I"h?d:^? G)snhb2eNC[(J8=I-e.nb2lLLQ#TVNLli@WnK`PXVI]M[ki^r0Se4?W_&9M%)\]r/0lcJD[Rl4rI2qG(_]^1,`_RJ#YA&Y3JI,eHKKG@p2##LQX.89hjBo!t_,MC;;I!TWAp>!sjf.^,+sZ=Hr%N2o+cSk.9lg1d!]4#MX6(]ReFA=!%"gqCc-MW,8#C;c=th*btBtJap]K\^+lV?\>[;Ap8<&RsH8cH`#VS^J]?gIJ5lo'9Z,GC@f,AT(>^dS2StQ+mNQm0e`6\_:)?/Wr?,_^'ea6XtD2fY3$hTp?eTdaG<+,!fsOW1-^B^4:8d++a'ra]JQkMO9V#V2@U_YWLW0L)OSU is?CXFt'5KA:p3ZY/Og!=ImOhfIR4@Ebg3AAXGh-Xkr>!!?CbmA;M$=]<'C[W.i=B+s4"RG.)DcBm(Q7PB#I2MiaYs?\VeitrGO4@U"ZWW+>5V8/C#.hP(`P.9,&S,8[6IO?BUO.oU[*OAmm("Z=4_) RX>'AjKETf+?Jt`28%7n%dnU3bRc0=>PnWVZ0_j+/a5&kI$G_=Nk"nAPVWhe0PV*tIZD&*-^]gpV0E1P4A]i,DH8j*@-@=W9'B2DTA\Q23k$K./AVc':YSZ?%dQ9[d!i58q!6$qP*J-.i5JAj1[1J_`lK\6pIhQ`;pA0'"XDL0#0oV;N[mZ)e$qTtNRZb4AGH$S(J9=ACXY)jG%^ggr@%IsTQkk:ThT`@^qJ8[]qPj8$.lmTp,H<71TW@ASeAY:q.[0mZ5N,sA;VkN=6?j$E`[SPR 3n*:ND1c1-L1KU'-WPH6QA+/E_bph'83j;eG**giUl6ASo[]7m2[^T8G6jUUd@prbCrAOVlgIU[9_chGe;^X@ T.a:+&tptA0%5-p#@#$>r5T27#jKEjFHtS15pplmSM\mO`"FsN)d2jm9KKme *OTa="`gABf'/O=2@,e19XR&<8p:1L&U,(@DBYcCGOIeD7ajB<-fbp'\V>q7n>o8fBkERO\?Q4ie#pFb eSs)QTR[pd1`-YS=Jk/9Y**^`p#YPQENmk6UU-"]E'ZP?^,L5SlthTnc2_lKd_>imUpXBVDmRbd5r2-O?G8;6=,.$CRMUdZ9RVs'oPB *U9T*&Hkf^]Rn#VHLZqlh/JJ&Y`At `hPB&TR"an*#.J0E26`+CW=[s;^?%gebsV+[^`EUZ'aFMS!NjmBc cAG=VO+]+M[1rgR-?5lOMiXm^@0X1"7j_=A& Je2mMh_>M'mat?$)l[S'YjOsH]l ek+Ls5l8 cP,=`MW@m UoEYnV^MD/A>4mN=4?S/Jf3*>f%V)B@(;A$Bf^IkcLAq-T(f]i`7i6Xf:%=0U>X[+'(ac:l7o#[Pp;;`&D+CLq:U"/k<";m/K[E/L"23TMi(bf2L6A0'D3*B1 U.-]Z3FHJ/#@9'V5A;Tah)q8)4]JBp+%7>nmhS?e79@Iq/C*J_5r@9_ZdsVc5Y/k`BkgialL8::XP*%V[cg^&Aoje_/c[ms_4\N3`Xt^(KCneo>^ogjDh,=^/RP'-=q(!%[B54UpT,ic%K+RcrXP9sKD(0/m%>ZA:s==@cAdm`aT]JIC63Q0209[%MM;9:d.`tnKqFhg,3(YO4]4 =@&[?%6VWTA+K=A%`S/[jRA/rCA3#BBhAdn D8p'l/W+tiilb;=^'\GRM(8b"I.[?*VF,+%1"_#J8mL7EYJ#1T%Y3G?K^57Xmk(TQ/&Ajl6^mhsR0CB12Q@$(tBiE0YB)Uk;A@'tJYCab76t1Q9Ta*0f!AdV!5!3%;K!b<,N&mO%TdK 4bOOfn;m`I_/:nHcOq]Uc:3ljjJQop8strF,cY'Z?ME[`ps[+adMHJ2A:?)ffMG@OHf6*,W(kDNM:P&#"f=)e3h%4^]f=0T]1+bapD=A60M&l'b^4HU\la-I-j<`A_"/V#h6r)_Ti8b)KG.K>6ECdLQL;d`VeFI`8=)`Qh0ejFQjJckrf,><6bBmIUJ+rZ MAs)AJ'*[qSIC_e=K*1P0G.nW_A]c%)H*HR.-.g-oO7C N+Ie%aZ]_fDW]:S.9TZcXq3*ih*a)U6k)iqoXs\"*dp#U&eM%A6mVd2[bp&`r$'^UEi&jSsWU,OjYX4r9$AG*r^Db71Ul1M9m8g6+s) CaaTI`9#b)U1AOY3ALhtA#q\_+]PE2TiW'6aZD\HdkD)/Up.d++A%I^#fGKAW]>CtGt@A.Qj%UKZZHNnXer;a(&?Bq,]W*ot]P9e%iZ@]lXcdPU(h#TA7HGT.E8R(h;EB9JT15I]q)XtH'h[0IjLYE=/RFFlcVS)&GK"[Ag`+GcdI?tTD,_XG..XfWAl)gT)7dOFFs3jC#ctjk"2lpNM!Ui0$5H@ja;XZXDT\FMh-m ^D%AIc;N5A.j%o%"a>#'h:kjq-Al`V\]Ih H>:F1hd,tSoPac]sc\'j:4\Zfo<-%foa.F%XN@]ZYm+SIFi3f2)prdB/c$U1)["WitMkFS5N?=b.\XXf4D@[A\\jpg8iNkRCch?pB@R3$:G!X'O%-B!HRanglMWA#5eaF2;a 2TCs_>cEXqFAo7-<l$ ?4krlJ/q]K\Y)j_$AdU"3'P`AblRql9t06f8(bRC&*:[#E5c6cnNWAQgS7aSnn1X7rNM<c-tV+Hpd`MN$R!AL": =LdPZ[D5mg=%sD"TdL)m;AaQ7P_-9A2s[.'TnY'6"C6aFL!a"G][8>&Z0U1iOHNSG BShrT+_I.=P0:S]oA[]6&,W.`4_+#j5G7Qk+67og`SA8X5RB1)K9WG\go0C_ao<m$^:m[JAA4RiVWn_V`c/am _]F#-;K^ HV\QBI4UD()0+e>N-2sI8bQ*>P_NM#%ie,fA31lW[sYn)Z-r#>4lA[C@Spt9bG0YQt_;1$V%O\-Srhr6H?jM\GX"KX!CpVK,)Z)Sa/YB6&^i4TpU\FNZUgPQ#`l5jnK]-.A*l<](I1T)M mQ[TM\;AdEF-n'*f[o&=$SD`oD#*7Kg#R?0'N=FomX:N"m$rM H*_2X1o,RRolm1@Pe05A)X[3Asq<ig!'gbhLPd`1t_,eA^O9R] jl+a=jlE$g+k<"$lm]FUTi`RPZ?3BUU8A.F0lelo#drgnH2oJ -dd6*>n$r0RHNDAfC`JoA!e*.E]NQWh.O8CAM_Yk%s0aaP22;=30;9p`,liM"tl\@(q9K\<%V!ifKFoh0>QWs)RDAA=Ra\o]GE"3"T[2iC$PL_ M, TFR<0G%iR[j=4EJLZ:iHnSsAGCQF;-gd"'f^PI3s!WP[gbp\p2Kg],fl(NBF,k;l[bE'27W%cKWL(J,8RH^PLqi5d[&W%Y5iU.IH5\6PfP"-2htG-L#W8b^"J%'XB6nV:Yk7'bE`sp[^i"l@kZ@\*T0jnA4(]_pf=R^SYRG+EFQe[V&iW3OMp!VRghd)Je+^<VM5=f^)qNs3.KDRBCM#6gJL?:(e1@M\U.&R2AJtbdNO&9 [\-T"p$+PLQ$Bco QOiA;o;N'HA`eAV+654S[o4[>]AjcN/g'VJHS9Ltn7b7*kF5\\`rkP@ChHLh"]W8!;V8C)&^%qLE?Mq88IHbJ-eA$;+qOaB@4kCGY;O=d8\.oRU%s[]O?\D\0JO98 L`imB\!#rHo0]i+02k9"4#)5:% A&9Q:,;sDZk0[o(GVlI*T-W[-G#J+-@r!,AF3NG6OhUcK-hXd(##J85GUGZp0Zi"9_Pj4^e])>UC3I8T+Hol=BE ([Y24p[<]CUcnR-,G=hO3WH`WDo]5;`=EGi3^d7aj#G.r2kEP6S];>ab[<d%03jh2X1\'!2D'sl/*+oZ8;&\"VXrI);dL\(c?1; Qp]/?g?:.b8%J!N`31"B>Or&U"dHHk-+.`=27f%IT+#r:$0SfoeZ%p7[4RG!3GTUmO/JVKYm=5aC$WQ!X^@"9li>0s2qj)2G,AZ6%F&N#lHlaA (B5r5U5*TX\LJGd1!hOV`]YpD)_>[i*T,(*_oi*"b6a-am,)Y"nK:-T#Eq"-l>R9TSU310G8h?gm$[7DgXt4B2i7fB+IEWi`Hi<^lRseL7U>f@*+N_hAsH)J>f?[B$(-,E*58/44`l%/9]6c,Kj)TfCDaNAROGXnlUaN=WIt_!Y9b5@@?@57K-68'\0[`cnBG.YRD@coGCTG*&ChORm*2%a"<'0s7TKC!hp_`.A2Vi,d*)Zd Iq6QK^KSO9[n`[soc&tHMWD`s=K]1h ?BbJ?pH.n>A%CIWKNsboRXU"/p%Ma"iVi`mA V'R)b^e^Ge!iqH`dqTs@a6\7EA(lWKVHW^,,2o5@moD^Q4\GN9YPjq7K4e`AadDQL-R]3/b89]MJ9jf7*2#m>=*RW&Dg1`A)dAjA`^&]^,OV.iYWHliSEStGtBgt71qQY86*KcG453U//XH5:'^R0<[=9h(IsMdA)$%L(R'mAW5BRHkMP\5dm.:"J?0]+b+=Eta#\XFb9VpAZU6;?1S^VLWq$\!V=./:2\+lnHEC=.oMSj/E72a7[kE1ZM$ h;m1=lfT#32?VZoCDnK?EAA*MJ%MGB_l\<&/P:3%Me(rQ3N&'@,b@>KGk`4D^h)Fl$DmI>L:J>^1"MYHK.o^!_]!qj(Z[=!'3S._MeE1GdPrI#i^#jGq4"h\DZ,?i?jdXMcI\MtsT1:(PG8#?DM?Zse)Gi1OC1W:d`69"akP7!>:PcQc64aGhpcnC/A+d/nn@fQsG3D@9+i"GP?G9[f.3W!RACAqVrdn!k/VWJSfoh;f5C!H:a,M@n\7_]oT *>nDGh*r@N?2;9"6cV0-.e4](:FDEas<%>X fle&l=!C,q;6dNIU`;?C#[p9*d+'LN_aX;a.e2PGRkcVPFIk3X*q qM`"jRY?>#E]"-`YLK[C:QTa/,8p=1J7_rZl7XX-\rlM0;$HGfZSt;_Pd/DPlGJ+E*aaO!X['htANedI)<'j+s!KKh@q #VO!HT3m\SF$Bt36o@0tc-ZYFs?VnN2)D,?Nf^['h4m#0;OLSfOA/dcHiX#L8b4dnDs-nV_btDU6gJ+[C%Q!&9kL^.Xh?JrO7jiCTc^3d@;\$,t,+JQOjjf^FUj+*m+*A4]??RgFBWlA]bs/CcX49ejPb08lN]h)>=g_C9`9sY'g+e3;A7At.1j@>4gM^Tk0S]E=;r1Q*p)8ira/O:I+9/_QiRc.\R<,PDD_lGKK4ff**n2A@HK=&?4IUAk2-S-[E E`JepsjP*B-$@`KaMlrHo]6i-PBP]%i]$/FKR=$>-Nj9,m.RmT8H&h.Y5o,Y4)8.MPWLmnRC$A.D0pd>3C_sB(-p%7orENVmP6Q2kd*SPg?M+GB-RBH0'JU%NVt-qg%>-A-Xk'!V2sEXF*"<2[:htt#e L*[AMYK3B$ .lH-Pk85-mqpcW.2o$jlf9>%UCd%E2(O6)#kR1,1K6OPDV1[2$&)bJeFc/R@(2Vr5Ko==WmK80+s(4>Il.0SE XX= )-[W"=@BNT//C4EGCWVSGo5/iZKJ@$A2:5Z:02L1eR-1Fdh[ljahX"+-XaD&c2`=eod1g"_l_mIK,kVP!.1^7J3\YR%G0Qjr9N/]hgAdC3@bE$hb`$[A:f+Bp1rYU6TH0!KcnRN4( r9 ][nqNnS[brTD(`CEkeoLoKAZ-Bn227d-k/%$i?aU2kD`I!Cjg& 'H-/o"E'7bdaY1gL6bpAefnAqJabJZfnQ"^G@%SV)S.4 t>>rrdNp7f5?Rb@EmA6_q@(%OCd^_]SDsbgf+C488AFd%Kn@dmQ9D\8P9dW\^/+g-;_?fDr) qb#AY+T"R^]JkF-n8IP7o:;Q7W=4s&A8?IKrn0U9URPPf0Mj7^q'AL^<(D0:UsbP>HO>&N6@J1`s,&^j/Gi@^#i+YjnEf>G&!)dohal(\&Y^d\Z0_+LC$c6OFV>iPn9WCd`?eM:-Ahk[#"daffELAi^sAqbgKAf9q-+=^V#4:WJa#fI5rFrU'BM:a?b-&_-j&[T;,0KH,!:poUkAORn6L-U9VsCX9r<25r9g\hltAV79W%b'k2WC"'E6H*:EA A!V1`PnSba\kVrr'AVShRN[''U60+%2)kll<+f8+MefEDtmsXgB^;_O5A6cG5j8GpWVs#bGp(;;[oNB9tD,/D3[pcJ.@+@=n\F*l!CHa%KW@(&@0>=(W%mOj+"?og>4b;3Yl]ocT0Nr'C_o< P':8(\3.Lcs9NB8*WPk,3.[_29,Wpt `+h%:0\]?>$5s56aeiS;7;tHIgZ`5j_WONE,e`gJPR^88K+b VMQ jWI%]mc)3]1tOt5\/?;TM`=$D# d"#pfLjUn"Ns=:RX?gObQa2a[i2g&<^(jG.ZQ]>rJcqWpPjlA#EYif^<&.pAl\3=H05lr.=K'@dWb@AWZD .""MQ7dsXcE^g0t9(:TYUlHjY>DB6DgGP>'9[$](VBh&a 0t&@Uf1B9Bq4ef$]sPI'S'"=ef&b\/j'HAM"s1tPkh-^'GV4j"f5sAl%WCp[Y)9HJWC]@VNTf:o+'5_L5 =R[Y50##nJhCEX 4(!G#<9A?oi$pq`Pl&`lPWVAMrBDYaVam"L70VbSbACEAi-;]WP )>Rp4ep.3Ap&QF2Q[C!LI6WM4a*f)62!>29VZ6NG]7F)M'%H@Mjoq#H^+.XZtnV'Fp4H#Cp?055[?AK3LIt#_if_"9msn[+Z V##)Vq\/_>kM%I.,h=WA4[f+Ds:SVRAoHdn!o:CS;ejT"?@k-Qj*2!#eXpm>9RN&JS$Vn6kq%iOQ-g%Cof=`\A']IGVV%0O O7"qqeBtJ)Ula4Mm*86#QQ\TmkR/!J2G'?6e`)6RVq5%*ItWq)P:5pC#X!:K^# 3 E-"eF@s5X9=$AZgJ>>YfZ.iq_C1t^JgZ.4D0]^88G[gsRo+=^/8d3e/(lr ?n4_4EL&%VX Sr$$S]@@d3SfX:\!>FphR;%P$R;TX>\$q=%mafk\@Z(C]/UZnI9R"P%@0U^_pf`opkp8.>?ZE/c&FVqlGBdYsj*S!Dq^8!K1?%mR:g:PCNqagL8hS"T(l[ ^<\J&9ZN%Q!AtVKS;DDkbboAKT'nkBqa!Q90#LJR;..-te=aabVt@40KFBr8h/T`Zr"A-P\1`84Xq\fCl:USe'(eR>dblk.#l^YIH,*rbK4(Ws,:?Gp@d#W0_+.,2aiK5trRDn`KO(+4kemO.lJ?g^bOsWG%D^P5NP*$nf7kFG@%0W]MlP*3.$TO^l 9;i'p#OMAKdl/rKO+jU3F!JBFdg!qXAl,&sR<'o]*p7V[A\k[YNQDr@"oct>!h8eIH.QU5'6L]Vpe*-0XUhJ,5aAkK:6]UlBLMtm5--at 3PA/YT@^D9!E;%cUR(ec5*-SHVfBA]86_b$]gT@ FOG!kf!mUmpI5A\lH,^sN- \%?.W&ReT]TN*jJ;3!Z7GWRW'[\]=Sf%A\GK$6,s#'Hr_ME8DKc,HiE*H@0f*_TC(8^'qCZrbh#.`50hC]9A!oK-Ie?]f^gZD)'sC\JEmKPK]1&6U:A<A=HOlI)9?$ErSj8$\)6.14Xla@eN,lj5+Y;g@A,=V\l7$h&BI];RMK6(__^n\[Z6rLKo`oO\q-p/$q%AqSEB-X"A=:AlDR1lKCHVl.Cgn`4?5C2iS>&g)d"GQDg4PJ,1.ADoP36IMsso$*m!@4"Geh>QM@e]Xd-I"C)D=`:$5An$4sle" +\s/k".M#dG 3T/,,LipcSZYU%c_T&O_/HrO+U,IA.$a+=U GBt4BgpPB`!Fj6< &#:5M<??Qr .T[`"[Ag"O^2!9 DWIQp_/7B.t6+aA/W9DZ($JcYDAf+Ne@iLs\;P`/>C'e0o,0](Clf:Dfg@-F"`ig:*Fr%>HIQ#V/?,t5H4B<Qs^A[l%88+d<$'aMa5Cm.fD9:A=LAHbpA3^M%5=rcnMAA$pCANJ0qYil1jG,8IPA/4.,b/JX#nhUbM%Ynn6S1]*=`pO^q_dlCh7ledKj1HfCU8$"sA=<\K=qKAfEX5+*?liR$rUBh"W`p8m(**5--fCj?,18QS"?h5^iaMZZI'V_qC#JPCr.`&0Q=n8LmNemp1Z32eBO;EACRQWaIaj0(]8dalOb@!NV2!tkfsC?+)\'f783/-1Yn4lV7c*A2Al9*8:;(^JSd#W69%p$jqQKJs8L,fAaCLsOPT5=;+2Sq%VmEA<1h#6J-KpU$0A-aA: $a'NV]oQkk^(f?eAnQV&tVO&a9p)A2Vf.ata,FqU]$KsTf']49JId2t'R"j7jO^$A;?9:0HiEii(OrTP'Wc_G#2W[Z^L2AieEf%=k&&-a0f..E8?2gh7=S^-JY'KkHm;ABpb1&)@lZ!eQ*!QXs0.qnTHkkO/Vi?pGje3%^0`EVcan>G`Xi XZ>kheR`oFNGZ'#pRA4:^2)Y).tsO%g\YYK#n/sA2gO*?MZLNpFXVcY@R;S:X3;9hHgF"N_JDmYCE,=lPY+"&qkIgr@t!!d?I5bMd^Jg2 IVIA=FRRat.b16dEc7l-V\7^Om3 LQd0I,tsa@fG\sOMF%P-K56+\82XDJ445em!")a.*49s@>W6`j)>]E$[5h+b`-ji*Q! gCZ01k%VIBlCt']*a&1 MUSJ4H+AH(BYE&B$7JT/TLbqtY9%K,r)Bt>XRsk[l]^9G?4p&N2.5J)4#k''Mq(1/FnAeCZrKqWASh/Te^'+p>)O\4rL[hY)F-Y+X,,@"#J2m:a@\Wp-]VbfRRl^$tA\!)('E-KC*[K27;KbY#$*l")_lb'NtU:GX%n=[BX`.$6RN5[["/$pA^,H5/*/;WF/H.D'As+N+/6.YYhfjX-a1Cq&?6I48OVR*"tDZ=#p\&cDnbnP6Qe\tN6C_Wt2f@ATsR8]9[0#s*IUI>gA^be#nKI`4fl-]%0qXQ_VM1Q=bY1hn*,3UIBIMOF 3@QLV' )F>H>lfHZs[P[B#bRK_f&d-5_d)Lj\*Z\Q+aI#U)]D9TN'&!pG=<8KScpJ'WjU?^5&-EaU$aU5AK)E5eCIO[TKt[&WPomg8`m=S5j9lUKB$`i GK5+qcW/>$FKQ:_rTG6K,#%PWP qM4f'E^ r;<_\Ja4/2Bo%a:f>)Z`X?)]0.V-<-=fkPIe$tRoPdI1M;;d0&1W5T$^dWVn!CX&]b8@:_AbB1c_V+,_:NtkthMM6m#Lh/PR?VEqb&lrCXFC`O!6+`Ce^5Z$s83MeK2`Ho_.jo\25P7ghe3XQb.3bfF&+?#sGeBp,?"*KNh\1XUqdn>j?V*Jm87r%U+ZCAgeF>\(9SPU@GI<<,C_j$QjT>J3k +9`RcbX bL!&*U5Il$PjL&^W>:$=FcVZ'qg-8VGg17-o1"B:B@iI$$'h:F$5#We1rS,^onIE?S/@%_gc2oC_ AG-MnMZ b[i ,-#BG_Z/jh0;ebCkqCQef8UO"$M1cW O"Li;97/9?Z1bH8MaXEi;3aAC4-2dLtfU@_=>R:[Plg8NkJF<4,dXk\WOq)tSP=T^)b#G+18Emjt.eHFst,G`]Xa(GBJ=5;"/>;/=&* +'/3`Ag kI-[i*Z/T2#ZK'>7PaVO,kW[20(nU+(BqGB@AaZ<4:YdG6jUAXB0CVteK!7Tn0Ai&rq_J4>O>siC:?#FqO6n,NY\_;SElXKtLD7WQ+*/J_Q19*]D"H(nP4,IA)p(M\X`or6MdT?RU5d-Mg8ZU)FIn4Jn4A-AF[mQ`f.a`;j[AgZL>3$<:jcnWk/!+Jajgf<F!&Ap:Hl \PE$KX,Jd,bnNr<$>:;p3reF6!Y!$f`&68$COR <["a*O2dkf]hWRNjKkl2K/Ts+m=@TjE2%^/R8ST4?+*cSY`M-+`dNhd+Yn3d9GV_lTP/3#^LKM!h-j#0A-QJ98d8(DL]Zjm?',U=+O5e_$8E)ikIY\Fbc[PLVco8:NYq/dIE`bYm)0@7Y+[DtHrlTd[B?.TYG02neN7s=fF#HrcdSe#B'R\a(X%hKTUN>-Gl]VnX-i)cVVI4'TRSP-X3Y<7,K[KAqoOIWbhWD18$\*^h P]LL4s7*KdbJcX5HSOLjEJ:DY&SA,nZ]\\b&^r41nPIoQ(83k<:K^]oW940AVfHYIb`GW2,C.G9X*tPI;G+RrZ^c65Ar0lp3Ah8Pc2CAgZr=9DBe8X8JmT;7*%Hkb9tWg;Za)Lj(VUX.>9/XbC>GrRHqtJMLA,,Sc7X:<,SPAVF]iC?=7CX3(;Vq es8I8Yjb[(mkYc%"+j!hTkP_c+_K9"KLjHo_2)$^;:;G;B@`!$Q6(W0G Ajb%tsAI'YWIFM;gE2;05=$db5GT#s4i9)bp//Q*GT?EknHAdeND;ABONA]*fV&3'-.@ae oWH0dCS[?5DK!gqA-b)I7!6-&ND<'@i ``I/YqMqY-6d$QCGOR-IiDk93Mbrcrl4K9/mK*5MP>AQZ/m6_EEti,m"A3X [fY0f"(g'ZQgE+@-OBg]=U CN"=?1m5\=&h0C2G3t-a.Zs5i-PaF1;QnAAZHeio-9sq9\UJ6Gj =W^(rnNgok]mS>Fl3Nb##)6#&DVWKP=+U3CWfV ;?<?<+cZSpd-+3V6o"!j]p53_b3KQUP0G;72`'5_ipWF59>/k\S*EjnOe,Ep=WhR9ABBiWS-%?F.6NQq>n#6k<*H`8U^B88+:-<(^=T,5qAp.OW%i5ncXA'[#2@72_tArB3s?'6=^faQ[ak/XQ*bqmJQ`C6SLM'E8i^Cl`bp!c^f,_5=t)o;\G*0(U/"m:)1qC+JUdt02caN)oS(WtK$=pB/A%qC6:Y`Y4E[UK5KTG47mePiqFRacGX9,ps\M1sK%@r@S,9fV((ond[)ZL8@.PR_o+2U"J[IADF 3!5sF9>UJIpQn830RX2VfpQ@Nomt_h]R0#pa?lXDjhQ/ZqWjnC2T-5bNF 0E'L#-.t+bNE!:U_W/4Vr?Up<\Kj&/K.p@Zh%PAtdXJNA@F Yp4D55m\p]-[/G2PUo5>haQq/^^Yhl*Tn?Fad=jp,=Xrd_eN&0?8G`n%8X_Eq98n8O$hY=\M,[@n$b32JEBA(9=-AcX'H3BX3\Xs0U'9m\EVs[(4)&$9AkXc:(]HX.dL"Kq_mb^2O"nJ_A/EbFNXT9"pqsZ!FCDZ5sg%jm2fIf2A:_A23WTjS^?P5ei0iq)a/#:jV8C7-r;SP>M\c_coqI`W3ripm6No[M0W+jtcAZsPS+)BdFVh>#lZ7De 'ora7XVAS@cAC?CCs35JjCXb9'!AJ-D#2U;MO](q] ?jhTskl#V9O-gZL6!ad&b95Qs-UG5hNWd%a%C5B;Sq;;"A'P^0mJ]F`SfkP2aQ_-@BpC@TBV#DdfO7asSY'!De! ]IT$lSo-c;qS"Vle^I:k(Oc+Y4DD jQrFXATEUlm-3&3Za]Fg<05T&^!YLcL%<))1A&>1N.YT/D+):#!go-,+31P"MC;k0Y'p.<;CoJGo+a@4("!pX=?Y"$0E1Y"%UAZo2_]&KiNjH@*PKmTY@7I$_a)$1cP;OVU>I/$tG3RJ02Hq`X^c\_EMCX8Z4#q,'HF/B&KiY"IQ&p+$@:i )1)3/D"*m=2MHX\CX;mQ+]((C]`%$A*c.L+37:A!@A\66Fih9VRW5dQD?1'"t;fq3.lrYB@R>7Mc>mpp>g_DZ$Y P@VE)Kr.WAjScRpf:d+af_S39#79BfE00ct?DraP:=\l3hNQ9H9>3_Aq!lD^-ta3GZ\W;Aa7l&s`q1?"F\JOpAR&XW!QR\(AB[ X(t34Rf;1X6_%d4-20)=!4!TO8I.&#nl/#.P\CAYeHJr'c$b5EJio^a:e%m4tqZ$3H?%5r)E$$5q98rtU2-QbqXsLmFA`q7AjqOIK&X19N#beR,]q1>^?(Y*8rMhthFT1qsjsTCGFJ6BPpJCVZlWC>hpKt ljt#+1DDZGV@eci,19LnK]j1sA!g>f9G>&rDQVA7m#Y8a6;1q8f:3Gk(VAc8gKXh"f.YXb0(H4mc%#?sCOh#jX!/Qa^c]5@*NsC0.;WIMJ2l W/h2FWr'Vq),Jqd:Zi$:!eDaC'k;qG$1>?Fiq_hSJd."BEJFU!QIQ4TMd%A"5rD-*WAmR_BF;866s-s&Ns'D)fQKWrp%9Vq27(fZrjKA;3"NWDl_]WD+_Ji?lY"D%LRZD*7m+:(0UqS`3WA:;AG=rKUii]qJH[$+Cm2c;?te5#YeIjm@V@(E$U0XQ^-Tq/*V*@hniBiK$M&"3T1]hV3""q@-^7d+D! Ai5D;=k_t]Coa&&4UesRq(3!S5XQB"j`0B`VIhBt&O9q+YUUn1f'1GdoKk"H$&[A:bst\+V%FX1,,]m>k%b!ZY!]mk6Aq0aKQfmbA?`-"@&_si2ig^KnJA2i4)5RR.m[1C?IlAj6X cQl5)OGp`SE>4&=%)ofQ;O9.0r=.pcm)HY*AMC86%"g`2_Ac2n\?AbA^p]!,HKj>g5scI[8cL<f/$?!+5iQVL'_^D6WMXg6fE\ImXTjY2pN.aH-Q0A=/SNO'$F6%#B/;AgcWY%cP?14a`l=2BoFZk<`2R# 9snT;^9-*N3BG"rq q#R;K<`"eb+`<"ie:@sA:89MVQ8N4>2 9\UKt':KMRV7!>j*Hs++aWcJOOSg5'QcFV%E7"_I`k^G:Rj"rH.42PQ1fF00L`f#pJsroLXFr._M2]-J] ]gPaAi#BA7M8iB1e5P-FSl4j!GTk'*U3PnPZ)lQrQ\Z:EUS:9i3G87PB. GMM?=jr]=D4BWeWWtd.Zp$1AbeSIAr-+-GJDZr)g: k4EOKl8g?EMYqAmK0U&N7ogmHC!A,]kGG<>!qThP`+3n7Htdn9$#*WKPDe"Z@7?MH$6AiiS[RMsq+$2f-3:U7N"X"(1I?\="i]1(-JmY%Z/4%)^AMdk/n%=`%Nom@Nd13#(YD`(k0FJrFiI:a.F4#N]U2WcD@rkT!G:^k3t4DC'Rm8C]L`ND$q]WYe[5$m[4H(%CBe7.;,t+ArTW!=lTKmjn!i=_4#BdX(ds1#1Gok3GC;DcO5WF:7@BT7[Cqgo> B04p'1LQYEYR50PSsAE@1hi(*fjocJ@L),e>[3AC:_ )0G))l6p?05M\n178XlA#h^lpG)>\]DS^_D&mULnqgJJ:2^$AVa_lIFh^dkAPo[gt?C'B+H>,1`_gboi-M* 5 30GeG$5B*s:l:O(ZBeUt!.o#'^86\%Vjdb!0tQj5Y,IJ"(qUD(Apj-s3[2I]fM41Wj/#c@?HrT+J=/WlpU\>GUj]so=jIqEV5BA13AD"d#8hl[#^2siAb'[&!F_(fRH&%h@NAm3,>XE4&O4>f6IP\6%nTrb De@EYF,/Wbs3%@p@E$YHQE&Y`Y_D)g2@'/$4]p/Q#N)$XnatM:<:HrPg6&F7doN,Nen+bHtE4lJN&QT9fl^P>W3j&Y&Q!kra_M9[192YW>R`!U^!AS^62KE;=[AVrPK:i^_9] A)mU%SMngF]GZ D-Y+5S@HbHp'X^@*/V@QcU*>iA1dgK e<""`R^YY^):rZ!#9#=ApYQo.EkJ4.*EXcjqmS*:kQD6gYdi$.HBnsCni^5rq+SY\0hC=:t:UH,Ns9+V&k,Wt$DpSF!3HfAM^fI+-A*"9!=G^+hL9R@4XRG3S21VGfZ5a c!(:r+c7iel3(ZAIbQR>L1BsVnn3L :/Blg))[-&h`&IR6YGFCXBKV&G0)@AGTW7QY'$XC0/U<(W&*1R'&Ynk*A8Gnl]3j20ReM1';6T_BK*9h@bB k83;"nq%n]FqqBQp'?QD4>6oSb[4dm.:+@YRTFMABYW3eI.@<D@,'o##hVAP?B*kMl@cY+AshCHMM4UClWn#O4tpgtU1a*"5 cJ_Zt8E9640;C9AkBabe.0nZ%VYBYF8;kl`9^^`aF7Hg''q#]bcXKV#_@pj:)Pla@+ +!6A*no]^?$V8($RlJc]jXWj6]=9M61r*f;btbBT*(N5Fl<[ON+'4#X'hsGeGWpML5&6XAIGWjsRs]B]8'IU#-m$7i-RQ2HA)MqNU?/b_KnsYSD7=8>[d.)*SQs^K/"+n1Qe2B`R/+oK/3Yb@C.1O,>kG9d%=D8A2'aG6Ln-P7nrtoBE_;t$aA#OSj/#dJc=[X9D#^-#i1:\rjR3A*5aZC"2"bQ$otgkEkES\MoU%*H'/i;T:`f(n8:\;"NGRgBQA<.Z@,7a3R=;gZA9MAV6!KOH:=tKWJn)fdoSC=ttJ*N,B5E'_L1?Wdl-M]bGpf@J6'[gRU,Y#edf=T[($O:22\4Mo(Zn1E85:6lg4+"%K3`PtR9*R$tlCJ7FJ,bcbd^T_N/nA!7*QO\0t7JPSrlf:-Tn=q`S7WXG1;7d!N7a5<_6Ul`M_eTE0eZbfb0%E2])7@P3hIDkf\S>#i$Z*[p5>s@ZV9\q=n_O/Y)G;*^S>?/NXM"t$M@t'am*M92] \VEX]^G_XTfDKL4\tA\Ls)J;%:1E%A@8d>&[Am,:Ke\'8kZ$=(+K[s)R]rj2X'!ID"#VO.>Zh?L"0o-=pY^!=BRMA5g#ZK8-/:ab3:mo/F6tL-jb-N)At;%VA["R. _o/Wb#;5C_(NbF1F"G4N(oh`^$18bA8aL`8[>38W#c6t/dcEkQUoZ0+S;LS;G]a\>"QKCsKT4pG6dTVg@kPTZ6F$&*/p[c+n,XeFd6YiaE 'a'n;C@t".Bt*Z?Tb8A`2sErW0CXD:rQ&B?]Ys)+`St-2ikC#DD5$!LORR*jHj^^eWiQV9GF*EYnr.:RT<+^oe^,DR XQbpF\JalQlP2%"%Q9U(?XX&ER:`cSLl9-%78O7Ol3BJ")P![X?J?))$2T+395?;[A5/<4kqm<(tKhPGf*D.O2$-J4t2p%5OFiQ8Y^1#b,5gNYWsb"e/t[`JqnF(*D+5aD2!_"bGEcQe1V+>BARj*J:t*MR3.\WiSNg8BP53,knAVNm3:pD)pAh.JmTnC$A1pZ_$9VOs^[n26PgFb5g2 WWr1^#5TJ)F,2=R%KSp2J!)?Q_b$s9/?lNTAr4kb:/Zq'/%o%K>Kt1$=L5Nroj9_[3;.;+ld=j/a0kq.LE!Nfn?[EN!1@:GsOElhN0=qVR=ik0I<"r/m^ZVk]3.Ee_3;aACWCV<;0thiq]hCj\^3/eC*8Y^$RKh7^lBMQR40A/7P8Ap>4P).gUKPe2XD,f7pAV:aL^d,Un`am8iJ"+o;p7<(VIN"&q#g's^eQ1lj<G?q597IW]g4! F=<7I5A[,H@5GlLT"4dslHt[^Bl=0fT\3sY Bs",^K.Tdcj1H#Mfb\@cb33pkjI<'\dAk(se592g-ja-6Qj^(PgBUL"iSGhm/-rs1eaG2meF%8i7K0besQKi_?L@54>k&LhTHR!F<92ZQDZg0"GKS&9^eE]$7-fad7aLC=2]h.4IT'`XR(_s&#NEptr_h5^>5[2Ff@O[gNZ?\Pe5k/AO?MlfOmHL&jk`ei$r9hArAXg."tEV1+1F^e6WeTS`MjTM4;/SpUt,0&O+V'41Mr%%ZI^t#gk]<]Q[Epr$VD^00[rP5lA'OdjbU;R1FO&*#)e _"N/8KCEOi)QAWFl;47_k<[$PA0RR c)HAB52JL<.+TLp,!2sJ;,UGVk&L#ii!4V\mibWR3Kr6hp5;e0>]d.XHrKMg2*#IWT@6#f$JR>W6U#BnqeJC.iTePg9A?TE>cfs1Ip_N#L$s`X9aJN\Y^,2CTllW%8#r@MdsB^@7&MEfCMpFW0Ze#2!:S0Xm< +S]6lCPk9L%AFM$<.l:V5hF+eXAt]i>%)C8:VA&QY]q]Wg[;@G21#mO*5"3ACRjDO24Iq6pf8e,L_JWU )8_'+&O[Li'IJ#<&(IUnHnhP=7q)kf`2lX4m;fFq0!>)p9k+]a2 c*:'^,>BWlUD^W-63A_O&[X]Zkp\da)r !WRk#[j2H)N^4Ss>k3lVpgiLM&iSe\L4Tt"oO>s=Np)UqfAY/>LPQ[r0L=?5lMWFS03H,XM2J, VN,%O5&2@msR\m<(%sDJDPAT,`BL%sk@a9.sq7*]A;n5iHY^?&ail;J?0**s.^'C].*sAKEn4[D\Qg.gSg>jXFfX!%6AhFBt@mM<^8jOr#Ni6#U:icok"'d!r>k(=E*5sQkX?^<^-4R)X:!a%RCGU83k"P*:eNCCBfLjtA],k&+;oKc D+`slC\c.m8?LVsKJ*2Jc@%FC9Ql1*o%>!2hFqnKD0cUh/Ap(_4a!AYA(gf6?;L0"H0R#AM(Lr6%q@A#qfDo8CaZppKbk:H,UJepP'L" V2pLY@eNG`;m!OQIE!^?RABSLA_pb.FbkNoA%m_'F+;^&AfA@m]<*J?*!$NPKr-=Ze%kRU\gkn^gDsB0_?mk`QFsHcpJt3n;A`.0.5)5Y8NttXQ;]LW G7 b_3,XhdYA0Ak1Go[1j0K!-rC7X+1o;;U<UF+c]GFkWifp/XqsRTQI5PeL_1`b2]?(gs4b2PIBj8H$Yf?mq1fBcB3W8^#d90a2jCkkW&].9Dpt*)&3`=L_`i0UsGc8JEBe[HKqWJ?da9A)*hm%Mg!ajr[tm_V\/PK"A)4?>*9iOWE,C*tkLVZ^U-olaeOWM?hkQ2mFLlOfV5Zqt16o&,C;<p\4sI.a3-1n%"O%;]?@&&Kkb'do] r,Who/hQU<`Jt ^N0?d)pHl2h+,,m3o7\4k/3]4f78Y(=N"JRm0V1U``6Y&rBfgfp?'FG!bIFZ"_GefA#O.b>(LlZbfmbX N0q/c[@WlhTsEsWG&2CO=@@EFWdL0sAsk99o## L;[f4-*IE>7;%X+:A@F(=-U6o>nQ<#./LV7FPb1q!6aROsa[[\@I_F:/<2(7^TAL&8@Zo0ZcR.YO<+'cniABAE'>O:"iq<j/-P-VV8+7JALk;f>^=5NB-'3375YdeL hRCPe7UQXLT*bcA[13a"@.TWjViKS^rVT.L.`-o iS$!Mq?+K,Q1Y %%94)m#8g*i QMdVkn5X*1=`$&8jNs?/isc=b,*SAmYT/^MWA]"@SM(*Je7G;7QtkMfCo416#Pl:.*NkfSc]T5J;)!ff0m&q]`7,nC`bMbpUn\)o7=LTfP-c%mTPhm:?*![U*"5((V?8,FC"$3JL]7n`.>D$AjCl?Y/E%%C,+s7\Ee&Ch]^ m-tmoYADoQX6Vj>df&lXVCc?cSBbdCXEVaI-2;72PVG b$RB*iBT]\O!)tOH&fTbp&LMY bAB$3,m$SO;@Y>&>"SqE=%gLQKq@9A<%'_f6r-9V]`eC,9`!"6cEn:@e*W%tI Oh?Y[j9Hj#"t@.#K5tC<rGR=lk;8)rk]BpIS(8MCRU1c<=oq%&ra-'kPVc(PdFK5,ES"@(_I*)8\"M7q^EeWflUAVCDN\M'MJsTZi+kXPX)43T$.aW)-s<:#o8*Hq0MD1=8B23Sj:>J]qVVVN #A0/A#CMrgb2'slW>-"Wr4Dog[$-j]eo"P=Q-cEVCE.4_/'QR8rT+8=8T2h,A@'N/\NL8[.2K0T\;OS A?(AS&o2:S_TK+b`G:bm:e$N)[G=# ,@;\KF:R$&`D];41=E9aA)c b[Ks+K9l,3r>lZ%LBs`(AciUpF;A*$"^Nt-i,F6d22+Qmrk9@s 37'LPk3-dHad;Efkq$nJnleeLA$YIASX_A2)bq15M'1l@W@=7Y&`bqfWO,.6p/pj2^8/=C._bId'"Td*Slpmo9JY\@Fj7L"(YN!jAON2CAtF`:rDtL9b3JQ7\ZmWZ1LnD9bi,liT0(e HY);_0Re%r1=X(>fl\9`[Pb_.O)3TeSDF`+h@nQfA#3SZa@__C#65Gc]$6J2R(sBFAj)A+VL/"LGY5Par[F^bo!m=sbTY-&aa^;LeRCD=*JNrF0H[p0U1*U@TL=2]O.?iK6,$T<`@/;Gme^Wd$\nN_/b8Ra]pZFeq#g,t?D-V]M5$II3(^b.17rU:(%_I!:.j3M1oooLBP2SW#(V 3I$9CVNU4mdl1JpP&oq>,`mJJiIf5e@\H8i@IcP@8hk3]O,\;43*k4?'q=12)$A6>0DB:7B_el#XZ!U.5C ;/?r:qM]QbO3I&gA%#.RncpfG@UGTU#M) /SH+"r;Z(mJ+M?i]*CcU#dkn"J<4510Z.$YcW=Gs#0N:7"?0X9(C$7,ZITf$-1<(YV)i/8it@m;42Hs1b1JZnMC[t!4YHU] @*!q^3l;bhQ<F&4^(,TTgn]IP:Oo9.=?>sQGolboCh0L3oO\a%,eHENt Qc&R24M$j0Q;C?b^=I5=A.ZA>_j^GY]Ds/D"E(jRf@p%dkE13&O8AY;^Or,!?IYUH%F5k_oCpY#A"FUWrD*R9Gb8iJOi'HAKZ/2:RYhToX!qIIp+`N\Y2K@ e,_3i;9f.LMmEO.Pg\6b$tjF5[sQkd,3XHK&HqVJJZ'tUcnK\gikacet-hQlH&pPAD5TM[ehBh;)LL1[#-O.e@-*DWq?7aeI2;LG%UF;_QL*osn[`TKs^EqZ8oaE'#:p23P7h>HBHd`#R;9&tS(& qKeFHh<$4'tG!TdG[L*-';>+RKU J$aNR2O=E3I'B__9B_\BFolMh"6O\4rPq$f[mXa5'3Tj4I!5t!D1L4dF'rbiUdtFj!(*fhh`L27$# PA-YsF*:&o+7%AoK!"T^<,Jrp"WIr8BAB\mEBeg,&GUT"$k!0(Etj:T=J8W%G"1YGqYD9]P&nkg2-887t@d^XhEJGPa3RAeiAi9,Pqobp+Xi<0)h)BgrOI&YW=R(J^;;_HiX_f]aY_=8@ZQ4-&AKh*RjZB`rL"'rMnZf';Lr+M/E='=$VCmB)O@o6T/I\!Ut]RVCEM>o99`ZHXp]81FIsqa_9ab:+Z5-MK2ob:"c16C [p.IfG",\GPUBAA1JROjW.c,UpK,Dn`'@co6AQfr*G?TN6kgCX^dI]>Tb/H!IUWA`nU@Neb05D0$HQS_I`'Y4!dTl-&:p,+CX^MMj\W@1TC05 icp/=Ce*YVqS+ZHb)Xr*U[2(oN.=CVI[H"!;diAT_Fi!M)L&G1p_lR0NFYj.aB@@_X`sB YX*J9.9'r-`6C%ijb `F]Z6nAL1X/nUas1A%b<C]75JGGe,q",DDncIIX/AM2=,rC6YCZ>M@Ah3Bj]d@ ;"8DcC%orqsAT7)h9\QA=i4A+Ka)6sG,SY6X6qh)h$&*kLL^#&;ei!;()!dVO;>19A\iZajHd;Ihk)I?$orOYU:scq3Tr@<+&$E53g#k@;5WISMGOicsOOq_6n1D_Op4F:7l#&EhbpQO(r6r8aJlJL' d**Nrr/\bfhpI`Q_>q/-3M)!8b<seDU $<4 []6";L]3Og $D5SeY[d/Fam*c1e9g]qA:Yd<>+ZZSF[Y?: d6ri::(sr%,.L,8L;9O'A5cq`KI!$9b0O7A"\:Nc@3LYA"eK3UgBJ/$\j%OI_/D9<;2m.DUr`q4#eleY"&UL!AI:=8'g__)"r#:VN3D1#Y82mEA+Ubb-\g,AaIN&>?POXk#(94`fIfA%eQG!(A(;Z2`mFGs]c\qmY:nXY6#k5"<7bO]>5A?(m?^3PQ^C<>Yd;WUFRs8@D\C9l+ GS9RC/+R2VWe!Q3*X5=_sj!3PDC=A-?"SM_`CG#^.j-E'R:7:MVMW(TL>lO?l=M*4rgI>:052*0b%m[dOD"f AI.3n.MjLTn8K:aDTH@mTqP'qQ.HaB=?6L?b!ma5:"A=3tY5C)VRF'GIdIEa3JCfKWnQQB&^e7BUcZ>Q7?WIP.2dP)Q#T^gd0&AS-0L<&@4\LB6pcW "VsjB@0LPLMr 7qm]ga1--#P3;Wf4FVM;l]I)[Vk_^:IiW+KG>(,SZr8_%Apa0>SUBhAW>VY^3\JA\$$3;RfIph*9P\MbY9llP22N1%o^Y3oU2D#k)*W DCN&1$Y"@TSp+`4c7 ]t0mh(IG"/AXZ,D?i?_-%l.I#g(^#Z3%g'RmB4Us-T`G]:Xo'rE5ZDGl5@,]3crC8_:^HQF6h>'d&!%3['k9O&gFO)r7SEe=_]=6Oe;DaK:XZ%VNm$o%'>;M>q5qH8@DFFXFU^t@O8DQP-J*'"Fj+N4Ur5[?7h6).#+C[:J6I39>Di2CF+] Po"7*"Ih";gA/nhPJ>EP_9"?e*m3*UUAT##9i7eS%T[/m$%Ab, S^!^X+DI!tf?cN9@!t*L[2NWOZPRfc=Ao E$AH=\("8?oe15>dT!B]T<ro+:pAF1`'aH;XMr*$U;)p%9P 'Hkj?04I]Sl;j&$(,S3IC8,\($%XND-+i IPY]DU7s`@PBo?d-bfZ")mOi#$b2J.A3A]Pk<c;`eYeeN7\kR4>RtQRo Fb6G4YJcKB2-i^Nn^t7)dTOdC:/WlkR1IoW)GF^*:=YFA>tV94KRfkYnFApkbb^qLqkc`7 K5m4"$[\RIIYJ-Ys&Qd;P&RmL;fs#2=V1LQtJ[K10n+DYg&ig eYsEbt4EjPP@FsaUjs+^[<i4)Kh$2fe(`b%GqZr_+lgQ>idEMS+7'V)&=nn_m1%=G6ZLP8XTP'rNo>%[Qb4/4seF[&XSB\EVi%!S^SrtiD:ARnB?3As,%L@_OFhm"@:'/=N*A*OMESS2@M1VpaXTd_ISUSkUO@ERQE`SaJm%V0BX$#WAd9Q>_#-]SV'[:N_,_W4/BeP(<,PA+A#lQc+RF![]Xs#_A1Y3Dl_A3,kXp@OXT(i'M>m: +#b9+IMkJ?!94+p`q0Gbrae#sVoTXtlbmSFt(^3P,?jpp#&H/f#9T8m]UJKYT"N?,36RDGgl(5i#j]% # XE>6l$5^?0&kKs&9h#P-G?$q1NMUXc"Y[Re1,K%2RI3D q8?7J6lbG(>jT??)E/F8%MmcChF3Ie1M*d21#"p0Kn0:Hp?8/XRF! $T%-<0f8c&+DV[ZCV#+;a\c'<+^"e`A8+9!<03(F">XTr0,hl-+pZlKA(9a\pCQt:QtMjYYman]4nI]-kD@`kOVZX3o_`Jp#@\q+hJ58LT_8El&d8%.%=o(,!f&"Kca$Q),D<F>BJ)_FNob(/BD5Jp36H;.R-.(fE(^HXHeUbJkN>X(Rb-<o!=P5l,68d'GSP.OGs3O$VL5?a)]XS.5"j!CX'=A2*O.K(3Oe^AU3Q?9Ft0Llm1Q;%"4HM; i,@h':b0Xo/icY,ZV1"W B .c2gXih(2%D(Lapp>V!k1Lth&XdW-Afg$@0'@[bcA52+=at?gA;4W#354d(Un]l`=+^_'P+$pA/4&STiO&>t5#`HJs4V%DTF@j/.6Z&U>'*[da%>TkjrnN3\L.PS>_g#)Gk&fXrqGUJBo+7"oS?U5UeE<n6NGTUJJ3`1O:JKBdYL+oC _`^>'@A;Jo`;r9Tc#)Lep\scM8$--A2C(K?SZlXU0E1M00AJY+?XnhSE7WU?L l!S98_XBA3$ddc"!rtUcTDOe9i;hk1R+`k(?a@K1lmZk5:eSAo*Q&n>Xq`<`I/sg*Lg"=Q_VO0=pgqX1+C^rO-.V& :>rMD^#Mc@-!f--t:KR+ 3mC%[4&nS5!sC`E_W,]A?,5CDSA]i)k0pj`_ne@Fi9GJt6q-d]jJ-jh4PhR(KbmDgL9p:KakJZ8C"?iso4%Ar\5[!Um,i)lgXB6Xl-*U8V.Nm<%7Esb_`?*7tTMqhjqTGh0.3[%6+@dC8W+h(WlR2;27:a6_O$5k3gQ_o(bh*IE0H#E).4b>9bm<%NEI?N#&GDtP6&N>cV3.C"_:O.=!23?!?3LHd5m> NRA)lO3c/d+\1A[QB`C\2U+57OpQEqSc&]@0AX!d,\l: H sm<"j5'(d"[gHX0Y"O#`$hU0mOkh01NWt90&rAen9)NA.io5lq#do>peBfp<>A1BeiI])fe!\R)]1\"OC?0Fc0k 409tn!#qQe&N@*E[FLpPR3HoY,PS,%8A9_iD@Znc! Kp*gIhA*nI"`>;Tsr;g[R`1cmt6"Fj/Pd#gLr!=8XR\:Amg \")eFXG <]JL +Jg@`MOD7a9Xe)C0oZPBE4ikP.QT;AD=3#d^t3sn1il3qM)!2>\c$\12;!jkUftXecD"IYgtr#2tR*Apj$rRT:*-nUY5]T6o*fFNMq#I :.G\ah3sq#`7mT[;2tW;U(Ps(ohs8?SStj13fULZHM2&-[9#/q V\fifI8dq+Bj:NCjEpYa\g<1ef3>cBJ\%8aklFb4V<-A3CW/+L#C(9r+XoaMar ,C:t>6r[KYT3XC#5Sr1oVW=q'/@58a@qD!/X)AA_LrB?Z^V?j=WD)1%eD7=o9)Wti:`O3"]r+>KjIK/K+3+ki11&ciJ4+p>`lA#]p[int1`QTg1/K"d:CmhYG,h&@F3#>h2dZ$kYPIT#Bmq6m4f,seO5R)Xf1Fiq$Dk[kHP74lN>^mapAnWrCiSb4HsUYAYr++\**e-%UVjtfP1S7$K)Y6 0 &;OPXKY]L6Npc>SRHd`?n#A4O3[:tCR4*!;&DQ5c0`lL!])^HsDUJ #&ZO1bXbe1$:q;/Cf:bH57oUE]H%iJ6H8^em60DEeAX6WjXhV0_MiJ]tdAaH<oh,]j+P"R^e0]sJ$AWa?XnK]hGCsYgk,ht]_7])nX2*,+?3eSeA0L^.OUq6&F^[IdF%I#ofm;/J^W#N6N,7(>o-k8\6FSN(a K(6?T($;dRT0Po5\MJOXqg^pVOI[.W<8\3Nb(s9g_-P](("A_3$Ra;b_tSYLb W3RKP!_JV9],P.q!O9>?Z0d^53"Fi+J=bf/0RFnPa]'f"iY-g\QK+ir!K?H&MK6K'Tm:[>+j7P?/>mZ[s9(/$=sU,q787+2bY U#h8<,qnUc6tt3nJ[d372 (WA&*936B1%+9m_]j8m2-Z4OOHppbR-GXQq!s?HhI:JB/4,AO1+b+CtmAAS.In[)=AkLOMbmcD ZP%sqqHrj]F*BeAaso=.5F#BQm7[`h'3l\3Y6&!S2j+pX"]Ma8M; X``jhK(5<%Xm_(DbU^I@1m6qGk0`2hXH5T4Yaa/#m`+cI4UiGc#^Sdf .">A+&!A:gW_MVb-TC/S"c^r;9bbHc6TEtWemNqNn8bbDs9=pGi7A(SoT2d&=Fmo6W!o'haZL>GG`9+DebsocV9q_T_g03?Kl-&'WqE%>sn`4>cA?_@-`p64Z.rVFfH>t:)d#Pe7B>oK&Z1]D^A"A%2`kh#>_[&o/HXjhH2LOC$fW$I1(.?r@VIH2sgDa4o4XM(1VTm4^!Ra6`AD6T;U9d@$;tNR:]4k^ 5l359gf'b"AA&9)^.r!>hA?)]]bW5F>U&Si$ss'7_3,6[`]Acck9AC8Ca\OL3bb@fdQ=VS(G=ieci2BBb_jFq)9L8>o0J)DAL4<]VG'E\a!lI1aEaG-$(3`N 2VrDrQm+!>t_O-X`Ze2 $mI9WQ2T+U;\1P;aAgAHl^Jn.;-@TX2C.T2J\R9A*--2kjc_X&sk8r;^'$AoDON5=bbk6?1,0rpa#+R&?pGAl8f@_])G@lF#N=_ 7cLY[8JYO'k%d[XS$ LdF@lE4Sk%A_AZbP^7lZb62k3p0?XR$q74j`Pgc\Bkdt!3CODA5Et&8@!:A&Z7B4d3q2'ZH.EhAGt;rWYYo_e">WQ#417ATk%'Ro,pS5;`5'&E'\XK>2o&B??IHl,4Uf>95a)qR5F9;Z _AS e-cWA!;?Qc,UiT?iHdY)5rQgD*:"-:* /l./Q%&^b)_`h@37IGR*P)V0Wj0.RIS+t _UMJW)d^S[snLfAocTL(GIB6ts4tr3%Sr6^S&P8:npYaAlVC>n*D``6F)`7-pdG+L:e_e7MnrfSJntJ GQISBRm996%%X?c<l?G1T'A@'Ih!1hp9U*[Rm,Y<@l.:'.i#`S0,nW6hKGn'\):IB#Na@$,5JA,VP5DnErnN_\>tKSm0);?L&`D0E`[;\Rc-9c\ihT/;*9\j'(V"-T@#>lgS$0]^Aj04nKC$<9/D(2K\od'XbO(J5F9PR6=BGFp#3l[p"n30&NEQUe(OkEiJ8%)BAPiK]L"6eM7Q)VO)FE\bYk;*,R %,K$,^#O2eX7#dEKk>]5(Z_p\B_Al`f1HMokqnGU)L8&AWEbl"?495+.`>IO;o0$d32g=b%W=n[>9Bn$iaB=Lr[gP3ZU6;htm_J^EpNtWp;;9cXO56Rro-'13)&C?tq_CX[g'QtQ8fHeQiarjm3ha^q>L@Fd`A'Vc$i!FiSXKDh=*Z4(d6,`.+K>Kq`Np%`.4TZ*d-BAI#/q[Ns+(g(]0s:X,A08)o7ALtHHCOOL&@NqhmikX 8,>=;]!MCea7RC'0sHWnW'L,7E7'+o$A%t2Ff$$a(pZoc5_76#cs76&,b$n,XO;@M"5VRUld*"q7D+s6.kBY]VbTIQAB3PePkO9gIKTSVnZB&0m,AA^?_QRkk*\;:;UiS'6`N:;2.H85:h2ptSR`V24@ H g&F)&@T]A!Z3EdA\L$rnd &D9TN"hCrMls<r^MSD"7SKAN0D#NPe1n<<;e/%fhZHOrV"gLe$1j8Cckl=Ei0\#tpYJ?*pIXc7W,j7r-25<+K`7qh$,Q?DGdpNA7A+PhUiJ'Y9Lnad?8r^;^;t6Did,l4\5%jH[;fPN(0.ReEQfRcidVVY^lX]F:71LYqL;A`m$M*t5(]c5d'A8%"7%!r'mtFDUj.+g&S].*+?7^DXAL[s+/;f-'#&sk&Z*"b\pcchVBdi*7k-Xf\+"-#A-AlbL,NfbcUf6">]^*PmcEOGU4SKjp,1&(]?/.rqk%Jr:UQl3H!X iHpMOr4)0ZB"-0jMqA!>21F/h@%_X$&)Ze_R?_AE$YP6o`,\6&L@tnB#Ja$n,YOF1;e2AZ6;>r9+&IWK5N<3Y'5 GrJcp)ZK>r`TXr%8QWs_m80GnWE[L%geqW7P_6XIq!-'(imGMnKg,ZOUf='#d0[b#&LF%'kK@`;/edX)=pGqsjOnGG:467Vl&r4] SJ%sI%/VQX#K363QfJ,*YGK(1hHf@G4'lTTTL9>>[T%'I3>rAG-:r=GnFE41HgIo=&PT[^BWH]M-!;W=)Ad!.MUs@p#[:>lmd9&^8 ,T_iP9"Tj1ItmHC;-Ib'[r,l?RRV2$V-j[#;h:HK*P8?l+h,$#=t$D,%-Xo)t2#)RZr:>T[i(jlBc)E+>iPIP+6h<Xe\\5FDAX`8@]aGHjX[Uq2k`tb<DZQl3Za%Q39bpPI'RT?O[M(/UAdRsOEqF6A=6#&_G?aeNHYItHQ"Sat2R+jpA`,RB#H9'WVA(45m#,FAR9&*7TK-I$+UgGmA+R9 PC%^hcZpYmO4f%aQe^"a)DC 3@cb"p,>k74KWWML4*3Lq/#6[bn&_GsnLPMI-+cl>[mNdb"nl-$W']\'KaLPNA ml]t^WNOt\W3aS\7]"D5./8lS'5g+Q+hlZ&mm;OK;f"@%s]qkT1n$T6AHtX0FM^en7eIdsKZ<60;(:X88gEg1W@9f&[Y#j!;R_\7K">Y"35C0IXdi0O/$/jm(!l+nmON8=2T8fe&Tpf@YYJi;BrB9Oq&5gDl'j@9F4>/"5J0/Wg;ApWb::fBpp[B'MCUCsKnn#7Uhtp7BqAtS!9f(@Tc\>pYD& Cl&ZY*:5mWKZ3jDVXPZ2( U5KbP]\)#qAK-^NjVd.b#'qk>#F.Gt?ZK@rVt9FgG3mQ;iHIe&m57(h5G9i/8n`:G&HpfXLD:\g:RXg`P)X\k\V-`Bp8Q/[UP0OBCCMHY$i"X61b>q.Y^-7K8ENOXTF%A92nmd>72e FEo(JD?ZNYM80>_iD+1.R^H;pK=AAqLFXnDD>'@oV5,tZ6rpcpAh_F-$A(ljbg-bS>N#i5 j%dT6I_[?_$`a-*)tAjP Pf$e]ak1";1#G/\k)%+c[/3P7\[qQ:\cAE+4M>^;lACMfV$_d hcesHeX`,E7a$_?sIZho7V&49_)a<JT* s9EW8"P_\!"QD)_0\bjUYH!80P)l6:'isq!t4c(Fi6Q>>X9]mhD""gYjf[9K1caC:Va$SPl_KLHR1jo?Snk[R-l$`'aWrA@_Iio^_b!2ZsP^Vg_6Pr`8@>BdRtLp2_G\#iSoJiI^jAj3bm[=T"@Si FfG?o&r(?"gb>% =(jheYkR(BWC_H^Ki=1q-aZ=g*h:Ls! =EMTN[-n2 [MC9*d$s2tn'@0fr%KBG"6k784fZ Dg%OTX0PpR7Kb O5..q`kZ]CmirOg6$*Es#<5VXV,Sd1X*$*oo.&ak3N+g80Uje[H0$l+\1I]*lRi)6=h?T9FOHk+>)JT#a))fl Gd#/"!24O6G:6@PDQm/?4k_n7%[!Ei2Ap@VXmP_Agm9?=F:7WeW $NF\3C0%aI>G.ZNDQLQASrn(hjfH,.Z(kp@:&jI^.?T2rLol<;8o[P5tS#U9%6Z0UJ!dqs?(d7Lnm<'K%_)m6n^,IY;-j'OTCZS`A*j_^b-G'56kcZ'IGa^kNJF6#.=X4Y/VFIG[19(A`"`KjoTcQHfL9Q^0jkRNZK5I>'&YR#g"6.(A3nU?OIcnd+QL[&jN!<!g'`LOUoTWPO3/W^R^`#a]'En5)=N,?D;TmBitXdG0OG!JD=5;HkkOY>AVN];igf.:E*>tRBO:S[*mYjhPCJC)8Qg2$s+0AKeBd4(s1eZ3WD#_bVo'6m.)\&c-?V+f9=&A_j4L?9ZQ:-c'pW74U%r.m#DEH8f6F7H1BLDqa+eIq_cj&T]dr DLjep+oNt93$T10 GXAaL(Dsb(hT&(:FTX,OtVO\9I4#2%boc,0Gh5p(f]'bU$L1[0ZBkF#?ogBjUm2oQH]pTinSN":cD_FaEkA7_M3\*:Q)^WUREFZde1APMp`McO8pe^:-^Y&H9QR,#+n_JO&0Np+9re11>)YM]fYAIkCACaA\3-7fKIFfY7Xp[s\oM)f&*+p)pFXkpjGUalhQsV6iCn2iOBU"?19Ns7.m-_kh<-qI8OlU3m<\r;tM=]]b,/.]'%Lm*Qg1%jGlE4AfWh5TR,:nCU3ob!)XMF@^2%sJdi,@/Am2Pqgsa,nZm;*'%^XK3e9R!96eVbt'2GkO+s,%\F1Vcg^W"s`NR8eM$?&'MA?]^Kj<@nS75,jA-V,`;=V:=p*@L>_Th2>&7TI=,.m;XE3142Z#0$m$8&(!7EC%J<>+$t#-;-"1EVJAW,`AkjOtXb:;IaS#q)lDk6J_DZaJ-P-7?]MO1XrqU4ad)G.lD%aH4m[:`_Tg`5^=Dj_nNSfQ446ffRCc=9#Y.j%AtJ4l:+H2oK`*5;d9mAIl_J5LX$S99sY#TA-=nB*G^m3/#T^"sLOb4Lg6(nGa_'L '7$i;bdDq'j@j5ME_s1BPYWDn!j2Z+MtB8*Q_V#ofZ7Z$?K\)g2Nrm@-6S@C=^tSl)`T$bm2"p3jj8a^UlME$JD1#.XNRk/$,A^g-\nj5@>&!-mhJ*XYNKHps?' jG[*S"lgP$H"CGQT m"hkHk@U)N?"dVp!I(]]0$0;kc:)Fr2DsMXGZLWUFT.s&U@fk4$L5F*j':N&X(DQc.P]p*0ai)'5=^6r4,)%Wi]`O9,L`mPj,pJH)_S*IoN%X\[X'A+RoetZ*q4b<^;2I85HAbh%l5kgAJ8)+,bA1nL!H:8&F';1!V(6D'O;KDE&PhM8oRQViRNV4%Vb@Ab]qpP:Q^i6iqW%/'m&kBK:dd=j58ITNR+CRgI(g1.69cq'B+'+0Y[5[ti=]$0Pe9=7H>s$oZ,6,^iNoNJtg8,SkCjpYOPlSoZ3oP^KF-s1ME@)n?U*KtaWCpCSAFK?C*CGmr4;hCMd3]bLI2%]m*4'aPg%K5He #TLa@#%"_!KItS"4:;9lZEoTOSI6['*(_I^@qFf0+Kc=f3E.`(0hiK&C!jq/-@HQrk&8T*Y4\S!%q"-1H(_:-\nR?O=jKMFfFin0LqO9#prAm#%HHt[4jXK.XFEH?G;""Q0O\5>;jWL;5@c6E;`61Ne?G'T+Xp"-n7pF=#N=@@ri<G^jf oU\UK05 3*>kG,/Ze-3hB==Zs@:OY\AVX=_Y.UotK-X8H;Hk'\U3+dg?Y.W$_Cb=KUbm=j(AYc\CZ%82=JWY53$D2p_qITtj/.1M+:SGC/b'RJF67h7X=gEREg2[Z[9LRM$fRZ2RL4"r!`AYn+jVpPT kPZBHSJUq?AL!fBo`\ ToH1XVtBL0(r50hV['=UCt7Fr%@&e2K^5md;r30nn^'BL?Ra^ZWf&Bo#Xa@_FFUics@m[;tt)P!43p`hR\@O:eYqdAjmY-K7';gQ6Fqp/rKqYn]BsMO.-UaA$)#=-b:di#ZnVaSG:)*]AF]]q3L/0nGU"]2E]MLh-gp4s'QhQ0;oq3WOtNCi:ZQBf,_,"3Q;T&] XFgE'rg*;?MD3`*=N-7$#%nj9sUC%XN%,h#CA71ZAk>q%mKB0mO2n.I]h-1I#+!Y)n,R:rdpBbZ[BHlAV!q2cs+@PSb""Yskj.A81 A.rqFgiB6gJpSc.V3N\Nb&jJYI<(+%QZa7dATpLH'H:F^3FS;YdGY25_U PeoQbr<>J<+Sh(`$P=kcM"0nV\O#%lEcGnrN_=X<pG_^5Rfk@p2UPaY%&Q4>n?XBT13k=qq).!E4BsZ2"pqrGU\;l1r:re`W>b'.nrZL2I_&S3A4OnVW6V\E%14qSG]FQHi?&2);SqGFPZ)q%bn!Os(*`5C^(*>0`8f5.D*9CFf8,C3mMpmdn=5E!X+9Kp8'HHc [%Llr?t-,*RX59hS4_I7gl;;k;%qG4bKscD+RO#go605<^JCZM5pBcdA,oJd'75+Olr=aUe`l>[rL!36J" Boio2$`)Kl-=Mgge*+@Cssq1n:7KE(pZ,2$dY.AK[ D9qAKrjo; ZeU:Xd+q/-KAI&1WaUhsJA4i)R17&_1LViJ!EDpiILQn^sp*1"$s(^+^&]57\5A9G,rI_$&qFSKBff/)WBe!+6ka[k*YaKYG<0RLEA,t:_"g.Y5A5LdTWl"/_UisPLQ:O'Y8-_`.4&gHYIj!1#PfbL7M]g:=hT@M>6%1-t,!2*nXtltI8#X#<)T.L857G*F7JjXq3:n$5q(Ad(8>7J#H=4si+]U5\AAE2PP/h*!cEG?JM0:8_5aC1o1.cI,h'd8B%6BH:E<2"]rrfbOEZ+=q4t$@iU2hF1[AmRg@>t=r);Z 3+Hbd4PcHV*i@Nk_EMD3?Ct0P?d<#A:5W_!F+MG"&kK]4j]-Xd Q31oql;?O7Qa9t@bNSe6A%)hRO12E@VNcsSf407#@?#92KeEU2=b oes)XZnaDg[eh)3PG(*G>DB/:^GsR^-)WK<&BA1K*2i8gd6L"nn2 ,8Z4O5[B22Q0p"r=T .]Mr6AeC[qY?5W)d,72#0:\d]T4LM-2d1)>79[4qAVkE/Z^aSB%hq7@UL)iN!Q1=(-U+2WIBqO_RU\L$rBJ(q9oH53n9kBB5lr[D1*/fie8Q?LB\M^0dIih3Z*^J?)Z11k@,sa:p59]G""sB#2Q;LX@?Y%NBt?t8?p5FZWl_S(g[!U`oD,=A^_]3?8n'FeY(>,kqnsFAN)9nE>;YpIm+#\0lD/:mU0jDZ0+Q8BD+G'oAMtV%EC>FNl6Tn,714bS2_f`X!lJK0JikF#nqYP8DSi&d0+,%+CVq+V4pOd>Se5meYchh2-f4Uksj'3R[m43qh!'/.Z^3j]B$#CJZqjWb+XLUM&-a`^0)b>g2lFt3Ml%Z$g"D(i#H]4FbD E9G+BtjS?8[1ojO:";nU1s';M]F[8DTpiNP7iaPnr(/&1t,EW!f Ige-AD?U8EUET:3YB= &,E@JT;%7^rdl"-1A-@YLU%?sXNo?r8m,A[-H/2nS6#jEPYnV%?8s[ZEKI#;th?Gg`=[r!O=(PIh,TBX(g_14V[jS*oaF=I$]1sbg[.L^U^;gh(YWfco8K*Yo_1m:Y<9XcMf`cd>4B5_)2tP$jja#:\4!Q&4b7GY`NoO5)l:-NSdZ!odhsA<0YX:T`=U,f\%TD&t:"m`> M!V92(Df#!`WYAoBl/A#NLH"XGVXhdmrjc+[)dJ*dXK,\IGLEm)lgX-\MejV&!G=Y:j-ck52qU]f:?rkh:i7?2;1Q-l21cr[\o+JQb/1L2)t5^A(K(9BMK8ZALi4=<=tND"j]nXAgtA(i`T%!"+;A)nFJFVQU)$Mi`Z:1]_AA[aVB@XD>;h9_6WE(l2Gt>I:nBrLcj(nb@GM"7=g=S T\M 6Sqi_o/_)cOr]O:QDt@qk`:jA4tO^+:j#MPV<1kV^;k:)$;)_?,mGqe*AY8#Ago.k. #OY5g:>?g`$qSg+7\>3k:ak*qmj; gdGUiig&5U,BYiB?$QXWArV4Kj*DB,%W\1*9ES^lg^=HB>8qa4%Pol\nnS8*!r`%4Nsqr15g[*Sp[--kpIAq&^Nb91"\Tp_iT^&m='FeOUT&X*ni*rD\0P%LKUetBDK3A0^^EX08qjg+O2Wrc-@U"`M"3R291mG[$7G ;>pnbijT)6F(,$e?88$sX>=(P;!]7e(ht0^MgQ``%7KjDdCmVbV1SLTeWg7PE0g[:e0Q+,4VPfHg+k78Hm^0UO:Ea$>AV\hB0c\#Y3NZiA$i(hPh>PN@s_bKW!W_El%bNg^sA<)b*p66]'!R*Q9(K4'&YfSUHY>`J$0X.Q.m'j _%.LSMKF2 hcael/5(B=mNh&#@7pb'ZLR[41U60[S2L\Fn@eRM_2X+hGYM^-7[G-^h.^4m_d=(m]5DYm[g 9)kF0/=]Dog=hA`@.A!0&'kK'#l.2,T^qBde&[Wq2F.bl@[(-?d-,l>[][34(NmM8*/l,m/fjif[+b'7gn#A!8+H)tiOIfY-VqEbFZ_*d+(Gi3n^cWGP9"I$gpO)Tn\@m848(OA=mL'MLD+#aS^eo.mA0cDK@Ug5O`ig%s&b(t*&?T"O3RE;'g33#cEE.Q>B7Dl"&`\[DF;(RL8R9@%l'e4s$(;7Q3(Wo@Dg 1?GW>,B#9f(48d;E3nkY::p%B?E]4rUIIl/S>_Jm)dkbsPX]I1iedL@/lhDr+!)O_):A4=cK\S.U:*t%V?A3hk!"i-Cgl=KA6Xo:/DJ##(3"Nm(Dh+j>tg;ORJ.t'W;1=k.C5W1sm^T?g%slq,RG37+!"TtcTI$U3UA+B+=O8'F`?mh^5=beG\9,e^69I]@(&%moD-N!12*d]<.7Glqa!*ddYLqWLO5j#$QbW0oJP7XXJCRG,iXOM9&\=[HQ"L_I)^,EpN$[A@0&VdqbX`E[`UiCN%PZABVibPN)U&/l+h_E%h'%!t^k?NKmL9?1i^nB\OT?-_+,`*X4'OH8h%\#],cmg1Mr?M3elTGrA&po0n.XNh9Fk*>h$[(Ol cr-K S,)2mYCtm$HqMh,d(3$Q-Er+=6S\YWS'2tE(6">0]g3D.9*7t O!rO1C-g:JTq5Fa/>MoASLgTj9FA%b*%I\Cj1.jgkX?3n:,#WmA;@EUAEa&bJ$?=5(D.[*4F2ReSk8pq#oOWCW-k$1ks=hN q& (PUA[]iq(elgSlXbZS"I%$iOcin8,_h<*!@@N\raX+JL 0Ln1GTjgIj)d,8ZU#A\<84AiW'@s%#FZ">/ #JaU0hgBgGB0!Qc_RR&rQQh*7 UR3Z9@k-(lDP)XnsEoXt"An-;LA:*4KrF*13/-n;Q&[\U&X'&e97jkU',IY7AoppX5nKZ#s2JS_na@R6ZF2m6pE+%-"$6mt.t5\/:rcnO1B%KC@ r4sr`p0'RoCQ=lfNam6;^?dLp.'3SX;-pZJ?b,kdd;V 1#KB8WX4`Yd?ta$5CGBdo1" P+tR< ^oq-F=0-.J7Kj6)nmq9H>5(BWBc)jG%qIn*INl`TI/np<d'%:lf__o"[jOsqiWUa"1hK+"bA7`"/*+/6%?F$n,^rGfc?.&c\iFICkTtQeBgiR?_9g/G9:N$lKMdnpil^^p==U5)5?7BRiM0l?b78K"H]c%)GF^dR<4\tM"qfhWcKHcJHPH[i7a!>hUP<4<@19*b(^]?:KTZ+P?\/GE`[QMki%nfAV?A6l+(g(t$O`\-2pXCkcU 4p]AY;-+khk6PoZ>lUDbnGJm2``G<h@p$t+39jh;9h+?^4%B=VJ7^'I(_B0^ok/>K!iIe:rE"5UGl1c-;O@Z)ctM#Lft\65Yh<@c#js.!]J"c)jQn\GBaetQ[0WIGn$P(Y6;&:*QW38ffW4DA.Ah?;#-mJ)gi1YT@!fA?7`]Cq>[87HL)rgZ0hYj\<Nm$;h7A)M#PS?$Iq!oSjVCqpaS#WIi(J5=A^c*mX)/#S=%UI-LG!pl -(!pWW2#XiqffEASLdN,(Y*]FR36OZ[EIcY<q%S\?dC-]"I.,bf+rdB)RmB%9I7q8>/q+_t$%+.E7=XB`.PGg7hs7NiZm2`p)PM'D]*e"Y]@-a/7+)DAH[KJ%1?rGgE-G^B1EKj&'CE>-?`mdXs#"\b,P3LmFqOP^d7C:d,4OT2ZpAfBt*^]h"+Q/:8e.3AeW_9;4.fDW@]!!^!tIss`*le='i?_4.F=/L'N3(B[d$aQkA%4%+SF4Jr!AHRTWkLNlr+)_H',e:6sEWnF1YqAiDGt?(5Kgo?&aP/t"ZkJgf6CJ)&ER&^44_dnjZ"> @`1L<3f,*t5Us(Pb>bKLBA[*n:H5MA ;V='WQ@[iBiPFaWcj"C\=/RnlUoJ-HCTgEt>F,l.*f92ArUma2 3m5oT4%N^BS$=$_KW/pP;bL6E1lDUPM6$F8OOcI7I?.d>*E35",<tIg/JU%C/T!sWa4:;ohiZ0,mXUjpC9@b?TJpJO>9\>4R4>^8i=/H@%_*iXi!@Rf\akh(dl+#rsRJG]H)B5"+QEC[1ci,I8f`(QY+>Ws..DmH+/BDV@9PTTA5!?nKhVgAF?['JprQQEC4^@16rgRqELddHHoSl $:X3HCrr Sgi!AOG#TNg&*?r^o*Ms@< Ooi]j28T)^C=II-tdag0=:oQn&>)E-d;+mVrWM*mH1d%m@Jk<*'F$I@KJ>.:25Yh73gOQ!2?:O?2a=/(G#)\X#_rg35abm8rBj8K&OF7$QKH0YCp[D*ROI8F^$\"e[:rFN2J;W0a"-Zqa?;(Z1CU5;OdaHIULE$`^O^m=A5t &Q'\"0U#i\(EL,j)oGOKmU^b>\Td=.mn=9\EcLH`N9&jWAcsOE2!HEkag7:LefbK;MkAA_!h?iAWBN^Di_6R[>0n@[ FHg<_A_-&l:HNP!A_j $"]s`Q'*7dRl'd%F\B&P.%Q?L>q)\]B+ce )qT\KRgNNHQ#o!-e"X/S=(I2bDE3)FV&4:fKY:?&9;nS!RALA>q^\FBY'-4[>lQ,?]#3/8F3.8;J/FG>$0,mJ3dJ&hi$,n]iE5P?Il*"mr3FQ Po-=<)id_X)e/ZF!)qCA:#0Hlh9)R0L$P1O3s(O5XjCK +$QRLM&Lf#\D[tJhQ0g2%.Et.1EhW-I$@8PA7ElQFTX4 @Z+$[0ER'AX.T0A&m[J%F=lqa,sP]_2,KG6J;AN,EpcbjNpAM`HP,F2W%@,X(/9s7A1.haE4Z#FV(Ut ;DHrtNPr;p_V(@9<`YlTF2\`U9Q_82c#!(]T;r0&= kat71d";K$:+LnaWq))=ON$KV:rIda\(@Anf_Z/I:>&-k:i$jn-^O4!j#NfEsGh[#"Vq%5 qn3s3+)b(^.Xd07Qd$dL61bR(%V$D!sAcrh"JG'FK&r,d%[thtZ1Q&MgV 5Aa2n6jV+Mp"?& "i8h+dmKbo@<'k.trdH3P('@$-kJJrI7^.*$"Xl'Z/C#eQ_7@8dEmsQ\L<(8lqhf8OlRSni=T$@'FgGqBD=Xo"m^O8bJANBdn2$78Kd)Tmn.Gm.]f'S4-XCO >b i@K#>bL!a gme-G(e%-kbhB*SGXF(&bkF4M5[B 2ksLC[]j=BIm_C^n5oMk7>mXr><^?YRqJ-88)nH.lYeBA(TlT.Xsf%bM&i[iAqhD2nk#JkbTS.Bm tnE:?h, HONoE?+(+t'q29[5Gg7D*0"EgODHeaD'[O#SDbpNbO%h#Z6&7*0AW3*9%gZMk8C,_#4R*V5Z!5Aa``/PAcpnIc7)q3NakD44nF6.r\P(rB!`cQ#$>PE6rn,Q'jq2Z$.t@clQH/q)K@IjIV?Aa%+.qQ^o`6+`NT-Ac./4;LQ!"HJ&@)]4kS-dVEthjcMWCM[?Uj2l5`!(la4LYpAt120S[F,$+i]MY0q[j!bOcpABT<*A"Ge#%>>">l>J!E=#_#pd73b\J&81(+-=b0;ofqW#DAeENO26b=Bte<=Q:LbC/W4L'NOJi*]kC(<1A<.ne;_k2K'(KA!CN5IYW'_f>XmZ3J5E+YHf>66pe(+W%MeTFtGO2C^kjd;c[td7:f"JErc^WWW9P8X"EGNb`\P!3@kc`]ThN AYGM_6jlqXqj8RaH`BpnJFO2G;^ _A$Q0Ol#6 m4hSdOQJMfg_"j>o5Z$7gnSf%i:A=s5P`M/6*>oZ72@;0\\O\NI!bo0IG`/1l0FW/<@lnX6#\BVl'nb\s.l4/KP60orniFN!MnRO^2`l'KZHHne*0:lA(Ha<*Lq3,M'>&fo5';oqXZl.tbHU-`O(sJrsD\3KA^,LhM!:=YmKqDRCN^&^:L_#H2SUS+n0[(\SE?qGOYE\CV[7UEIkjR)bPsA=$%P:0jo%B67\S>F'D*Y(onLJi''3pJpDW^$Pd4\e='d[lCfj5m"ncOQ;FIGS+"*#kB#*.@ tW\Z&!rZ/116]lhp23o,2?=qpc"]3#8>$/QXtslaYR2e^A%NGOS6?^h"1-9AS%H[/tUH9NF)0cKjLAl?WT85G:_\%28?)cM#J)@i0ajWF8h#f!%9d68&O2;LHS`G5&8hUra(Edco^\Af_fNcgaoXaLH)b Y9DI[]_8B`=F*8"H&*)hD;]5O!DI?]VPR+`VE/.L[QFc._d!kJD;5.;pG^`7\?O(tsh$nn62%X>5h2j B1*\can[?.t5>:OElXG]o]BE2ni.m4GkL,#AM5(=5h'o5P9n sZJ))QU/]T!3ngkVGW2:Y\\=A2A]VQ'$-g]taXA8jY6@8c"He4j4ai [b*5G^>bRXBCo!^f!8c54&.I R!a`b C(<=.`Lhssq:nHF4m8`5BU>Wf(Fq/AnO:BgHbAXd4S@TKWFscj3@(8DA fCt3Ap7Af=]JYGcIC$k[#,%/jE+X8 f7<$!kZpZ'sT53W@@oTiKOi*9Rsr1Y-JI;>BOIqY]S34A:*s-hhkQaL3UCsK7eGVcodIqGB`P6\(M$9>q$OYtD-_`,lF84SFOAWdEcsW8p1fn6\UUoi(3iXNt[M-7'ZDh*ij_rhO3dr_V*E/3[iGGl:G%9 DdO%+[L):QVF%E9oo6_+j_o=@hg9c;nGt;7pWCA5OSEb)beNGrl7Go*:Ab9/La (Vc,CHTp -ed\QeI-L%^$'Vp]YT"Ce[HsM3"7?T#e,8Gj". e06qYPms`_'mp:AIgealhh1Z7$o5sD[o+^XjmC5-kaX]kGZC,0Lo3S!dg56eJ$*G#U+k=. <3Y149a=1@ _Q8R!DPMU^/Z-WKoDM0@!E5@Ja+&)`I]-H$3-@*_tMdI7;A!Do'78BOZ#9RXOGj0Hhq[#^m4&75kF tr&mo6OD,#G (Db4"\e0hJfAj!I#aecb4UEfl>.a9tA'T&O5X]j]I=ia3HB0158N'.%h"6j6Ip/g,nke$",.('-%UQYjCQ'etA(]lGP!Cr0aFO1GBX\F2;Yn?j ?DK"]kVYLb%\1XZab0n:7\mt1sHdf.pUOS_)#B+lat?3L:.T."\JbMJ,EPN^2 6d+31P,TJ:\TMRa6)*]lT6iG=B/W9l1)MmQP+oBH&&"Qcq4Ak+f$jphpbGUc\f[UZ@RXh7[G?O0eGJ AC=[ot6X5ls!ST!+^:`01dKna?8=_V0s#Lro4'bgM52UR1)!ACO4Vf>4'R:r=K-=6Y^j"RFjjL_R ij?@tpa(EQ%n5.B&bCY]];Qr4P;LHZSm2b)M?:0rb!f/C457tRmAq1Sg\=GtkG;saf9Ag[AS*qF:FYp7$rm;;ksPf3Re9egW>eLT_V4L(a<\LAGjmkD1(so:)mCI\4QYXoXN9d_8R>+@& tGbj*f,FC>+F`'\Ep`J1Wcj*3N8#nm;c1=qIi9*#HMbtdkJ!q4Q+k?VIQ(NW&nU]DEA&8pMTVq@6Orq;NQ[h6q=)?AEoHTEcQN?DYD%F8N=7F75UsA=^DL(* Y:odI+^'3"c`OK.;G`c[8;?c2[9bUmA37!/EEfNIQB*A"1#Y"3_._Y/'Ug&C_`&5V'')6[t.4n\<b+X-a[rH8Ci^:E5a3b XkAjD]&HWWVS-8/.pNM/n+-AMj6=1P>+>[qn #=A66c3'"a?_'R\QjPd\-f?c 1ga%M`^3;c+4RUe+8J]Qc^c,Ea6qR:1N_@#i+BgPD^QC4$@[7'<8Xi8^F\gEH7_,mHW?ef.$QcN6:C/?-W:]`RDCKN`d8GV@@R*k=Eh Pj1@94h%n4D#mA8Rt0O<(l7;R4(sg)EZH?!/(iS@WX`.fro5+$Bg07]NU^+S7&3Jik'IOK_ZfeGma;rK#$ZF-iPa5+d2LMWJR504_EW'/!&[&so,'GJ]NJLb2kEp'S87"_VCmXsKc8&pDg399c8Zcqo+(^9VV\-4QE'79ir/;2eI#HTb3i8nXX9po&?=i+75Cg$d8QYB"qAB0RUGUdZjq)EC)99>ednIT+rG2P5>/"l<$^#62@X.OP0<\l&tK2fqSko[-G5+WXG/4i,lt3m7j*gp-Fqg,2;DQAA17Qs\*:UZgH@MD$7.Yg+jAnA,_E$[ZrA(SbGGRn$P[ Pn[$Ak]Kf1tm&e"7\3ZgYWh+Dp4r<`'ha;]^34 ^PTd8$Fd[_r#L*tL2S(O/TG34Te\7Kh%WSk`CocYt@2tI&0YIVoa@#:@iq#5"gL79n$[Y7Esp?b-3Z+QjrVJ1iB&m5p[nZO&j\7BHo@k(,;`>b@A]b)Y:*C*%g/ab=IG/^&W`7eG?"X>\"D':(p2`D>QANkSke_V6MeJ3X4&gB,fes+mGORj3NApg34f0\+L:%JPm\PA=;Gbh^D\;[RM9rV/!pB$qNAA9sno2"bCM\QRA.MZc4&Q`?^OVQ 9'DLP-S,'U3la.pjBK1\g5Z)i>)S33M& T52iAlVo0`A76jFEimi&aafI7>pOU8]_SroKVeW. ,lM]!(:Zf1=V2%@/"ZPF:XF8TXDtAC'&rc%9T':;oLIa<&P(D$MF8KDsKMAGig]UmRaIbOnP?9.Yid]s6::3`e4[H*l0Eg)\At:J#o38<4!>Jb2/QQNE*^9An:I%-bm,)Ar'i?0,So/k-G)S_(M)sh>TqJH:_2T9n^P\A>g)[Q:`L 9X4[k.#X424]_oHPg.faGtb,"!s8\ PqGBae+V9R42d9qQ$#GC?>fTUd8KG!VIAiV$MWr$aMAf>,e<2jfgkB=i@\;CD$Oro^2B=FN M^o+ n8@07?E!`ebB^@BWN1?IR];O_f(sPdLnd]6n;5"7?n>2I[N2L?69OH.>.iZq6&`;^iTaCK !?Ai@S.1%n(A2\$;/fJ!6P0[YL8XT0@:Q:i]C*9E[-S,t=Jqchq:UW[AKFq%A6I1R(F0,'DT3UZe5PbG*?FHaRoBd[MNja0sN@4@X2_T_Sd.^> 8Z]A(dD>(5K54HM5@h"CK:`F/4='/0+bgQKc >Vq]Ff.HK*Xm`Lg+`L7mk%1"32so5Nq2j6W8d%.QnNZP`t5eV, U3Jln$]5^5]^O4lT8@SgbpS"F)7'p?SYAjBSR Q`opb$BV`:"3bt>WM%_CT'(Ap3P>i_ C$rbf47bdK760,a3\&EdC_]d?:\Na$)_5XF;B:_ENnF&Ltd"XEF[&0JfAsID)k!?*21!rI&:Cp?/tkUh>:&:C6KAFqCRQe3h;nNtD$kAqj>4kJ#s@L'YCp-mRRZ[R^p^Z,BUq=6=`9+!)&5AoJEg*rWK]nnb@)'"/S)CsYO-X@5?dq.MF[PWEU5pt5F[]W[M#rZ\Isa%#;KeQ=4t[r%K)mh6b1o04L]N8jlEB-*F8gn5o$TcJ>T#%;1Q',oiXOQIi0Z_lm,Dh]&0e6+I3Qeb9O[YEX)VB*K\_1_t'N;nNc*$I_7'0l-_if0pYIRimXPt?ZGZIs<\>Vl4t]F!X4E&(rEEV<I'1!+9: S$Mg:/*p^'SN,W4_'-mm+F9b[pEa$Di1&jU/,n&I:H`\6"=!Fit"f+W^Z%s:b3-2D5,]aeD5%[a.=F50nZb^Rn$>o6Wp[Ei^=+r*q)(lWCFrUk 40p(TP#ATs//KMZLGDmD3G9nF]A>_E+*bfHq<nB]hO$KUAYS6%B-I:_]CN1PPN );>A.A_-X')92nDI?cj^nTCXE+J]Jo\"$=Q`l-,.blk58Q3N<$X?RQdA5B6=B8pEDR6:KH,ppA=jJa+K@n6^bn$'$O/)Y>J?c$$I-d,#3j^]j80Wt41MWs\?WJE,;COD?4ms,oD.sIRQ9a\!i8t961pg^r4kF)6VXh%&Hl9b)q6K;`hc#H8^n2 )AkTmRhAMi3I"RWbVkaFcN=+%5FYH[*>XUn0/b8XsF!+f^5/0ZfClKWRFbo)M5tjDPecUD2m=''7eSmM/[mLm!r[f?JmZcrkg!Lh[1dUfN?dA@)F.J-9M)3$.Y20n8Zg`3!(UGd(MW(!#5ZTk2.M"2cSaNAOAUktY' nW2%P$'I>U\FeZ [N"$%gr1Uh=[6AGTHBICP3:\*l#_Y0k"Z+i)W#8i_:O a9$IBpl>:i(VYHQb=`r"6 _fW:gmJ[^6*`E921NAIAZO^#7'9Vb?oI&.\S7c%#^#opo9IXehk=\0$T0,G%e9#82k=g$S&G%6N#^S@rDA!+rrf1"bRe%AL (FOT^tDX"( `1?C:Ip4sIW(W%[>5Jh\UWaBn>X."Kn[=A.c7#a"C)<:kfN" 9JLLN_S@aRHtdj<[DVF"f*9?)do<>pD;1kP>]0Vi..`S`,5.>9fq^pL]A0`k3Vs6,]857=RYbq@!UHV7#9\,F6f[O8Rh5,X8b!*h[.&6o?BmZ#9/Z)=[Ff"EK@J`p.i7?7s%BA+n6$I\-VL0agqa7[42#t)+a`/-F(Rs,.6$+6As/EQAETU`7_`*NQJaYlW38t<[FGQ,\S2*q!7mZ]E3a2[gBgS.p=`(O20#3ZfCMTjW);J;1_>6$@ZdU &m[HUg>Q<tgQ_!)k_QE`[%.ZUB9]k>^^db"&rlbj?KDiifhg/ZZ_APqgXga](?jl%0\"OeGm?l*& ",ptA&]q;N[%KIrr&p_YC/BpJt>aANfsB" <=<80jfO3+pc`%iQ[G?YO6eP+]>d?nq"5,^/b+ZacXQa#(/!&"bCEbSqpD'3WPdblq$F-AJi5)2(B3>5`jF[9LDU@hh6=q_?L`R9H3&:TSj,hfhNA*J&%d2[eWol4`ZW^)Y0^!M8UM)Fcq<;610>oIQ6/7GKALd+o.:$:3kqk)Mot^Ne0654ciIqn%h+O@\$V9D+tt.B pB!1fVL;MUGE`s;(<\*ZK3'.?WPO;jH9K[/G&>P$8Z#-&E_i1Q(^(>e+;[-g0PD&.AIlFo?\RFs!T*Z?#W7aB/.+4oOgQd@].*bW:=T.qJ3\j#%5^!N^a `[!tV*dojYTeUId.kI>%?8Q&5Gp#IL'^Tsct/5E\imT>p*oJL KO#5Dr>1.1mRS2eKJ_rZ2_cS+c>rs;kE3a<[K3[T*-%R^`@*W1eL9&_&l#=3NW`+Y^]KVcg]ZqYG,l2Z,j.7,[02J^J]!oeoG-5:U23"5Od,da430\ZNXIHd.rJ*;jUt9d>(t*L^GPkX]ce Ya#NC7c#MGa)!7cN)j5LF%&X0?D@Jn%*/A"NAV$G#mI-+mj)#/^ecY`^!WKfRk[)Krjj1ARmUip]/P#qG4I9H!<]*fVBJ)k*dr3,gI*\'M_bb4C8`ip<-G_ngYq,YmqEj,$oYIi\#NF(>ZsEZ"JWrfdhTGDVP6tSH?`Z";]:gMo_QQYXA7I4Qg?Z#tE>?_t)*t](SE;r;J8cS3EP7.@3p'VJWPL,fHsD%eim[CThlG&SH>eTd-BUo]MC?D=gptat:;":Q(X;YG*5rU7ZHN&[9[!)eRGqnV#8A44nOnh(0Q#+G))c-nQl1Wm/]t4bfpO&A(p)H_8@!A_!rP+0#(8NNa\53QCFI!Irc\#NmmKX;AX:haa'Xl)haG'N+(A@hWfd'QR(Xql,mX!#OA.-?k&Zl)HK5Lmf6&Kp!!dS[fh:rabYhCSl#c#B'F4ZZ-UZ\$5XJDf_X74K]nr>T+"jem!+*`s[Pq'$C$oc'/r=h,'6!O*=3.1m3.SPF4D]jS(X0#&@ZCo)[GG_?`oddGD 7s/7[bL2 fN#KQ:7i:B5(2q$;s=n#^1"c$,5G^6$`V!H?!I%/M.t5n;;?%rph(p0YP/[heg5E,:o3toP@=.OPOPUSnd%RH=7k[O&Pl6c&kYdi^%Yj?"FEl-A>?0isP3KJ*=k$--I5Rr:EOJWo>1bA:n#($pV_7VoIs)GR2[p>C2C\p5A0X]o J?QjNBb$qIeSQL=@62^#QhfA*aYA%f'$XRl5l9gh_G,LRb7a7O1Zg_;r&A$tA\PK&B8sASCYObeOA=(FACKH3!`[DHfpf1\JQnEb_aOk@UbO%?'3-WfSV?b)DIcVD^I;eAU#9`ZH(rp!i.rf0tKF[aO9<,A8#or;^g50XfIG5;t:3<)i"gG9)7CQ5;7MLf>)nr9EY@kSD!Uis*c0/^Y[aIYBlKoX#sQTP4p2+]$ZA1;ZmF%b.aUTSi<"*+@A?G.\6d:EX2%=1PfD'oeF!UtZ^KJ"3JnSh]"s^8M4* ARL^S+oi.Z5-$j`6]%?H"gr;YNAr)-rNT!E6MgGkVN>8`9e#$ c#/`"FR02ME,e2)ber_C8^$#USH:EaV )pi;h=oT aW";R&&9B Q]P@K:!1(A&"G?]L4_c-j3lFVCCqRJo*<$3$!R56l<^*C;)1GBl.">LC2QnRi"AU.,%2o;E9>F.TW4rCOfo/.iH_\Fk'T9b3bR=T06("Y=C>A%7JNc(`.G":j!GCto[aZnDR2LTk1C/,A$%Qna7/lFEjJ-dHFf6c3`2OQkYBi"9m"YZf+,Y%.&o*;H<*=r0- UT^ gp^c8J,5cgsUKleXTH^l?kDPC1 =*l,qpe@n>0enhaI!4A?OR6jb.ja:/ qrO(T;_9iTMME!F/]rOD0`%V.]BpcQfk]Po:)0kN;)d%.W>GCY/gjb,#Ce7'mCOW2FKb3Ea4ZJei%:a@^T`p>D9Q(;I?U;F7(Q!eV.$(O>l_q#olXJ!=B3m_N;0QB4^pjrmRp-4.#=#)Xm382Yi&8jA[-a!(S2Mi6VZ+>Q lFe ^h6P)_N+0nsbb9Yk7R+FI(WZE8\nN-.eT;105'(^QCe_E$J4e\/8ThAI:CU`R'&>HPL/pt(n"Qd\A.5G3r_>th%lS_^sk6H].jfmTNpsJ=",8$"TStbUY#&8Gc-q,Xh4]h.p4YZZ@>hm8^_tZ[@AK_h$Xn>47//PMT@Y!EO=m49=?CO_;(2+nS`3AgXf&][c_"$N&BUpnj+SFhTQ1aCXsZt&WFpNl66A&2V-Qt(&&""=IfljF@"'&]Peg$ik5L%TKo)_^7m=H37bb2(pOX-APf_IlRmiAE#c8*Z4MI.bJ1:``C@pSH):W8CdoSE#mbo9G5c5"b!VC9IZ\6GqgGtAAlS#S#U6"kE@+$`P3YC$n>J52S5t5P\*Vt=Woj.->>WOg`d8:iidhR\F`Th[l?;m<,OAag'DY_DmXi-asq^VA6RW=lpHj*"3;J_dN:(AZ>CBgWC&2tqrf]/*jl%:Y&MtK@?>\Saf.>:cmp(-\n9K>#5DCA$!_+k4kJN'Th]3Qq!dU2Wd!=QlT&n@^eBd#$`/rgc1`IYFjP1KAh7!RG2-%I\t"ECc`n6t5`sCgjHk/rMA5])U\7hMGh<(UAc0RP1M*VaqH9A;2XY.s^s8-KeAH#ipk+5@U*DF4`#+h"*,>3`6[cWB?cGR-TehldI1#E^88TCKd\m7&IQ=?!Tb;DM_$RI/&8;Sc%m: V4o;3[48$>5d0R\Wem;+US0E)+`G<2=]Zb*L$`W0[^dN^N1jQAWEcA$)L1sM 4YIaGB>9,e+4m4C1_[g5[s-S_5#L2f-ZkCFE@J"l?s1(&*":A-X'Ki@B*Z?AFdY5jlk5OaT,I^aTQd^V]iH2P9GY":ph=P4oLi-)3P&[LS3"cA.85a Vfbl5VA`#[(UDKh[fn8+MkV&B?]`6D3o#JZLa9Sfh0kp%Z6>$MMN.!ARk$Q3og AXd"CNCM)&)669T76A'*lB&A".N#Y0gsJ A3sc #/cL"&a[dC;S9$.C8R\[Tg`Rk)nmt @AD6>sk5+6-8V=]F"Y5`Z-^L>(2Q0_ pcig6GKqho0/5dZG>6.U__ S6,!L) sp8eYZ;F`K7GK-]ViPKqkIrhM.AT%3H%eH 'mqa4bh>\.3P)Cis(/;W<%LVXeQlQ5lO'31IB_&Ue0`<AdoC&s#KA;A*1oGdKf268licsVtcpU,5<#jnr*O`Yl_fTAaMrlPDU ;d JH4g1]Hqan Y*"qWsiA[0&h+6EY .D]4&<d$ t5-T:-@/Y6!A]7;@_#k-%]A`VO`h1gDR A!i>e#eCRCSsC8Yg?gRP9rhdg:@g.H!X2Ab RNKBsQ=>mde.t3)7&m#DbLG]qkm1Gr_tAc["br-7-,3#r];%W$ 3m>>K%JgT;,!@t`IH?]R9]CEq*k)At7Q9<@nKbX[8m!:OB)BWP#<_AAO89sON[g=LMBk3](F]A8\RYt[VmMs#,iQ[)eC6JA8r""")gW?Jq#5!AJf7nAa)R,3e2Q?cA`nFp"M^)kO[))qS6lq#%<8%%,N7A`#Lk= >kAaE``=S,r"EQN\3JMMR)bF/8!Wf.O%A'MqIg>EC$s`6%: >3]pHd[`hZ ,,j#dH1>OWPkL6'^HNb).YhY16B5&s:!k_,"&%A:!ZRpNfHVTO3q<\QNAt](F%K,B03a,MYh`k^jreYh&?NCqF_H8\99 tWpjJJZQVqS?p.!-:NrIC7*[7g`dqa.M[W6i#8`I80ie6GGY+FWfAp6Oep^\=#=B#.rA8:X/=d` rP)t43i,s^bKkPBS4G?_Z]Vhb=HA)+7E0M ^V,&^`c'M&kS(r6b#ft(F*@rYg5Zb%4.gih[+,r '_V)d07/8(d7Algo)GEhW>.g#jhJ\`C\Z,Hn7k(41`o:. `9 pHBRGA0q/%<_+43_2)lB9gjFH+OLjVa&:GrqR"$_'m0/GYKA`FPio<Z-#+1qf1/2YLSUW.:L<+ti7k^j(tVY131(Yf !Vm.&^rl"=OR-`hA-jlogkW]M.k?UD-2KlH`fk"Zh,@sOG30,e]#k\4a)47S:%)lhNd2-Olmb,r)hWDW^pq6t3](2('jj8V0oDRe)-r/[mfAHol)'>"R/5U"5;5lW>1RDc5TB7`gR<(%jmgVCl+.dLpmsb-t I^&@.lA(99NA=eL'j[ZS5iQ7(27&-JjCTlHt&<4r;OorA+Qr/1-3=jc'g.*$`Ap>3)O'_M"h6Q2?ghgsPrJXRbA8T._&_)04!0k`ls3/]AH)Iq>s&aGK7fU55GEQLD$J9'W3'.`i2=]F7q)8etEl!B+M5_Yo1bN-B6$79"0KM]CsnY6;cqeiHNdO.9J"BI[;MCo>R!rDX7T;*9[_ \s&=*p7e7>4L'L>knbW(n9K 45(T_G[$_4k3Y^8Yof)550FJ9,^6 #AXiQ/tekn]OA3Q_IG\;nbP^-@!EQP6n!h]`-AV*6Z8kUQ!g&dL"\@C&EP cN/>OB#AdfA["=OW]s::[WLCfiRqa(9;ldB[REY^Ep#//28eMZ4<W%Df*q*D5AM*-*Bc"9?fN67EQT%'6ZfDBlE[KP.^V3ljM3A%=?,>+/-P83Mik2hsGoB.a 4dne AeO7i-mqXo g"LQb)4!G_ [e">4Rg[Yi('P*Km3K\_=1(4IinfR:<Y6adAG eir?6UOAd'Be_bM6""?H;QAN]Y6leN`6TX(I3f$::F/ra@fAjpA63Yc %2\3rJS8b;qsC@]c)UT'd!A:Ak!'\i*P1 25WDDb'D)b^:so`E4l=?8F"lpb2nAp+\eDT21''$m\&l#h\g+%"R0lr8lfk=94PLDH.IoSBf,;]#nK"3kb?Z6RY\s],LZi_"Sd@NAI_$GHNBECT-grSAOcL@WX1,'FDeT2XL8OK;d-,L)lP,3\ngKVG[Riea`tK2rist,D&OfRZFD#p9]8CqpYIPq*n)pUEMW- FEpiW;_(< <6To3Jb?RdV(@1j?r.$#2^>U)#AT]+t?=FcB/aO1h',8peaN!_qE'CM;aLTPF(pF"b'`kk[*G@%bJNKU)=]#?FpeV#28^Ffb,1+mY6<8J4+=$M'!7 =_"1PP12";)Zt*MT!V#B7coB0lRHT]rLXEY+3t"-oq%`gV)1IEs7F?Y,67h%8@6,[H"ihY9+5:sHTNc/qo-esI"_nrmHUZ7Y$!Gi*k[.TFrKaagJ#.ZYc`IZDb@S;$R`T([%\otr(7'-!-8_P/?#1qX4e<^==3L3codji\,sAA\)"NR^]KX38CDA_ZRk9g/*Rgd'dIU'T:UREr*9C]bR^"e)&Y6nC(fr]"=0?QX:6ldPb8)\o\Hm7b`:k_PNBYO(itiV"o./S.s\Q0g(!@%qKX:32LDk^S(t:MBCXA6NN1AsNU7_-)@(He/,ltg[<=IUe6,KP$1APhQDl*O&lpe@2At-@SYUb0%WYt6-,Hg!)>DV3BDO:9I()T/t. dja7JL;Zl3@ )K7@*esQl?.:8Mq"YW@DisKkf@T:jA+<\AaFYJm>1d%;m:('"A0aP`C?>D7 eN>JIfTEIAS1Q@B4kRn\/`4JId3a&'^,\n0XGE*Zonfp$1?rO3LT3Xol:O`46kib+<\F,ilohHRS1?ElmM(#eNE(!'Ip;L3O"t'lr[VhZQkcDO\5*,0d]1PD/( mf bcoCVi2chgQ^I%J1Qa3I+[#k&b;Rd?PUo$Nj_:*[`pPNtob%3Xt!Vm],\`G<"[AAYl0n$k>dQ[o-SNbQ'ZU,<-T" Y8Zp15qL@=Ao[NY2M;rAJYMn)X8p;c7o6*ilL(`mXG:aH3KO oh1=t_*QZ8?L6Mrs^+U9h%O:b^WlA9QiiRi'nZipZ._VbMVI$4rBg(R5pG!DD$bn=2:!*HVUHE(4!TDZO(A$*knR\hoWjk8Gojroa..Sb]Md;t>Ri49_f%8q6(p0i1+7//+5P0Y+lso[="9V?)#\'mBrihJ9`0NG[*'KjpP(*Q9ofL^e3h*kb,B5YJ'M$#^P>&Y135]ci3aD"d&9P,"%5"_YUXpO"F83JU))9PJk=?tp(f0.AO7SO$K>B4AIa8IqNl'OYbY"jA;[7n%Gag_9W+egY.f8(k.h)q%LB@G$:#C1FA2XM0>TkgG$kF5[gPD#m&`je4[-'8PrCC"VL!)sf;7E5Kbh)r,&kJHlgEAS\-`bqlN]0Ya#ka2*Mi;K+@EArBZUIp.E>NBh(j`U<+-ntk>t-QmF`Y,jA*I__nA._k/S"U[ql^[Ctc>e=Rs:/oE7/i(6A8^c[i6'\tlQ.q[#DoBe[ZHk$ Vf1W5e?g2f\6bK*SSYEZboDaLqNrBB8nX(sIU+*Ca+!K:&/f1_`Ym9rMWU.e,r/gpt;_4Pb!\tIW"m)f=T>UrS2+ErcW=!#LbbR3h<Cb(`3n(fOSX2!jTA!i9\K1K)AV]12k!!Hn2@8FoqfBK0)5kisTAbMb:P"^HogtX\4q!OeF^!G,c;boDYB/7$#cXUV,+0W*GjL[3o\#(:a?H'BqipVm1-sDj$=d>niPS#J>3i61;qWL.aVmT!a_qA:%LZNW7(]=F^p^D$$cELa&_e:AACH0D/b'BMaat?hrA+9tsc)66"5OsRr(ckAUFL=TgA_4Da")KA0@)1gp#c1d.P4-n*ng*.XG1f.=\-;(f]\s"sE#sfSX!gY,?]sAjAOs^V_&b4c^?i=?iDjp7p%^[O+jC$Nb@l9CstnbkrQAb?'tRRE!KJ?+TtQ26[&eU3KW(L7`L)O>8E-)GN4H6/X;Pg7A7j,$]&[?KLq1* o[o'mI\iP_m?ECe=AMh)Vd%?os1eQ9#>+Gn8$L%dAkV=N_+Cb2/C9h0j$)i@]VCNeZ;d^A,Q7:Z.?]#DV6q1SsmMT$pqN""p#`5HjbIH2^((E*dOp\UFAZVKkd2S?FM=n&[nHMJ]S2*aA%WFE7(e"tQ!0T()5T]?F[RQ\R?S[Ms8*-G[fP!_J<6MbE&cY=$;1src9GdkKiJ+ZlR3m?M(;Fe:<_D`.;I HI !25$:BS-I<^1SPj)!NEmJccU1`0 >o-S!b7hZc+C(.=k(LI66g-"WP>Kpn^p`EY)T^HB?nA[UW[HMD6&,qcNb;($:gJmLcLa;mR17pA0,I1lBj;sB4U>?t>'_sA 2<7&`HACF9IMJ?HlSCGbng-J[$dG+&ntD26WAINnS$ A]_Eo&;AJdci;W?kUBK JbHDU2=G5Ef#hnf1aTo\AsqX0nBCH'iF)sX*->7G?;;FSkT%]^U\is?>BNWMXGh\in!Ld=b0g6OS,41jpN93[OQa,1.*kNNVYc`IMI?gX_3YZ;ZfF@+o>a^JZn+W6P;UN0U<.WdE4)=s.m6_%4fQD&t9@Q)9>F"O)3*oS An?632I[`68Gm$rdPAKMtHb:dU)R2DX#mmVB3GYt71=dDX.D,kLOnNd"EC9mP%S9Ln0IA&)MMa C@1.a+:"J)A=>LimCYW(1t+9,4h\./VSQHRJt7f4UJFn:HY7bef%/5=-n=;=Ek$o[Q( .:-a,fQG5TE'dntYs7hClXj!)CQ20gEE,3B4^hFrCOL$;id=;lml.kg-]dX0[ZiJ?mZISK"L#H=4T^osPQU(P/T.AA/Nq=oh4%n:m#mKM!D;QsN+1?+E^>iC(5$9-K?;J%^E3m.UIL6WZ>i[bY-sDtO+6_BDXm1tZ@%c<`&b,g 5XVjH+AdPTWB"+sp#^=hX^'NnQ;o;<7-c_>l]%:O@&2ei68IoJO0+h#Sh"'0C)^1=-qb>C)SQm?)ac!5DHA\c4sNW@KQO]c_FBO^B>5B('FV0`?C36-&h=ap6 ;KHkY'28PtoM00:m_!:h5AK8<^)O@&27VPRr>s5L6CFB9ZssE(ZfTdeGPI$T;hX#ksB(D8OY[:7_8oD;` ld8QA#ON4+:oi(Q75g]Uh#'YfDJSR "nVWiP$q'>(R[-=Z8T#WI0rWo&k;0<$\9F]B8O5!baW)45APX0PTd4ST^J[F5moRCC0InB)/t7Qcq'tWL%5tX!]Q)E`fN38\8$hGDg5AA:)e9cU;qGf2AG'2Wfqk!!j.SV2EYn6a'_Ors;=[F^6D5B+M&9Oa3J>E-DAMA#[q4::0jp[l)h,:3Y*IVcb/"pqV(EjehdV:&\X&]'f@ffj4P;)'W Cf;_2-C0Ps_tJ$@*ZeV6)LfY[a2U.m6'VL YFAG-)?-D<`8!bYab.GE&AiTj?*V(hAsHaqNHUN&3_M%(Z3.@NB;%gfi0.aH,XVl8UTlG6gAlcZsgYM\7ZoEb+</?@ekqFW(OB+m&g8AR1BB`NdPmTd8FD?!9*NHZFQ(*Hq5kc,/oJ efAmpWGYtP+QHa#LqN ;bGdUOep`3&Q*:NafN6@+-q)%l=Bh(AjZjaIsF!32;'aP31I';WtBo"_DEk<#?$54O4mOH6YhRTp\oUZ=JTEfDo9*H@I+/A`/H$)PL+EVM 3R4nR1^jOc!_^?`>8KBMT*]QFP4_r9a&M-A/MM%9&Vqm58C;IJPMR&!nXR,\6'D'mFfh(TN+.q#$=k>T?5t9H?$nYX:@=DEFLVkgA:'jM,?dGG!AIKHp"$0!KA%2%!d;(#\TG>ULXZ]'24H?Kq-hK%Ee]18#S$nTE*Q$m;[-:@7GI]r3$#bNg26YaDRCdb1H&G[]@f@&!#%]7o&J:RpN"J:Pt5M:2;Af00/b"F.7!?_r6gHYI-&&l*42`PqXHAO&cK1S q-A.dej%g2r_N6UPcZAj'/Q)iMYQoWA!63at](rR8BrAmc@5 g>XK5U;H8nY)jn;jRV$p.%cAZoJdZb0.U:dba+h,[E\Hhc6PF(h]l*!O-%"kg9[A3pWJT(CXae412[=6,Ahng7YjQ<>VoYsY>;?.56aQBtL,B+c(9:4]43_H(T--b#jp38=3k]5PJZc>mN81oF\,V))#F!FO8pMD:$BI,H2C\n1(U[r.G,2."jbEj4"h*G'5CQg"*o-_,o9Yq1"=MFqm;enNo)2me[s@t.b1,006:h*-7kAL!,dmGB%p3.[dh=meVN/,;r/n^Are4-1`MV4rN$"q,n-M0s[K#J=@/X9JFr0/(gle^TC=,-22CM71id:$F"'M4hWk9mU<\GM13iO&/+F'>'p;UlE'M$X)i2^')8V']\)W8i1h'=]!;D4sMj$7fO0=[r/O;G&@%:E]DJaKDVX0b;LB>1H7\r0+C':R5aq1k_kUef.BhFW40Y1^AN!bM][3j6#88q33ddAoQ5NEQ]ZZ<5A=(/cN(5@UZ&7aZos:0 pdrGQKe+o!!c !I8N0Tq7N*p/S;Hpcp6*<9ZEG+V%;SWHk%eQ7hU908p$nboO:5E'(Gn'BG4)&E/6C?OMF?ZW`(lq7QCfPF89#`\SE-q2]N2nstM`&iN_ '`f6Mq6&8p+*TI/I.!kM2c)Ibp+iC6Ll\!iB+2gP/7b)?rM]IHA0AXAo4"3Vqjr6K>D&\7N]`j92l9[Fol\B:l;QBr17S4dP,X=_US %]LJT$;ap1=F"U%O3,AH@YfgaHMP1RJX(P]JX_A@E85Z9A-MQ7Q4tR_htI@LRLoONhYCn1kpqIj*Zf:>@iD*9p5Ag_-7ea#&Xo,![+3nY>#c&fAjY8qiEjKl"2fC"HU2k5Z?(VE]lc2o&$N].k9o?*/;TZao'g+`[E/gpCbgp+2[B8nDGdtiqU1t)HBNMn4Q'j;b<4k,.V?XIQbon()B8)jnL$)s.JGUo><)]=+#Ha=+dLlZQ[<$Hg/@PD7fAi).d5*Z_F^jk\K`7&9#>W3V'1lE;N!`N-<0-H+R50#A_GJVdB3>@g^XX`4iI3 KU\6*/:BNo^U-YAlY0L`(BS;EY/rHeA^m[]t7^[dMT!-70VfUgS5`W$mH"OL'h5pO2640 nVA[6'rDE6sDJ5;U?[52?Y03-h$jT#6K23$;7pDLR\8g?SNojB!VLtchs`MR-75n.`SZKf? ?+4lTFJ;jE6*$mG4'$K>BSZf/=5c/IK&&Y`MARfqg/E ?[3n+fd&NKKe-HkFVch+[3ojgg?4H [5<=>]Pl 4?Q9Y\4gsUq.AGsHP3G(#^]6nILm;9dR)I\sH2dM3UVKE7l2aTN)7:iKG!$PB>`Er)j7kP:HW[0=Ad@p_(52`>AXOcgkr0aM=UR7!KFs8Q@06JF(.0sSM-*#Q-&+Qp$q=JX3X?O`EC4eAtJ7fP^DFRR>4MT/jnZLqnWafK\VL\!Fcl&j,?;aO@WCJ49e>mJ=]d]hD]qml#mDsM4t'Kj9j@@jWp:kmmoSU=7Vm"A74oA+SAe^JX,K&H_7:^"i^->gKdi-UZSs+Ghl32NZe5$7:^Q7WaiW[8Pr61_KI-e,r ?%4n iag8!+,Jt.A*:COLpr_HK$;_ga[H3E+('^")O6n]N@#:;dl?]09dbH4g^pS60c^9!>RF$PioDhJJb14(oF\AbC&2$JlC(;9g>DniH(`tN'>5aqA#3[mT\9(F&!J5L3?F.RU6M9;'=q eV&>Y1%d]5e9?ZE&7D;>B*-QJSr"O*WF\S=c(qe8#N4FJ!7lCIpn69-3B;W^+6l4&K>;^U-R\@b13VigD%Y.a/c[N?d+4-TRjI,k`m.LfE##>#lt27lgCeL_>(Z\W]$a0Oj-f+t5/rnJc+dj@d4d!H(a3DK9lq7 .mUI$^/HTDL[GncYFbZ& R60(<C7NZV@sA$5>hmHPd5FT5$[BA9A"!n[;#) (n3#5oC#q%f+)65O =tR3\(*dIjm5\)WO)Qn+6,D9'P]A9OO-V^f7Sm:__ $=L7SgZ ./&`hE )#T,R$mE"Io"_VLU4`qjO)fQK=2fS,2!MMY?9]=;1Osa^T rQ.OA]NZ/<@MWrQ4)".Z- o1,XjZK\3EB75DCpL^pl8aiUeI9p1EcH16ZQ(^V>NiA</,$R\&J9m 8I'qh4l>OBKadMKOl*#9nhBa`?_:+I]1@ssK`%AH&JhK>(L03mPfr# J534:BkK8 ^QD"=&),c0%-^WY1ZmWg8Fn422;M+I0UZEA<@-U'&A/`2D=Ni88)t\+F+`l569P/Z`7R.k=ei2;CLTo:'jGb;"SaLdBqBHm=d;O!5Aj MCsU(AKW7US]9e"_9bg,s:??4VZ1-6HirJD"67_)%Fh7MAN\S\BDSbY3rmWT3k39I0329e<2o;0`:W:4RMdp;mN)AC+>@=chL?8+XU6t3`iI<O'jjBo:,RC5pMQOFpY)9c06hS%@<"`N_`>e2hL:Y9)!NU)97V@U(tRck@5i+L,r+iA`9@A=MF%1crm%2(YLX&.ZR6IIFZ$tjZlZm3l&1/[.B6Yl8Ug7V5m$;/ >EB4\>MOL<0%&@d21bOK@_XNFh;H[J^hQN[?9b8(QG7AeG0NmSAE"LC>?P!M_IV@2$WOJt,O#0D1BAF3j80&)Rfn)EbYX'ke4dER48p*VRiW"3'8#]Yc#%bU0bo1)M/n$r\QF13hkF^sh;4KC*^[QoPi]MpQNQJBZqm=Oah2=GJJI^$HcK\d%_e7f$6=mP\;_QtEX/_J-+F'^%4Y%:n06T]R]^Chsh)Y'i_mBZ^ib6^A%aP\sFa[MNb@GCXC/S]<'jB"jG/)^&@@_ADT^bht;?=t":ZOi9b1lJQ':NR@gU%VA0ROb^[Z5 #Qk5%cldRbrb6$j$C7.r8p<Na0r)^4pWN09k)jZ79g*:W"R[\8PGqd2;e]t5M8=)46^I).[CQtVofl@>?.q"pm=Xc" YLPr[:]nh TK-qka^LA5Q=%ktd?W/cK!old>\C1bUIL3LeNoFO7.j+*Al6'MShW0ENADFe7MZM)1['2tK#;aID%gH9oZ6BI:VUATCX2K%(N$=i]]^KJ$tWQMj<="YQc-fMEJo<,rnQd!0LO;CdnqdL1Wc] .n@Ni2psT5BK38n@h'%PW,XRq^gH#A=k7t;4Op\]S,e1+mNgj(:9 IEO0$T&X1G^-CU/RoW_O,F(6rN<6J?SB#GY%;c=B;Glb>mm*&XI@!(]!7>sT7&m_iqo/#QNDkj\p8VTmK@$H;(9CWojQ9@ejK;`nfgOoYbH>E'MQ7MT$;nG7Z'9)^WflKHU@:Y4O;5I\FLUb5t7e:gkN"q(EOdOrehq&r!ROY3j>U;iTK,p1sJ7s1?4jN2-dnArgtpW0D+eC<>efRa_Kh?:aZ8$K1@ABgL_n,kgQ:\n*%tW;#CZ1'c)Bks@W;'5P:hg,iJSFcD$P);k=6mh#A:c/DSOpG9./#iTg57o7rU]Nt,2KN4rW/'!gVA"KgN8U]_irJQUP)7`oU9_NqSfZ2`dhX,ctR6T,gS,S^78>W6hiGW%!rJEdqX)#jsk)6(^M#cAp%@d%o]4dgqLK]5d@jg&pt.dr)`$#$WECm[Pp 4Q #0f]At_hMl('aJCsA2S/M3jiG.a1d@c22R-WIb3DX&S^pK*qs-(.TbG^_/E/F'_=p;U\Ji-hkMS0:O4.&i'a+9MObIlfMF?\Qd=#A$pq;N+bh6j>5;Qh>$5 N!dT&XSAbADW4T)`/;j,t%IK=GA\SP??R/f9!'E%$7mK\tcioalVe2g_FeSCE)qLAstRl;mOLhksfHc>@d&\h&FsjdS/n\d@aDA_PdU-_%fV>3++RG=qc>T:(0&_G+9U;MXYUK\AO?H+s3D!R$OV]mYT#dE#g_RWkM"q(I\AB81n7S%M!VB,O\6)l9[Cl$ F["h6ARRBHh/At4ah]s<"b?4;fL[9GKmc75:A2r\0'CSjY\ ?f@o]pWN)Lo::Y,-#+jtJ`NA7`[8Mkt5T5hqeAf:tkTP[K_,GE%5A'jM>h3J@h%WG5oVsbDHOr5V9V+Kq?iY7-:EQ)8fAS<\s3WlBPJO7O]$o@#L@.bC&hDoW<#!.8j.<deSSBIlfMlFMSV$)=XP]6_r([V2O\ddm C27IL+'0ifqoH"?/,Ji$R`$!_tN4=Z\^BU&!(PKnsrC8W$*hPSh!JZ?:j5e%A/YVOL?[po`CD(-at 4c#FcK-NZ'E.V7+pq,(3OrT$8%E>e37o57[BeTJDYASSD!^;%ob5K)46%67J"l.We*2nFE_+Q[#2o]h7@AKg6QCZO@rFNT=M=,"'fF2inBMKam-B85$AT6$0ARI,"ndV*_nl7"/@ATWWGg:k39m(>t.AWg&?f"3>/Rp/ahL3dtB `2/$5?1bYrhmJLfcMKte`@/n ;s\PnT/el`laD&EK"5+(3,l*jjPWJe(E7Ikt9cJ0%Fc@mm4c3s^AaaV6B,<-O/m`>G+(.&:#aZ#9-4LM," NefR'XeH@nc1AJ?![jD]Ct+iFl[%%TUY_'I:%<*,/&hC@cWUg-2(9>91LXW^WRb6Z1Mpp$-:l[ DQi0AoqIoO`]b[G"Vn:+jA;%kO0-<5Bag=g_$P\tZ\Ufl!4Cii ;QkA\1%*dY(s(sSHDMq=oX*gK?G>A!kST(H.)`!NNb&A>'kY/-)&n'UKd',g+4$qNIQOCHPYBJ7!80Lrt;"M=>5X5G$;DHMNYQrdj!jJjQt1Y!DI?Bq)ZRZH>nCk\c44PAC4^5PLIc\g.285(6$?(c/!0j8:NCC0RiF*k?AT^qQatHh0"d(C1H4W8P>>B:\"^Ui?A\d(YB mOnh*JlA 'VqmWe\0q4-=QqaMbKSI45>A,Z>_#qfRJ#[:c^r\S2+6le^O/TCPFI>HZ8=/G-548sSdom(J?C3[$25 @:Oh<;JJA6)#$H'B+`06\Pr)o%;\`#+FA@:D7CMl8."5'AU5Y0UCNL](BA2b`2 $pHjf\&jS4<0!`nLbYrA eMZnU`,o#Q.[: )3-IZ>^(MUp29?DC.a!)r7#h^d,;D1-coAB:U;=))#Ng!GP/>"]q>9M(1`FW0a#Wr$7"cB$>#E 'eDCTt]3.FS0roi2q]J'B(JtbZp-es2]((SleEpVd4,B@X`=n,LT_b+/I;b?K )<6CS7;lA/*qA"_;J:1O=mrAgeP&JekLD(Z$ffEi5O(E79KWOfd]SG@7@\\NM$^nV_B/US&U7s"kM%G'"K!&?gb:%Kb82?&'"*Dt^bXt>k9E'h,Bl94+.Ns=el@F/FC\1-sA37Aa&<4p,BO5>LLD/c2N@01M\pDte )*nCBEAN]bo):3V r8BdgCl Jq6TUiF[>CJND$=UnJftI5^ApC))lfM#&RX*lFnJ'h5c@/WQ14=GCl'6o=;No2"C"JI/TgW7SViQ/(cjX>M[@.K8?RN([-2HrgS4B.@A^?AP2??N`")AN+U<@;BRAOX5=9<)\F/B!sid \]R4qV(INR$/o\*\m(_8eC3ki.QkkFlPkVSK2?HWAXqMY5*L<Q+V:HU=/[P#l*TEt!fUf5..0q/;ANor()L]\1ZR9YZ!^qaJt4dWt$AoGk?B/@jn?;1LDiLXq:qX8Ip`ciQ>87TOE`ko<3Dr-QBPV >cE<1T([B4^_CgZ,4LZf!bt)t9iVR(1kWXpj3-rrq(aG_SZM&O=-2QU37V@gQn@Sn,/!HqiO-gccspXsa1$%e, ?Vf'5=@/e_,ItO*U2`3mYcqB^eZ+#Adk'>A;.&2osb[=ZEO@^U#:ifJ<;GgZB^o!>D5Gc^/Hq9XH$KVb=A?c%DI294lh+]p[^cDj?&J/CH>p>,l/_1E#i?-YZ-)._(QrZnSc5?KekMbBPs;]SmRbJ=(P-?I!AedL*C@,$dqDm%P&*/*( g*qmb%q!nn8.hs\;nt!UUlXRVsAQAE*#qaO#Y%E)r"LKQNJ@dW"EfX)+\Xf=5.TH3/>dJ?9W tU9s#&CHsFT =c`3DHLNJLkA1cJ"D>aQJh%Z+I=h^rE>d1VW7'aH]]JG6I0YGaA\I4_.$q\b$R:pKB;n)m>%K/0l9LG^(bW1$qiQ\NbYONAA%c. ;:PFQ++0-E5P^s=7^MP8$)rr47`":&$='>ihiFb/>A^7^3UO39<>#]l6N[%B8M$t2jP@%RBeVOYO0l]pOnrFAN&oO:7o Ts,gtoYh7:\1!Bh9)!XOeCHYE%9C8pB10HZh'L-a0$c3AS=r^a67gCNkVht<`c_]f>R4ZAitLW!L;og%CIJ*^T9RsA,q1:c#X`UI`K>kJdN]*A"qD#1.Ua/!FE7e?JEj EGALbU2cdRpPf&=$do/?2),R]p 2D(HtnNsNp-J+k0V;gb6l2;k$e5o:JBCXFf.S)SHs:C/![2kk ,cjJ Kr2,Qt@$$t:-qhO"bnT3e>GFo`K+PbNMO;Rh:fKEF b^T7a@'oJ+a>"^V2Zk)@J`@N^pmAq%QWQN+!+M+bt90mtZE0 `g%qYf,qqqpKg+tr6`aA;Of*\RbV#Frr=&+-pqWsEFAZ/&ToT/sW&kO_7Lt4FL-UA:phLq#DbcirKJ;:J!iUhKdJk`Iq?!8S=dGd(kA8d;klrp4J+:88cXMP*\1)m=,E9k=hd6*I*90X90`?JA1dXAYfX!D16fdaBiI2gA'(;n"cBp4P\XCih-r#GAN3R<%V0<q2I2WtQn8%:*V2D!F@KPQf[A1`^V*qr7U(D%1C0t hd!_.2J4'jr-]MrGV+bo'"EoM:^a3rR^#fm*eQ'T$gA/d'Jp>5c)Ad)p-E(Kqk78CE#O'\:KZ.$GT^d*>)K3MQq&G=R]"2OGEqP%;BH#9<f.r!D^/1tj[ik8tIpRlXq@#7H8R3rJB;AKNR;68#k&"1O)^$.PB0(p]pN$R2i1>-%+i4*lhab2R3M5=b(`WeqJPG@;KkT,dQe)M*WF>&D_N*ib@0E#,[WS(Ne3YPtT -;'m-BQ,jbp'eo[pBjAF>f#h2b+qRd>%^++bN`P]?CNq2Ks$^/XnGO3@G&rEp\_&AX7XH,7!gr@**7'BiS)pERcqFmntb5'[=Z"c/#p:(E@_eZC:p?kPH=o:1p@3)J$\A]q'*C]G*9fa`jeSZgj2laCfVS/+Rgf9=%S_KB[8,l[@`lR"B[o4mBA-dY!UM%Q2c=13AZZ[6fc1["[9g\"=Uq5Dl@d4n^K:'982?V909L0= Y\5AlX1V6$1m'%]"ERYJPnT)Gl#/Fc<]k`/U.[4;cR[b)j#q4q0Qpc=c$eAr-5V+n8(\DNtiJhPis3:@<.F:[`KrKL8W\i,[1].b((pCjbj%LDh0?H$2Z*)J+*Lc`jQZI`Na.k>`PhQHNn2A=OJ@cppcMK00LPg"L@-WWZ5KE#s_ldV&Mtf)3DBA%!#?1I@"`-^E^=!X]4AVDEQT#%;70kd_4V"dKX!j^/UfH'O@[*IHC(b]AZ$ZhLM/X!0/Q]Hj*V%k0mI(Y8$XOn\.qIn5/e)B"I]#/Da6V\'O]QkN_G)[I=8'Y(Z_.RqXB/)[MIAq#n& +nm qtG6g<`OU\iKY/dQE6D5kNJV[rJ=8[(S8T$Ig4eIP_Ff),`&Lp!cC phI)oG57]I6PZ7ciGAcfh87BP]!`AMF;<5TcIYXOemL8En[ag"!hb]T(1\M&7[4C]n<>X,.(bE"Z=([5+>& rentPm#3'4/>U[ mc^#Z6rV*\t$LgGp3$:*IG-1.25FGebgA4U&coE".Ab+j-&ZR+E*e!p)qS>1]'bT-)RC+6/A&ZKX'T\CV2Qr3`E]]iQn[h5&5Ma$"*M*)bf"rb 1=p'I[c>VGXD4BO&O<7Y;W=qbng1bNU[-"<38PdXNhN941Oe,:'opR3b^,0YF\\+f07p3"0lXp,tKtrIL.0e^*.pf'00aE$R#8W]O?4=0QB3LUr?mkX7B(m;)co6E'"<1lQtfQ@5mR0YR*`FFYID+'S0K,Z(nal4ssG[7IS%s^48pi2B,8 (A)KiNFLc6m=&O)5j2 ld*[8=I!/f h4\G#i>h?@8P#VEE76!^E)V!l$DeRMMriK1&8NgVG;f,X^bfZ8;N4$nqP]C^A\%?AmO '$aWQLR^Va,+Zq/p@aiWi?>N[Z"2S+^e]cMRH;7DWNFR1OOaj4sQ^l*]XC`tZV8T>FWeS8N`'`ZmSGbb2eSFN!\>bDh=Mg:S!ks4EOLh&T0[*TN_`kpiT1=?:k_k;Q0I]3Nl])gbh8Qe[+!k4U1g]>XHKo9tgI1bb V:/`FVt5e&D/pg:(d.@+Ti`LPWE+W&/"YVOO`C4kk nOkoUl jY0"< %J9d,%lsY,a]+`A!Qd$WR\n:0DE(XF nG9G?GMXFO9&eBQcA$Ma3]LQ5RBX""7_De@DAoZQNAZJegBWjA36hDcEt.OXm8d*gd_-#0fc(:9*/ N2F9AGikh9'/sc_ISAj:h"s3Lk_'a=a`^3(<`BbZOk["B^_Z[[/,eq4;LT:oHXk;r5;lA( n@cjgaLC2[i)rKZ;OI:EhCnER4k#)1Yoa,+EQ$i6)dSr%2Ba.i3: Z6SA($a!gl$/nC6>X0EE_a72CE`nHL"`ZGU_5SWAA?W! (WXtM9Wj$I8P'8dij.S0aU*$(MBK HLH6'U[tq#JP7->J=na1WgXIWFkjdW;1Y/sUn#bTMqen^`7bA>(^c[!Kn[f7p8AYb(N2%5\FG-L0^5"qMVFfaV;sBVm9oiEHgj8H#OYoUjZMNTL]MqdZ!s]cpa;;lN)0USZ0k+_G!MnioBE=e0hs3r-CTIilr>3q]9?JfI)sNDPA#dp;\3rFdLnA@Vlgp74%r7>Cgf\N4eLYHU?3*\67rK]pP cW23D84fAQO=2,.p#g4RL\<&QdV ^;qPsYans`GF=XZhl-GE%EW5^K=(+(V=OtTqc&:bh48P[RUX/.YKGC]^DA<><6b=Gh2Dq04>^*V370c+O5F&r,CEhV5fK)nMfG)Sr8`i/9K-7fO=b@T+\J+7EJ@6klM`Q4^Yf+e^kXIrNXAGn;/:SJYhcqAr=0shWAs',%1sM.3OZQcJeJI`fO4RV]9g$#h">h=C.AR^)4e&Q&K5,iZ-B(t$:NFV#FF8tY^GHO5n1q#PIMZ_0JrgF[%\I7R\CK5A:-rc-P6fFm:TGqbU_rjs$q+O(I4So>0[ApW!qQ5IQnZ5GHgr=EL-H20@6Bk(AV$0UUF_#f9(6#g":j!Vsn&pX)b477Sif2mg^V1$*D#_.DY@_CmmU-8`$i1,h6^8U.(EtH9<m]5og)eJ!bbP[b!QGEpJkP@:bmPkCONM-(-`U]cXU]gC"%Mj,@f%/]*q*9;UYd9!)=Ne'4Z7rtB]b9pj"dpVkMkA4d>@k<(tQjjl"\gQa7PArYdrTe6r=Fe=T9cYL&@LU6=r5r]hD:o42!1ARde,?dMrkU;`BbNYcA"=KM)hRQ`r\hoQOAA37TNtXr^(6q9@=N9)j6I!8CJJl!pg-_M;tMdSa2sD)B&*c8t/dY0;+=;j)*-03I1n 2I7F1jpOc(ocb%%L/XUj\s$EE2[!<;]8k#])^N+AlXfNZ6/jO^Z2^!R,"s'd:k<[[^ig6Z6W<#(\l5m0+^GHLN:tD`4,k,D:V*HTp8)O_K7DO[>f!AM&]rN'< MOn)D"o@mK?jmgi%FltcD*0.@,-H(e6!!F<5Oa!Q)A4OHKi=2=NDBR6@jDrV&Wj.p`!VSUb0Gh8*Zjh-X[3(Gg3Nl0:'`YMLhApqnB0#aJC$$_67?8k]:lA:+pqsqs/Mm4jBpTGGsKA8RH@k$)kJI<+c^HbkSX0%Q6i%m;?7J(<X\V\G.lX)qP]=#7?7HPMQA>D&q+P0N@9)JKEX!8dCA0b"8TbCZ-4C%L?#,4$UAo`9IPt"K`Sf`b$7?,ne4fS';ok_3l4HIS+7H,JV(5[NqX4TO0KdO_&'"*ZKDtK30&f;;*"3p#]t1@ZYl82b^sjLL,;P)$tJC='b,pm1Cm1CoL1(]URj,HA?_J9;VST47LXYmIq.O^,!54Q4RIsp6QWdbW9CZ0g-5J;Z1i^4bRIk96r.nI.jUBUtc^I![At*:&UE(KjS(/ Jd]I,aAkEn]?QaL!&MV:b0tVF\$_(fq__Uo3W'>*p+6%E,[*>T5hJR^FkJ*$#43+VhrK&&p"?K%S'r";pKQ_1qb8JL_:#Np5>I_Oh%>m3;' $kA]i&P3A)7WUXm*#ZnF7kU 1WcU4+/c,^ -0gAri,BK K=cYV*G9sXa#/#<iK-Y]`m` ^jW GtqIn+LA4/bkSW.9MZ)ZRbNBKV_LN\>$DohPie]e3?rjWX GP.8#A2O5-\7"C,KPlP5Y&U2[KlMQo25q.3EZ/#]X2UYU:gAI"E4Yd2`IY%O<$ptj+Y5]LR'G?P^mRdRd'qh/>A?Dch4Ys!%UG'FYh>6K5g'Wo]c.oGTbGS-?^eAW\3VOP=+T)_WecM?5/9/6e//Jf,$7((V@0/%O_k?8A&H!C(gZA$\lIS=bt.=ZY@%!*`3#1(<:>NNP_$?-H;O/FPOsqr#q?B!C3%4*:JXFlF#cLCIjr`AG:B!d'B:ai=HEr&4cICiI=dGf.F'X;M6n5/S8'LkO6,6SRf"?UQJ 8,8[=tiC(UO]J/AYl0_?+#]rgkV$$.dI 7HGbO;WJ8I^^/ZW:jj+m+ZRir%>jmWXkmbC"Z$[TT\)Y[%)L_O+>NLsS-^\Kr>eStgZ#G A:R:mQ9l024Xb[V]M'lGW-%sjY%:s+b?o?Oqid&TFsJ@HLOL+=1SP31P hSX@eR@61(H7f\W"`mdPf:JlLE\%sVboqP4m\Nq-1j^;jA3521f9X,Aj8 h61c=0G480E30bdNHdj&m!Dp.4OQXj#aaF!H!=VO5-2R)NsdM]o;)bs d/2NC8_'%hG"68'4CP22i5 ID*8>Kok0XF^'mPq6em/"*-0SQU`KfTbIF."oVADl9.i?JbIjp!>4;qd>\/mJ%tM9S^(IBK8CF!'a:/*2^=R&TVHG1AoIgh$;4MMC.sTZ18b@_Zo#F^a'lH%VkRFeh2WYgs>2'$]7o 4)V)"jRBN-OqbfGi5`bUbEG^cc4TB*.I,M<9sX"\hpBYZHZU&@Mp`(t:oi*W:4eUk:j=1q ,E77#5=+>#V]iiI`,A,]$+;aTN]qO^elX5gd1_cZJ&FRjfe50o5YP2'/3.:tN)GPGsWD^3FHn<Po<9t.kFBFP/9mJBM`>qf7Y)jBEs,'lX0J\@FpCNkj$?;b53k3K,1&Op =ktW98o6go'DlS/q$]6qIlD'XPAPmF+52*KkbNsoh;Et'l?WA^MS,cWZp(t5!bSfAhfY-_Q]XtfE,'-9JKs'SPbdC1h*.2MmDb#CcO5ZK4qR hc$;0*<<]G<3F)bo 'As'2@+[.Oi&<\UAp2/fMeA.>A6/$Z"R/ENAd47X+n*=b4Q+FRK00@a(!! leYn1B)b%]n7>`@,nF9q4>7"BE9fLGLt1!X3%,!\R5KBn;AUtn2@2m,"#sBAj`+n(HN2KR7c2Q/&9'N ^XS:_/A'igE2AjG,k@@A^R,I/t:L?DO'U2Prl1NJqr_k&80fZcK>Og<s-&1HYFbg8i:+=@8TC6GL^"HdhZa@D$#-BtK;.,Vo(!keiM:(oDc,3m`!eK8`/jha2Z&Ch5ohpX1bFM8KJ(4*T_*g;DQ#N/SH*GBlsjtIsQ(*>'6c3$J];t3h6CH,g2P/MT7r?t,TKRN9\;OM3RbVC0bhSX_6F5R-M# Tg!EoD%SYW*1Qb)JLI/!MfTZ5""s:8Fmr0*Tp7P$FXqJ#%`#=_Hi91XEeFU(m9+m2hA%ZW4E[?l`=:QW"mdF>Ps03m<9`7jB""<4<6$-`bCsKjMAMPCG2W BC?^;O17GSDg1l'"Pmojqq0\C^,I_\).2+#%I?.kI##'n*@PSh /o:lPp2Z4b7o0EQ'c7%>Xme8V0/+A[A-_n\L\l)=Lt!%c70O[C(7qZ&Xk_@jh'DphP/i7p^g2br/7boPXRH[Eo?l];bY6T&LrD@4Zb mjUf9>\b\PdtDQ :AG\H91r>R(6g6qAb$7DXRdjt&#mdFFjNoXE&]0FU;,LKf.2lK`7In."M0#RCDI4:C;p):5PNIKrL3?oqj=BUQ3;4 AVCAC&1nibS^kES7a0kLA50\3((0f?85.QdN-/k:in<)tFMAkQnN#Aid/G'-+((:Pf*)lh20R&gpeI7U\Yl2k#r3OD%VKs\#i>oggj6J8"N-QlI4:t=+raJWD%Fj [k"AM^O5frFf[K$SI?eH2b,*H<YJZnt5(@Ir6VDUKnPh:9lsHAn C4]AD&Q`"lqil1BAIW+FfiQ[K]K="X'dM&Nb)L*R!A?Yq1C'gS(Y0#U'52,4&f5$">_FN4iT_2W5`Dk;&ib\_qM+VUPX*#<Ftd(f`XXa]BO';.a61BGK(DaU7XWs^d* f)=8R\0C01IdA(>_o:LX2c1!mBV<4l/QA=!gg5c!dX"1f/cJ1P((2,_LkH?hi77HZ0I=A:fO?4 ;$FnW3F6sg?Oof1g'GCA$&]Y)..5U76;%d!Qn+-kp0BTl'km"!0[bL%2]?d_Br;oa(Z>qta.#5A& 7P;BhDR&rW^c(N?H$ZG&eE-b0]m"^:$D&m5aAeh=a_.]970#lT,`a5A]BVThe@Uk)_8 ZpR+H-.YTY3;1>![%_HdMoDPG"s;(hh?NRqHZt"eroGFR9`2OY#VA1#2g>Fn`]<sQ]!,Mh1Z'3Gofp(K(sF(?BUJCHa)%'=L?7gb07T-&X:'n"3`8jh8kaK,]9IG6\/(`5fS$U%Y(qmE"h Vi40&3B5$.\'V/S^Mh$\P#,Z%43m%R()7^iP$oVJV[p@6-t)n&\87=]I^1L\7Xm$T9cp,j7KZNa<98DU:iHc [F!naeI4_E3A15X=K/?&%%JQWN=Hd/_DN];2 a2d0B4+h6($ 2kUAp^im/nP ZYNj/+7+E>\t@9r<sP'k&JX9 h2^2QD0/;go?MKAsS(<&3AQ7?MN=Y(hX9#bLReJ6M*/8L>="H34g#/NK>Ad1 \CmZ'F^F6E`PKDjC)efPUQ&-XD]o?Eo%(9,N3NA#Z[P\rhcrL<84n RsP^.b+KZHk#;\'XYg'knHL3 gJ#doTCiI%XZ@alWl]r/9b_7@0q/TIMA%=L2AbG,3a)lo?H(]!$t&k?)a?b;gpK@tF:H)I5+29Z@Fa8^58D%0DO%(5564 (&RH(!OdYt9-C=.ZJMsfhMR%ZFUc(Y\\5P!gcVp^+5)\]*)N .1<"i-71jr$AY7p7"9T),c)=`S)N*B6:L0U*aW-HDXfsXVf&a<(l/tsMn`;`[l=;f&rbgcDP19ZEZA`M6]Dis-MCIcAO6c+p_Cjkirb!a@hLMC@MqCs2O`]B#rob8S>_U5OXA3pr&39^o:+e9hi 'I3"4N@\J7Xa=lJE3f( #c!T]m0R%].V"YU.*=4nA:rY`)W`4sGkr.ZjqmcYC0gq\QpDs/%Qp5h1>ZaEk$iG4ddArO`raj:VV 0a9Co?8!$SI/:Y'1@hY75]?Ff'^? QFb4lTA.f$Yl90*85i)JDM)1n "UeV\ZcL6WMYrcW7"8A=OK YqMAG+\;q"$Q$C'>(S56?>3A2UgAC#$.EH]?mL2VM;j1kO[A__NaH)etB4AY.nDt0PlpQqVNA`@O>JJG]5joI]sKc[gAJ3GibCf`aceB6$AQO@=hcmn[:%9WVS$?\24 o>I^]qF01Sc18 KGW9[F]`I"A$rA]$6Q?OnpSHiaO5_q'XZfnP:UNHje<=W9eXhr+2qdXobd8)-FRk2OK?\GHPXt\?Wk`3n?d%5iZZ.fCG#MDi_2N&OObPNm(' SW:B8jX`%fFdY+_'f#)B?:*J8sbf$D8f.?<&Hh-37eQOA$E [(Z6"/H`*"%I??Gn<X&q5,@D!$gSMs/ :*&%b7,-&<;A"Bs3CMP]<&$r=Mrl^`$Gg"Pm/521-C>ldl[&$aZ-6gmUAESdC"t`86-WGc'm0cgT?0g.!InTDh,_;?C7!-SC-B f9t$\^.0oSHA94BgE+A2)Ca^"&sN4aY-`fF_N`'8''4mTaq[2kH70 i+EJh<,N:0<@Z`dsBKA/E:$];\j-9O5#`\Y6.'F4+AAI*L >.+Aa"smg1e-;U%U)M/>o^#f3*la>+ E/j!4FcZM(9RbWR0'hE\*-A68[F_G?dIbeH!+cS<,-m6L^8Ffa)]!9>E;kkaW%rds,W+a6mDnhJ2E?DU'f0OBb[Oo&>"-\P2'Rc!Ls I0cE'nArkdfYsfo_`.74[rF` Hi:9a(?&:SprMXm4Z#nC>I4SZ3Zoq3E3207!e`N7pL]?ALII%EcE)UcAsE.W2Hp;H9f.6+, ghLDk,_;h T&AP("mHq/_[9kfk(L0+c_kI+X[b[n.99_:>$f.%.56=4%s9A%%'/"LZ^Q)EZe,i%eJmpGE?Ys+0$FUa@=fjAQl!/Q.CH2_%2AX^<_Y:3SJ]rcrXA$dP).gd([HQlTq=]p7/]!LO9*@=ca0/Z3@0FIMFf_siXZa@9.G&^+ C Fsf!VNRTJV4"sdYt1e`A8fG#/1shHkP&:Bo8g,r^['#Tg?tFsP%J''$2>C)+>P`r)'DP&/J95^P fLEpi4=G3)34qS:,XGEEiEqS$Qj^Zdh7D/7C"8KP&(1=We3^kEtL4TbtU?mk;.VSrCA$8d\08>K*hJib__TmH4e!?G5SN_49jl!&VAO^s"^ PQKL%5)aA [@#,S0O&p]=6,mKq=J,mAB.<#*(_eS ii#NK#p\H>Co*SBDXiV`"%;o^=4VaGiDdCsB$H@\[ FiZ.iALhM>=p0R8UoC&CRV_OUDI5@4>iJ,%'G=Skgt#hMR6H)Ka=91GU[ao9UJH0Ym]S:ZY!d,-1$1"ae].!Ao&h-`/L"ej3YYI.Ge(Qce.Gn*QrSaX7WtSP`PKoVMA;KN3/?YreI$!KB'/mi/ h^$W2`BjDB@9p_JIrqFTq22\`WQH:;")70d"di`KBZOp"<:%U6/-@@T@:KiYlANXit!UJGtk(.t]$C#o+k;:WA&DgiP+TR1r[W2n=KD.9,<_F>i6`85t/+(]s:7J?78q*>>7Q' (Gta[p"f`;AAsNQntj[<HcSFF"iT%Z,P]j/G4lXD3O,ABJ\L3N%PT8_[='i+QhC8A \.X9$Krtr0WPSG`"p8 tU'AJ#e([Gq21Or[em.EB,"-r'+:\t:ZmBb*&( kpA!:63RTsJLbATN`//D$WXRI7,UIpoJ+jDc`<1tVGpW$Pcr#OHRPs6hbZSTU=mkPVLAhL]>@*^q:UJ,G"`'&/)?BB3]4c1p%P,_% +/?^@oPQ1?7o+ppq"@$J+cK4!GY">?J1'-1fA_lNn/[rmG1,_j4oq62Y?^9Q11P0E5'0'3J+tnBlP^]e"0kN3Ekc1WonI9-qsMs@b-.'/AACX:FY190e GgVY!hZ+ Aa7V`Z_k0E865">AW=1Dk^,,nadpT?l,%$1UUUqnh51&M:W,(UFc8Knc0ULMJ`f8h]Pb>T*i_Y$RHG5hsO 7bb gM/A5A'5 5,*;5S82DX%QmA5fgNi/1&P;q]dsNU41[#D2D^Z:M&[;0>b\:7jR*e* _H;m;@09TTsFcjAt-$H?DmP*]l<i`33Lth-ObZ#[_K:E1oBKA\U%ZRW/$HD3JrZ$M-%5!t<7.Z0]pM.75r+4gI;5rS?sXMr`\0Dms:P]2@-S@b7hF\ N\EOW*Djph-em`ak,Re(UkHPWM1`S@_8=pfcP8ZF.\sl9LfGbh6r!*fU Y@Hf?VDaNQ=><7L_aC4oAT*BE50p%_nI),^WUrm>77Ah65?7lQMn<"4@nc]oi3t-A5qp*BD@e'&XCij9#C.FZ6\dt?YRb+^2EJtNkB#o$)'-j*T;Y!\55BHQ"*"fMtP2[jgYr:N!ncG>:B^p=+AK+8_oOY8Gd/%R9]$3`o'aKE34?h>E9q%iIQM-+L46?T]4U7`fUoR!'Wekf._+*ED9<%CIS:^tD+/dd>0^3NWop?Inj>Nj[%&qpVWQ<<'dAhmO\pAECmd2l&?2 mDI:dVSc!3[Z`'!%dlD@8pAKZ8!mkb^^kWP[l.[7\C)Ut\hHaj,H;QPBdpohH]fdK?O.A,EX'5g-6 ZS?]! 3rTg@NE1_r9>p K>[;D9OjYkX&b1g4#fGP? @VHt"HUY@2Iso4nIZM6TA]&Uc]!nEHLj2[@dUd"(f(l!VOgneeni],`S)L:dL!&h2`!,$F,=5MZA4(5*0m%#/'iQY 7D&mN=2VB,19(_Rq]Df+Y!\=HGTK:1J?rkOLae^5`JbE9dah/X,k\]:A2h.Gginn.j+Mb>EXl)Xsb[NNF"Bltp.U=0mq?THM0*nHSblADA&aHj#s#Tf13Jt4@!6NKoK(d5.TLh)9Zneh4)7i=N;Ns?BA5kc"=Hc7gUeX 9spSSBdPO(,JX%a]"Z_fAJ!:"Ds9frG$$lIrib./&@O%f(/`P6E`3T@e?Tgo]rbc*+5IM:H8"GN"j"Ti#37eB@"h44>+B"gCU)eXFRsTHp[V/&a QO:W<^A$_:tU[/0"2>T,YTRNY Sn_@0#m\3"cqBtQXY'?Ial2BW6nhIA\cUc=c B^!d^W9^_-2_/qD&1#nst7C-&W03D>ah.%AU2(Je.AB.e#GZFFZRP_GPM#E dNaY 0VP1D8d.hL-%'UnXRtLI@YE"@q"QSJ5*.1Z&LKison[,3VDs[^MEaS]Sn[35_.]M@DNso)?sOc94@$QJ&533m.$k%T[B?%5:!;D95dCAt"f8(M/,$_8@4Ng[TBACtPE600l;0IMBA`e;JD.6+d_!,C7X[3Ap5S+JkPT-T>@p*HfGgC8G8l$Gt&;j qFHG47U5rP;'A(8RiEp@-"gq85#djA?-M8U8l`BjW*7"o#3'\$dI"Da38TRHP=P=b^Wq0LaaA]%K'8YkcHJZ0>RVokpZ#)k4 $Ta( E*Tc`dt_L%h2PhE.5Al1Qj%)HdAUd@.S4R8'+U'p172,a1$&m'*N+8iMb:A&]JN+-=Ad,"N$NbM?d9GjD's27\E<@s&bG1?me7&qFJjE?g)-^fUf(SoF1K_\W!jN@`lf3h*-Ud%8Ua!AkXGOL%U]+4Ol'!5J)M_!`X0/T1,N^(.SC77FpSiE_rZ^N*g5Ul:XIks/gDdZs70+kKtZ/sdg(l6mE"akc.1'.6) OI%Xoka[%<;iI!q<$n0[X\X)sJ>:.4trHQF,< =UMci)!lr1H'8bAc_m\8W7C0[fP`^sZU0W?$$.%XAB5G<%JTq#0L7OC#F"3Lb#eC?XB6:[2%PM;S+e6!8p[lA*QK7Ci6E)FZNRk'42FmIK"7$A NL!DG0!ih`'L'-@jH*PF0+^e$4336K>LoV!'YRt+!IpKM5o7&]JRKrL qaLj\W`;_NT >)t?;[?')A\^oa518(VaT5ifW7i2_DFA=.XE-R%Y+TWiZAQ_**DS@<6]AtYN3qs=;"t+ni@$pS;*K)6BAta'lcX6kMF2Z:H:].7)+*EOFhSH4S;R7:QU`N>c.S9B*o6^F01lSo\/NX3nd:7>9Nn0! 1Jm7c8X$<5`jQ9,r;qNsognA[a*D2sp5:JlS@D QI+phUn!m(;kKD,2k+b`Wh\M3+1TY(, mAs;!2;NTN.U^ /L2%D^'L[QT2Q[;4OJqK]Ck7E[o2IM7CXBLW*m1?#s$* H"MR[3R:[/.gC\[T!`2h0oWM]*&K)&Z,Kh(JB1&.eHq!N[M[AA$"Ee"IC1\:j7:DPn/h):XZM\OPG)o],.9]NghLT$DA#5Cl+I# V%t[!l9GmT;)8AOiFEXoL^(2'AVZMN#>0;9L?,JF(gifpJ_*pOHQ3o0:dC>aAU=kJnrVq_:;m5r9BJ5Y)df/`3nlE-6e:^i!!7@!b&&cK24pdA]mdr(%hi@YfJD1YJZ(Ddrj08G:J$iR%o\o@4aVPjB0h59$ek;]W)hK1B1-(^=.gD^<1Hgl8LmF9M*e:B5`Zf9!)IH%8(l +VXME\Bb>IRe8JEQ) XNm9A8j5.Doi^+%c&l;N$LXq4]U/fkm$0$;r.q7aX3)I\b[`RhVg\&@]Q.n/>g 70`Ugc7pRQ*LplB&QOro5!!g@8HMZB7@,8RtoC01JED6o5:l_/e'Q(7hal>EiWOh)`KnQh+h?5r912!?'r5'b+(Y,[Q'#='!H\( _`CBR/d;`6AUDN:%d)@n`Ag[,#mPGYWrZ]7?(NRG'Cl9$oCS@^WW8fL#po4`[U7&;&#MQ4l9T.Pr902kA!LQCkkb39/GjZkTm)8VkLZHmj5%UJ#G2ngHtb([`WTN$Q+33HbF]qfKqUmRZ3H$m9l6*G06>+h g^`NWdnW*Cg4kkkteOf*aOTRrN-:\e#%2m^87^1[J9T\#&ASQI9[O6gha2]jqa Id?:@^8]ANc>@*G&.(W!%J0?U\FJIrV&_CKVR))Gs@H=0I4f]-MhcM';9"l;L>dm-)P9fUJU@G*`SE?AVGn>AkA >Ce`Q_-Y`I@AZtkJq!oD\aIZ5H(X;g<O5U]Z\hpOjksfb aKpH>9K2fds^;SA%_J"Eo*"F+F41H,KleCP717"L69Z%5(Ah*j%:q?HH.maa@to2VqoQIm!5CoXk&"Akk>%/['&bP\X']n-A.)q$1OA_9C4AqpW%f`U-PrC< M %6DqGB\_bYLtdAd)L$+4'd+6K/.:ANU.5nk<5$9fSM+,PIESS]a'Fn"=*qg5PO-=bCW7EhL6/1.=hgF.JkE_GPMLs7/2WhW#ZYGLY\Y 'UTr;M7Z[\e:JIEAEjr nisP*ZAD%%X5bLSMC`_0Vg>hbD]l@8Wj,;CX(K&3XT%tFR<>F)'q*#R[bcS7Rke'E>_6IV[g83]4@QT,&,. ^7K>nL=N'[,Ka`2s4gerT?c1>+%+T9E6_""$NjT-]_A:C,\O!N)oLJN+cIh>7M9P;I8f7L:FJ`h[$88Z#".tae"1(Kk12CWL:mUi@[/R^6[Fl?`m89[Q'7MIKRtbVtq?jZOWADLb)5LfY9NDQlo[I'jbtm>1#s;n'F)J\B&X$T!9sH@4@gBL"KZZ3lpNV*pm%E,i]i5PQY]K[8M8A02L]4.P_8!6oBbT1e4U9s+LmG9BX1a1SoTJ!RArs-M+4oHkM kmbd?dm^IE$`>fCid0I^j_FA6VAr11+Grl$h=>6ptU>V.D$-Go<;AF@[>3j)B^`8scNE>>Mn-B>,d"H6>3]6_[`pbI Tli@StiR;]&^BmL(.O&ll 7T:H4n21BRe?`b,Y9@G=BC`3%/f8^#S]K,AJ]Cd>%tA?@JhO+3jjb6mg.[lFKH_N54JI^7n+.R9()PAAj',,kea\.,*heik"i@KE_Wd,=KmhG]")2:_[JOp,G[C]tGs-d=!_7L_pb\'kZf$1I'2"0NlS5XXH\hW0+tL6tIa8gWqDQa6SWil*jk4V31KfU#h!L-(2kYC=6RZSMKj.M&W44@Wikh*,8+A/k=b8h5/*O^Ei T.X=b?\bmFe4p =Y\%/5Ad:(39>AWP#ASmINmgl"gP8&^icBi;B?3,qR,UdC*COaV^0r9^j'J/g1'^k gr`W+8\reRBgta9P,Tao#^njl!.aR"nT:YQMp[+;sLi9m?"h, J.7VpH.?LB&'75J%9JoR&iS@9[rK=UldXCCraQCD_O("f>ahCTF/-Pq,e*QC7HO%sAF9-@XEV5QAft?fZ+]j6If9?D/*Xq,>H]8qjGaZ,4coEai+qPAnrsoL5!OCPl#OQ2Qj9SNTT5r=@-ghrL#+Z?)f9Cn\^+VT4['%"0Apm \ajn%s;She/E2cGUe6S7HifFtC\C'f$Drqhgn6BknpXP`&%lOi=t-aD\j.X/SAW)7AIZG&UWi_(%A! I9pLp8hgsS>;Q;rV5oG9dLDI1=[E9K19`__]/68q4[nWZ+J3Y0X Xop\8bDX.*#el,[HVfpa#`@JL-`dp)[Tk#.:sZG[J>9P$:LU$DZ--9Sk;"PMja,,b+r*i@qMY*07mWpi@@c*@ G'%setr`Oo i$*<)K6UY/`X\3./4W,cg])P.^>ENU4ZbY,p08=b9KW;06emM0r2D]rk7*eq>]UYAQC)68bl4>opCE\@Cia?Yjh'DNB5e!*%JLf=/:.eGj+P4?DC_Om=IFNsJ`Q,R`E9*te+:d6sR8O$k?=rhKA_+]7Z]$]6aNKc[mmE,:FtHn"Z[SU`r.E6a;'n` .6L1QO(!JhXaMIO@+Qsq)'+DD-5?B4d$!Oqb!;,%/c=+I5tW,Oj<^a?%TD:r%f_9U]1t5js[JC>f&O_cV"rIgiJs^,mD?g(;(_GAV)i\M)[#kW''Ur!O*kP57AnnHY7[47,R[&9SbcXW*BVr;=mr8+_U,nUr0I_r^@ br^=pAgHqka3BEOph67]1U#"j3567IZTC*`oGdO21Q3l/V:m7$KdVE;bV28[Z#G.F^&cISNhZ82.emT>oY/^rs.//X=<$%]BB"528)tTn4ETK _5C_IZm;"&."APR@,;=JGk6"o.[?<%Tq4S+9WO,Y:aB#0JLjW0#Sm(\nr`o/sP3Ql%&%j&<>doic^smX8+27 '4\1M h_0q6)99eo^tAm^GH!C'QF`e5r:ns#*bFm7-:1 ](B`E2trob<6e`^FeI\XUA9kMIt0'M5)T_IoX5pN`2C*E#\2AcR-Nsd+ pqo5=;0JsKDQh+'kN'%;"o%:ChHIN$R(KD5)A7Jc[eHBs'!C1>3m(-fGVYj$ZiX/Q7HArA'Mn;8r.W]i6m8/f,>4>XB@MJ!Io(o'T8A@s(?h`KbIGDOkMW_XCee:lL;\#@1I:YO8,p&dMm]#h,*B[o;-E%qUt_O00%l[_BkDt,Wkl8g\6@:S#a302_O>dZ>*>8)Sat@-\/Z)ds3.t6]-a:eLO/0_0tPT-Yen9(*eGfRT@F")SfYnV,$?L>%q,A7NT=/k'oh.kI9f.4kQK S(%_X%`:"%g0/]-iEm&[U\ARk8N+U3bl4(Z]G$9_d'hbSoK#bYreD-cQ"]W1T26F@^WsI QV,cpI.<WPTPiGi0/^_H5W^PSetF:UY-Q4GMPIg:1N-Ol;P#iQo3i4CE.]eYi!b.HPqP8?8rqMK&)%ltAtt7I[2Rc,.F3()Il`)9B[FH0NMiF"imOiBAAQm??^25+I6r6eonS@9&nM5t#5HMGTm&V?EMn(#^6B(X%X_4*o&["iSmAC77R7$h<(k9T(XHbMA7/&C:WHXsLIsj:_JJ*Pjpe$sh@tIp:F*]"#H8KFR=QiEorEFC2VZhO'(\4^C9qNQh,rjGm8[JAmGAC0V@=G;mMLn%Va\ZK>niK0tYo9E7\)kK\U<#6(oX1Ngcf?Mo;dB`lpDI9fVs2>#Hf>LXnq7PtYp[8>:NaCgFI+Z@#As?kokS9%.00\jN"UP+F9*5dQ:ph\)b]Lr*Z:E)bkl q8k1L3mKlc\70&ZNfp7Xq&3]dNg@[T3&/p,id;XI54:&`jOVh]U"Gd4Y"gq5)\n4f!TN!A#lCG:4NV< ,%p`b<-4q\dt^n8b&lpgM+dc/HXAsPgFABAakW!5h38tHVne0prOK@GV+Dh;.A1#;WF5Pb &)A`Has6C#0[TASJW&\8JYpDTHK3_DE1RTlPjRrcm;G&I88C2CrFY'Lf;8c&sr&pBrTSsN-&LTj%\-ct[k^\Ro8JPP% J;Pg]p&8C7`CRLg:cd+T=L*p9VD+'[R$EPM"iniN=s(57WT0eU$K:l,;rATGAKKE39d=`!N-VEA&5[b!MH?;.kKP"XrkJKa-\kZ[SLD5VO,Z+J_lNp@2\HE6^^NO%l%+D0^c9>j6D<\'V;;6[8hd4)2r@\">!pAjXRrKW_:hPT*039!&)D^slWa8AVt35M?6^?8)XTqI*9O9$SGsX!cbr@t!.FSnIGf"_TA(FO)_DGr?Cm"*'hhOkF)C2fiNoDP8YCIkA!l0gOG8bCXsn.F'3=9#(A#r@K@Uq51k=@_,Qmf4;^p7XqnGH=0h#]p](HJ?Xj[>r>?U-4ZH_iR3c;LenPcIF/4\*.ORidj\:Amc]oJ.XFN-<es"F#Q3IA9>aNP")GnN[r.A9qFK;Uc;f<$%X>U+eU]\#pj=Z hqWM:MTq$/&N;eS&<8TLd:&Ab*r$I`^Tjo9Vr=O)->.eWoX67"jKGNfFA%?q-'EK=8g'_3k:PMOEKE66cTU99+#(D PREH#Xer)2ZO_:4H:'/d Hp!I)nqOrglfos*[lJ#rR&]ShTa)$W;ZKenVk`)S[8@?B*'3dHLh$9&h*XmqI]Vk#@AZ"RV8n(tC#LlbRUJ?(hjnf)ZtlUY[ sgHsHKC%1nREJFq+@D.nb4aA!9pS?c$#$-DA*6GQ568LTrtQOT79!lk2d FPo5@"s!WY7q`=s1(Q^S90M#2I/3pHgkr=3IlK% 1r\_'N\1cEU!;668C"1-W-JJErl:VNKbji+2SUDcdH0\3kh>c26a1h#6$8AV3dCAk<5EbS1Z 4`1CE7a7ELnOsLFXTVF9S =N$7b4;a&,7cUY2hr*P]nX06GrASL`<\03eZ*[lG`_k`i);at3041D"Q$`9L]YVZ)Im)IX<\62,DmYMR\HS"t?]o1:NBtH=[:>b#K&Y,$Qa /sl][0 &?pbqX>nU?)1#?jkC0)^$T;OIEGAQ6RT>Z2+')DgKA232na)2586_o1=A>?mBk.9\J@isKbA6//kpEdDbA]pCoK$f!%#?`e;Y-;d[<`&+=XS\&VAoaFZWlAJ#N\)4E=0tMCMKXk$6 Qd<#5@rNCh%7bQeAke(c)Vi0bEG/"8`maPqA!RC6D1 ZH8ME@A_[flBH_CGObF\AAL];j_@Wkf?hM25%P6&fg3/0&ZQYE4(ABStJ'qKG&=YQ"A=esLca`BO5b\!,Cs%U5WTM@Xe@59in0#Wnl2CGU/f(I.nnh8d9nL:.ha],dL%!O&(;Nq5MR]rN:/Z;ga-Rd_JjKB)*`_4T'2AY=IC:d./8@WSU1) [8s3E[W#gm#Y]g4;[r>XD`LY)lAF4[TCgf$-_4' 9MH"I=N+!+g4q:;4m9WI.n/0dm?!6mW,,C==\O0^I"PPLZq2b^J$q?gQG-16IWAdHt5a>4J/_ls R#6\J5$X]o%<%'"3 `A*]=0>+@dhpC!UWb>_+;@E;ka\a h9Y9M"7Z_IET>)L k$dbAaL9]AM>As=oO(Pc-D5@p#<'NM[JQqZT[P=BLtscn*t6C+EYZ_fh0QSCk$LI0(a&`:jtpm6^%=L?8?]\F"P"C](I*(^fSr'$[gatV&o:&k?m^:PMi.f?//`>jOF%`N/ 7-7N>d(R5l"q8=D^C0(-M&tddJCYL:UdMj:pZPmi$_;/0cb7H/1?AlmR(S62#F"e,&CpSQO[m9[-,&dal@DWZ.7+H!;etAsatJpZg,i*okI,S;8Ef`rj$F-N\'%=DM\;$jk (Wg7!2531OQ;Sj$^j^m0jU%(l]j-e$RGirG"po^71[Ie9h+(OLAU9a D4e/HbsAne.d%SN;;goAQ1_`SV 'N*3#kBs 'TfNp`_JsMp$VYrcpIG9C+pV7[j4d,5N^\EK.q1ff!AU9AQ$44B8T6Hg=T-E%"VjgbM%dq d@13`UgbS?#6I$pdl=Qb"p1;A-Q]0Ro]bA "k&5G(8>0`#6)JtrC;_hdrU@CBBrb'%$C=ohkmZ0Q[\1a4A'8l)nA&o0#<TM1aXEGm9.%BqO^dP(H&?q%?'FKQ&Y0g];8,Y-5c"f<1V.t(%#H:;ek!imGA"`(k8+.ak^_CUl(T(eZ@^;sf0!saTpj)5peDp?ZE8?S>n'=3!iZCh-<:f'ZOb0;C&mAF\[7(f7=KfAhpjlM7RT)%=jrK%C&I8J2&E8,+c"mag3"re'""-#rrA?O _0G;KM2gQo`HheqqRGAmAm7"I3r2WYc'eeioojXT"V!hZ3`D\Etrgo-O,VaX8UU_#7GiCgsXV%-PK1(JSm7R'&eN$kQ "#kUArkU4lS_VQ;rVsiQ &@A`csf1E`*+EjNC59F[V\'o0$#Rhbs)><^/Q^/bqL3Z3k. [Umki)clEnQN\. s]S+8ZF0?MBlAqgC\[o7F(1WQ CkHB@F>BU2f2Z>AZ694KkP4q;tkSKaoF\RJcB(+-92"7=6Q_*$'[h>e9W-2,'"E#:D .TqXm'"HeM?]3-jc*(T *QET<^]bb3m-P Y#-\Ql'WL\X5r: H_BjbLsb9a4N"Eb/Em)"hc2XLIKrp.QIXGDL.n*X5A6:Iob=-6k;SAQ_N'>e#C\G?BtOAd%r'H8aX7%5C.5iR.`,Ng0CEKL6_:=UQ7F])d6r(Vo,^O6[I. IJC(Z$kS-sBWMT(mRG*::NS0$Oo!1O<e!7hE:R9hJY6IE?as"^YBI#/Cp'9YGW`V*c>`IO,&)k%lQeG4&oQ*2\aPM8]Fka(/AH508dooZB@\\I\5;iGUNH^;S]NpcJZ>j!EF>NGe<i!2Fr&"T\cMiC@K-h2\g^pTTPl%X3Q#2%t7H/cBGACb/q%>rU>On@+&d"5;;Lt2A=N;$S67l*ZT@Q%7A&t&c[&04&C]e3M;+!:k&ZpA`B!oT$CJ:IJ@Zd>ki/!2_-9/'mki_alD bhQB,nUVA#7dW^8EB8?R[o.T(A5E-?80 DSoTFEi04?%h1h$HL$L-L=nTrHlLAj;q^A;lL1E\XL'p/B5/@9orORMon>Gmd+6B8_r='+MABWfsqL:ipbmcc[lY!A#^f;AS\(\;inAR$^FTn<6%'P3dckS&]nV/q-mpOIgF-6\kriesO&TM;B9hX.[d[>qbd-J[Bmfbd_/j(OVKX83N8Df"4JX^:CH`\fT4,')p$T#0XGfAqY`i]/rm7"PNQ[e6J1OD#LH$QYMMqH1%QL.[tW $etq=r$F=YA^L>DNj4Y.?_C?+2WppMb^:j!.=gl1/:?pBa6#tZltcS)R58;MR09A#p!Rm%RDaTT^"o@-C@*%<;)q%/4.W)nB7^SrWMB3l>$3`UfoUkbgRW>FGK$M7c:gV6G4cWcj(+&BXnc]6Tp+QP%.RW^'-d3Pq! U%l'j26D41c H*(gS3NiQIsa]$Ion p8H3nr*>A^qpl.W[6)\-o+RU]Ydn%s.ON3@Ws`O1*qj/B5AVF4W/-1!ib\(B9@a^gIpW;e96\E*d0'bmpb]\1)22,D(jn1X?ZEglE[U[9;%D^n7Ad_P7)iAXj@tOFI[@4=>>%[g87r8T3+Pt<)4)5Hh>ODI>'?5@APJcV&bXH*AY`#L<4`0ef;N?aC1 P*76q!4M&T3T-/A$njY]p"KSCla\=(UAaWKAi@>iViK+" `]F-EJk2b&_:6OZo9rJ^!tWW/OFNCN<3lF ES=MTpc<kpe1G32)[*p`'At?J> S-AnSDq0'Qf2,.)r5q!MQd03c8g=VCR:)CEe[2HVNg*7p'+Bp3^i#3HjDQ(7i#!!XSAmt 4P-K;,!k9iJ ijHq4k]LZ %KNOA+kAN/^X1fJ"2I,0#<1mlMX59[XUg7ZEm,$GRW\L%LW>Go/qCES.A-0D/fBHd3R("7&n5[Vi;&q)4Rt)js+YEJg^0 &\V9A"KD&8r6t-@=$>! (2aNc:5+I02R3qS9Y n/FBP%$;&T8Tc]_X6p7(;*D)m5<#b Noia*7V>Wha)9/Z2i VW;S"8h=LsYpW;%_.iM3=#g`L][H1rEKIPHVV->?):`8!*Kr2Tl?hq!LQ;\4=rAfL*Aa"RgH1_lR&S?F5HAjP&T0PIg4XLAYRAh [a1Q+lkSA [("*1BWR+$W+i&G9q1][oPdi\' V_1[kqL0K3ID 3h.MCX@V<8Q3PDP4K@=]ob7A)cI*6YOkn\"R=o2@2rXaZ=h&&8SLr'2?8ht `2Ygj?Td,lsoe`b9c8hMpQX&,:o=A``PAX_W;(+4)UmgC.k%k1`?HfBg(.l4%r2 b;s)4q=/kU07;*Z!qJ/3_n$j9"=@p<([2LfI7M`##'[*meTIHG%AZCXWg\6SUo]>aLFk'&#RA5n:oZ,2raU7dIE)l/eo6S<6^EL+tZ*dQ^@m.nr6F`-;sX'@'hOcoT +D)Sgg(\5B/7%-ckN^1gB77WogW&+=4:f"d."r)paXl3>HBFX6XEGjLJ3*ChXJS)k.IXhHZXITitshjDD;mSU43qBRH!,MK$AD-&H 2A"H?q!dj^rZ9= \TYg;[G`SU/@>A`0n;(a@Z/2O>^1=5);qCFnM*3EnN-rSQC ;"+$BK: ?ZjaHJ,FCq>R@cBhXG6\Nf?Yt^99f!pI2e]S1*\p)78"LIY;AY+f5%hU`s:heEq;At/0?^2n\V&=pP5/n`KPVO9UFmNTgdZ[ZgVA`\ILfOfA/$\DXq>@QZ/1AC:73)shS_[o;&%iW<;^2M3=hU'@TOmK>A#)OW`#A:N^@bWOpi@[3st>adqdQF>5]CsdIlI;JrleEc;"dtUI.iPA6A:eTAs$G^oKcUJ?+ct4idA+(`C$H%M?G42c*h(3Fa\7j^#U9(`34N8R1b2qJ_dr6dhKdU62W2L%];]8MN@ipji.6s*fh[Ji@bJ3Agpt_cIBU89Tt('!t)B'J`3/,W?NaYSr92X9t.n=3A.djBQ3Sa0p:@8/oqFPYh(*P42s" 8@:1D\>nE*sn`/"^ATJS3W/?atV?Bo&P8@m1 HK;AS7+K,*FEm#4X9_oqJjXkHg=S^#8RWRp1`!j)k*PY. MmlA&1\r@*t$//AKr8F!R^.bqmse14(AF&Z:Q=o*LSj:>FpFn(erd;IsnaOKAmTMH)9G8G@YFp*(#nh95M.@?iX9,lK"]%r><p<^' T01#ekmY?7leqSFN_a? jA4B'I.VB_K:)P4#;b4#CR*A`cT9q%CUV[_(NYU7LJ%ciL(4P=DW\G]/7)=M31E=Q=._hI1+(Y#4e;EAK9!6qbZX7 9P9YY8q7a\#PeKlAWO5Z5A(1/@r1?J@FA:X5[0+j9I9,#)>26ScaPBl_T8G$RAk4^b*K[F\k653JaN1Snf^lBG1o=[$7<``l1jAI2TsIl-;#.16D%>E(C^t65)0Xm0(CkpN9F'Sg]VPQ`j/D3?$G+?L;)$[Sg$(^80m<].TF&C+h8%[-,ojf;GN8 qWYRg/CPL$qj7b?7h-D24*G1mC?c;"Bq trOD*aHJ+8:4M1'8AA,r2*fK!%&P)[.nQ'af=`W6/0:h9!9W06U2&YW*=m/K2@ANJl&KPS"e:=S$)sYC< _8E*4`=d\]NMLW!R*=5H!@g4rV7F)AtX0!^U CFP4e-:b?0AOmp2+UQh[PYK2H;@\cmW*!QfTraE2BFWQ]\M1jBphT6>_?#8A]'A./9'.[%o8W_KcWtoF:*>W,6PKR`P=$N#*b*R.0.F*gIQhgV`)j3mcLZDpnLK_*&=@)>B'.9sP4DQV%dnb]>=.f+bMq)#kHHUJ^dC7"RiAL@QDLj#r%A#QV)`5.6esha9J7*>-[C#:&N(>\tCV*aB[]$XQ3S@tE<$%^Njd>#n9>.K.0A\j@pEbP:FBAt9qap*"GM$]=Q7 7?kR7l6,)fXV;^^GfoFNL GVS.ni#P\@Me] <&>H5o4(B!g9pUY5o%[o7dnYtg[PlctW`5`T.RprS0CD2m?*/a.?+sHk0BpAtr84RE``9iK"^$i=aMg_e79AMf_p1qGGjY,=@>E+E%5Ft PLFgKN$;bA)XYFNdg[1DPlckss5mfe"A>Sp@R`mL%KDnZ/=HU@ZA&a,N"cA?KOY*(W &UZ+f]Wd6R`;q)bgnJ(m>9D/c"!6(ki;AlB8UGY-?0m6l`l[q@J;.`RF!^^psAIHXr)CMPbDRNJ\dFA`oVG1l&\-?I5QpAQTF+RhF'!#=F\bOh.MsUKUKr;2:Arg'(Snl$W078sP:kPhTiUGL[0Q!I$/!+)1i!@5+/hs9@El2XkddQ&JoX4f]cB>Q9#EfY':^D.I&Mtl.cAR@75]Q\]PbSlsX"G/Z6$NUe.$Q)+gGpF:I2iJ@O1HHEgA,d=ZZ:-jLe0U4QjDtN:pK.CV:d&_^:U(,EGZPF5rA73&L8V\ t E! Vr6\J;*\[NNE8QqA\(m1dQ[6VHT.\?PWq.O:l>"WAm+H^AdIs a_H\2FS*tLBZj=*oi7+Jf!T##@ 'gR\Rgh(GL0^)a\?aZ*53&&t!Z9_h)CCT"]^?XB+>/ZD>e,==9_YQOYZ@=4C%J)n5"t<7mA+s;l\?K%e@pCjq)Y5(QCt>[&L4m3kb&5/7'Kmq^pWUME.pNKcB Rn#b5Ti='Fr;c64M!@Hb:Y/O(=0T]K?8JnVf %(:H<59Vl&6o#ijl&r9SQl(#?Srmt'#?co"JSWBT"7)PanS%Z_=4aSf.:1-Oq>266R>OclW]*4h9_A,j/^V PDEN2e7cnnNn6Wb6qb4E-RXK/DC_nkW5roNrb0k/T_mjK:8)P@[ i^-:L]_?JE.S^im:89(g2?a8F\->fZ\\YqY$79i>p8l."H/EmBP=QL9JX[jB1N@,c,bg0f#=/nPLaQA0'a,oX)C0Q1TQLSYs/$;aGm 7mC&<o!2/ph`YH;ek;#pT7J+RO19@k7D0Xk4K4.sVX_aA3FZfX3(9Pko:q%PY.H:8@^G&pL__G5^![#d?bcRl-kQq+3WtiAr"EMiTTUB@Te@YkR`1W(TfAf8a?dP+aBj:A7C-eKSFcY?KOrl$U==9e:i"gA(?XBcK`Mo,)igG6btA:%C$6shNsn7=[`83AOth^RM*W%*oZ(I)WKae@:K-"Jno\#OaH!"gYq*Z^d@97OX4'%AN+lQWgEd*K,\=L,iV]!AY'o!ba+PXQiaViLAW P@Q$n!V9n;].sM$^o<.[mlHAcK?b*=XcROiNF]eVD9Yb*&iq&TWnlFgb e%1e1+-@ gN*Sb/1q;IZ%mDJM0r>Yo]i\ZA!%:8UF>@CDT-e&t[',Ag5#0GJhM''L'f7tli1A(rPBYUhe5U@\%!;3OdHa%qO4V>!B059/Z.c4-8GCm+=q0A]b;41rQ9W229`FprnZN1o!#.$^#eAp5R(*1K;/\i(I0<_ISZ>.?\^Wekbs]eZERn@5"3)OD=QBrN[krVmA]00HjR(j=.=3.#G&jDT%*%[0QUAh7RGV1=O>a"T/KV)b&B<%JOM?!dkEf-q^/d0Mq-Jnar7HsTWVeZ3j)ONakRK_FJN)[YTUQdsC/$^Elt/blPLHhiW81hWX?19KVeeB()c(piE0CY*HaZ ,dpSJoWHnrkW)BtO<pa?s;M9K`E+1]$-W.s7pCC(&AL Kp$dpX`/Y0@RZ5B[;1Cm"U%*D?.!__E<[s=$XbZhT2iVH@[a4JRDt@*XAh]eXArr4pj?YM2555jKLI`2:&A^ad)s,#0K4mXTpU..-@*FDU@TX.N7>%(h:JBFtYkr!KEG>Gh5KstO#)H7Da@7j!erQ`_6qs3 $8T6D1gP!5H5\`nP-_TCk8CKoDJLNX5-jbnhU`g5:gTf>g#"\QUk=VoSJ4d@NMV)ZYmbP &"rDGK Q7roi.+^XkhrP\VX!m(:-,lEY*bd3B#1$*UY&ans$GBc*:E3=&mZM419#E/mettA@+'=grDQJLY^]GP42R;c?JZ5;;LCnD0a)nRYoftWdk4_c(5#A?M;*D.!O[lT\Mn(2A.$F-H&+P/rg&TXCZILAc9YjBXA'28IZ'!!F6A__mBA?D2CX1:H?hQ^54O\Ba;=F=?rYPk3)4.^c^=OV]b3??]lU%$!*g`YkAa!GRG+UQtS8=)A!Y2='d:;#Fp8B-X3sl'qg+iW.EDU5n3[1"]1\<^4W"oJiE@Ma*CdFJL9`K%-4 'lV:5'G`mj)[]bgA3W)e"3ls`aP%05SDcXSM]d$;-mOc/?H)NV/#j-bl0YG2K?_c(N\5AtW^7mP?b)3;!!$P8\2BRsML.(/,.9t+?d>2(BZCk4AnR?AG*Qfd=c9GAEfXIp9(a3T8Wbg&+A_MN]'p$EeTXB0_4LUB5YiXOsMigM*SY2?Z9+&=gHlk\i7*-M'TP!e,!nb]0i21r6EY@/c,*np&P`( Y4ntisD 'R4DV.h7e'=gchIDed:U?bR9=NO,s\3mm[#O+:8+6?hRRS@*VAL,UH\Y`"DaZcgTFqX<"UYE7F^DrG?A 2l3dZ<46f9*"WB"Cd]$&VAo!JK0=YnoF0QN*ATZ\$16RY(qg]2F5&\,(29'(H'8q!)V_'pI1l(R'm444.QZC,@;7AJmP.< QnYbCkEC]$2,%OIM)'snFB^4T%&X8RMOS+8Z\?J/'8/N\2Gb/<20A1\V0IN$(O.MDh]MhK+,NAN'$KKfUXb(L/A3EWKOk$Af7;ms"Jrs%)H#VL>#^90!42jF?(+btekZPD-_>RH/q[hY%eNS;MAMkAM3[E<2M*6C)HQ>3+I(I^hkgE*;Ai-e7-U53bDR.E?0#f2f4(gm"m%B[2J!3MPZ\DXn33RoBN=>op\XBU(.:g^)g@'<>Qc#9e?Z[55L]jnW_^Z5U/:+@/`c9s\K`)6OZ[go(agP,i+Vpbid'A:N5]Q8q%V@!+/*V%Utd_R?MU1e+;@:*GA/\DQjcO8H])p:4A^,i[:\<-1tj0VXI$->% /5m(OC&";77"BmI[^.8C%_;)AS6+m,;j^hKG0`Nenf!@%oT [Gnf.n'Q1WQ,SMVp\'rI-M!tHce>(+B67J`NiFJi7SP1>j>$)&T#)tF_b;p[ecN,Y?RN!$F!/_>;(>:;GVT\dJU#nO-qXhI],t$V1aD[/]-[2B1%l0i\E$fDCmGK?hnG^p?K_H)\#UCZ)O$C_&JDX$F/_o6UJ%'qg%#r,`1jE)lDL^B;TnsO A'mk5pi/1Mjmc!AET;Cot?F3[1J"-(i*X%eRGp$.nKfVJ=A?h)4B1W&b6=8P."oo,?VWWIo-Y,DZ&DL7]laAWLW)$sI5\NQ5<.eJZ?5(h.L97rDJa4bb&AsH</gZ[5rZ\mWKlQ%R#6rcAbsfH1"Zf322_3l4(cT?q;dB;DrfsK\mtfJ12.^c!hlcFJZY7qY\S$OtHXpPIk^!Q%=5iSD?h@%)<Te#Ad-R%\^Ahe\oF@*'f0 n-\5R:,lm/n5_]iji%d$;!]W06#\Bo@D:o LPPEM@d&JW\n**q&Y:R&E3b0>Aep ]PP*9f"q8-]Y$hA+/bfbe5b-p!"H(6C^P&k&sipE\-"cb],a[B.kh^ ,"A=/]B[)6L7'9B#LjOR ST/]7ID`Y6/n]D^j+[A@V.&UXVnS7.J0Pt)<-[tZqCi#sC2PJ*68,ngP?: D3P<!*)9ta/$=.'q^dIRP.*ec*2/^YdC&JB3Db^e>=g[lEAA"1G5p1`7nr@sDgt8AP7:\dFYSgB\e##sM)kQW=tmI?A)qqFKfGn\F>5cIs 3qM0\fC]KJL?A$.((ij8>";_a2[=Npr[H",#s(=I!a&*)TY]bt8L&bhPq2TK7kGdQQml<[*i]jF9o7$]gK=dd ;>jU%4:(^nqQc/c[>T]iS9sXK_UH+UqrL!lQdM&_S7gr/tbFA^P2"#f[kYh.^Z(U(al5m@TL#Et$`(LO57%Q c^t1&\4dR1F lqANA+o)'@/IetJrJb%b/WR-$8N$A=d38K3[is;Y.#7=Xt)cQA:lX&.&;cdq!si125Nr#GW'f!"@jX#oNts9+25Fa5[jt0VNpBVE27/@4IPk->VGdg$ZOI`c? TP)OFJ8`%nhE@=SflQsXQr!T(@5hPA<AF;mVb@m6<2LKDedE(o@r&F>#F?,,\Xb0c"]!A31L(/7fUf4N!Z,&O7n4YhpK['K>FVE1R+oT'4)YR^,=FMNCUIa_hS=8''%VofLdgT,Ik*DggSD7*X0:C!'`PY]qfrU+76Xl"P?sZKmLAgn*LrcV^#mF=1'LN<6+[.@qTT0;0#N"FIV,F<_s=^`nF$tm"1h.-Q4Ri0*OI2,iJg05>*X"!i#_ctf)lV"?kn=1*0(p_]SU[%U4J2q,LAA,b-h q;BFRs6)kBgp'L/4EAU/kf2+KP_o";?t =44MWelLiom7@UfkO:N"k\Z2,=AhrY$s]'7&A&A;_I8Xc)dMP`-*Db9&U8>YeL<4#-d\eFCM3;YM1;A)8\LL9q1G[fCd*(MUSZk"/LTs42#&YaFl1BFQ*-/)a>>@2X-(;ndjcTGT d`o(p8ESY&Edi;q9?#:qG'"AbAW2$aK/;.UjRU0-@Ih:[$n!c2I?n'^IFArki5)Dc2,'XQTO+5r5L(^N^PP $OQ',ET!pp5dLO-E1kJO9a2=g02OV?Z9DV@a+fASkLjo)aF"JNjgGZ3p^8g5^N:58?,)JK#Zn&4-eGrHXU2Z9OPj]p5$+/Z$-Q3=[Hib%jL6\6L3^G(sAZ;/;$!9MIe!sVY*c-)c9hX ^B8!`V0=CY5XW>FmA>3X+M2KiWJl#nRL/]<<=WG3Y=t;_j2hS?_12 X7O6lAq.%n)&@bbm-%g,e->2ipK49HW VD%@c6'SE/81mAL6?\Z0ig9"l(%-&bA@NPapRAeBosJ*H;eSBq5eNfa7KI\_`FAe?f<*aRKKmm4Y8\mY.E?a\AnRK-'nCM6R4_rZ&7@U".:pJcl[+SNVAp0QVkA.c_<3!+/-KpW#1#gPoTm$-AVaQbMm)+` #cY^(s1(\d3-pG[bQTS#X2e>jSN*6$6& :ZR87O>&7=1C,7q9_`l-f]fln ^b`^CQ^QI5%nAH8=j'Z5MW&BMi(Osr$*22[[js_:%J9Y7FH9^/$>%%L(e:gQR:f0;s24gOi&J%5[[39bQ&f/%CO",Y'QZ>>&g7=ag=@q&9Q*Dfp:7-"6hJ<"7dXNpIT1d;]"s8SV6l?9Ra7b=heU^<4Ackg^FQAVhiU;YdUIB&V_m2#B$/c.`Cf*AK[!*0Q@fBJ#X)cZpt$=pY:_&bJN<mo[hZpDtn>Xf@&01[g+j_Y1bBqBk6tDRZX/\\lmQ&n0E:"@BrsAD#`8MX5d-;EU:ODs.Mkbf m:\"08hIRg^6C=kItD;WM$8[PMNbMJ)K'3#sbH6s>QSlh5o1Z367dNDXCRM4I)N>)SFn!:'E^GN0A@6-6,sETk?Ak8=rA$L_@39h]X%-5JAf,3eeCXHWgo^3VQCD mVqd!Hl\O$15c8dQfHVSnDCSr'0nDAS:Y/Em?DMWqc.hQ2Y*;WAK&CH7F'gWTSho?DTQOj2_!#LEBP=NA,>KX5&>o;_PTQRO>\Y@0gCnerAWa!6D^+KF+YL.Z'b\-"6(F?g\OE;Fs0kDr"1qVA_PHSWXO&;Y+:2mhcGaHsS/G_Z:!'ChZ7I^Z<+:?0.^-@IS@1@? ]: !"$s7!SE?(KJa*CJMmdD,1rRKD5O.6t:j6IddI-! UfW#H33O'YM]hLQY#JT;=5WH@V!nO@BSd-nSJ:8&k"0'S$Qt[-K3,m! RX'daCqMS-dfPHCBe\fEKRoF%ICJQ`NcG'M/SIfQns,7=>U[_4iF(LO(UgQt4h844%[s<n!gW2_aP!mj4\1G"6fA:3./>Y!:&bP/+NL8:4c6+_-F +J_-[E[sV_J^Na&RTj._ 6at+M)2&DF98d.e;]b@4%KA9;F";Ag-"t8>l(-(54VB$\=lFO4[5tqc-,QtinJ*5]D#i14`&C@oSP9n,ma]*SXn3`;)fF6GA(Q_fl"K#gd$T&_Akelq#%h7kO2qN*YPY*o_8'2gXSmE,Y7K?"$7(KF[.C5imgT%87;WI^Tnct1@N\C!+qIT&a!0U"[)).N>,K-rhQ%p`W'RM<.JY@RHepUbb;?-3(a'r\;"hk^d[7Hb-95b(/M/f4"so2f--WAPQ7-C<+!?B0SrE$eb.)m/-`A8+-j44d6]U"\QQdq`^if0mrDqa`P b0B/8cni((k(oTd>Z[]d8k\Glfo25A)^[)Z1pE&^5dN4HG^($FB4BFg%TK1^Y(:,M+>4os9N=d[AJ)qZ!o[J9$F:6/G2f[o[3D?+N@O4:U29OLK,acrJ:B..A%N[o=n3%!U5jleoIPD8Dc)SoT! r^B'a4=+%lp2%(*r"]ATCh^+\[KM@7 h7*9-S(fc_eaUK\AA`U+9P;DQ1HPb@Wc$NX%gOgQ:g2dR>0,e$g;\Y%D.BT_jso>FpDAFI$9I?FUMS1?$iI5enW`ICBJSP^Jmm)pjnB3.%s?-MH[t$612MJ_B'"R X\$aV".J!sEp`q<'>[nbZAbbm$Fl49A?LS%Fd%g;[ggO;FQ-i0B+(CS/-?g*Jm%1PH)gOR?4Q\IogY-JXn8S^Qf0AWZt=HjmS[)Y'CjWrSUA%1&4>o`GA$gUU\LS[kB+,r`/cA-J.KWbjd4]X-*$g P\Al'q-d3q-AfbA@+_7k>AtIJlL$$M4qo21\SQFLo1_V[B;tT>!$^feIPTK)/)V>EYiEJOi`_) ?c7Bk1)XJX#PtR#eAP&T-j2i6.=4tsZm\Ht9XAI+;M@Zj>lh6aA*P^9Ymg(-nB==-!A!JrP@Ujn,c[r*(jRfkdp?C`Ka'\tCX"c-]eWnE2]?!>E.353qKs7+!n 6#@GFonM(-?c#7/U `%=RF:Mq*<"(TX%6m'N##4BN`FCU]KA'IAZIS6Yl^M@.Ac9lM&j+B^nBPM_F8&U9A>4A1\,?]Dm"HjZQoeBS+g@P*r(0$h-(o%_)tF-^\Zaq[G!a!2*+kZEg1FIUQoQ'Is@!O-q6,RDW&L*cfTJMr;Oj@K-m4'q.h.&*g>6UZ=(NAE6(&A`Zt6_.a"'B,/4g6Hfhln\_$VK<9b%sD6DS1ik7n?VoNl2"AkNMRJ(srj,ggIqTJD7qinH'Dr"1T?,?%hclAMI"nj1["LM3$H.A[]_V;R5U&`:]b&6Y#jVf)[s2<3^EFT@'1k[m.sAA^O_^LFL59`KL#`c@_.37hW^3D!7q-d+sH]H"PKBbEGaao'4X0VO*q_]DiJ#ETa`/.\VTG:6;/hY=Wa!&dS'jIhi#gQg53R29DWgDB2mM!@0YmiXSUjT D!&gnKpPXUESfKN#bk#]%`T&M!DV5H#\6\@D`s#Yflk3&2%qXLo/kH-T2+lB3B0d&IsS7IA^oG>>h%GSF V]s/^>I\V7Whb<_U5;P;9SW;iK^'9MkJbf-b>'I^DY% 6/p1lqe$rmpi%@9QBQLOCh9Wa$ABDN&:17**U,7=]j`42D]FA(X='_`0=&J..5R6qj#'X=_SNl&n<0UYriB=h[1YL>bUtqiOrXhb)B t= cb@@148"gmJ<%kTK QA(T9]RnQM5*,[3K/00#\qa(\$r7 pID+>)5j.mCf[oOPbk *Hq]Un-2Neb**1fRf$19k]UK#)%#/icFAV62!V2K=>\f3(@^SAhR6rO9i`c?MtkINO)W)6m9r(H2'PB gFG4,I[Yp0;d1!BqB[S;'L+& pVd.dlcQ*bXk:70KQ;WC< <O4 0[T,\M0h3dL;rW*\m-A%C,B=p:F/QK'WOG47'$)1C*`/I.tc7*``C7q#;%Tf+P&?gn jN,t22cViK-s22LlGpZsFE.Sa;f\QVM!`piM`[X/BOn;b]@p1I3\*D<B#Fof/F:/4Jp5X`4!Ab`/ ra4j:RFrQjYq`!8AA!a;<G*is+]e:%)$;VJEFEEB.A^piDC\,Im^#IfeW(68F8jA%+/Q>s/BgLP1DB$OV`lJ`REf[-Z?cGs;A?ec2WMM)E5QT;A10:]\WaUT)s%-iC%7nSb6>=Qf#!q7Fjj+#Gs X$k(m9qAm;M_4/:AsX$Q_V!L5@1`aisf--I,&;AC[7`2P4,RNPD45@N?C`k!ZR_YRgfWtIfA*6Vok#S+>E@>19/TQVImrkno550EkE"V)c9'Ak:=[$#_,JiSFUg'rJZMD3D'fQUcZsQ+*q/MbR]JtbAA;O?Qf.X,4.#q(WnbNEd7K_@]eeqZ MCJIP0Qjl<5XA#+c(53G+)42KD1'>-#71FPlOpT:)L=gpA>nio"mCS/C>c^t@An]C_m?Kg$/\&fJ3U>TtJCaDf&!+O"S(\&i!0'Og;Tm1Z7t@"jbk[D[oI1qsV4"i@3Rcq&doS$0o-1+U*T:MB!>$E8qA:,s4*UFg]8P*P17W2"*NZWk6$'s2@ `bOp,s1C5>h0fC!gX`X@Q>># BH'>bB$BF%'kd/j/8KKIm7W_`R4Xa49b7+Fqb4O.qc)A`iVW&6%S!,6IE K4o@(lpLEUX96o=SU#cE:J1HKn5VFb3T-kJh!!eI.b-Mfke/EhEm7T0U7h+q7K`Q*]D0X6o$H Y8:Zi`Wsi*VFDtgRdiPY,A<:_M_`^h,YZNG%YhF:_I7*LF3`R.<-.0(o?; F2,A>sW*Ci][t3-=hpVaAQY?Vc`R@$2cY;'8+[,kc"r;fiQI(6[_GF@TU!Qi4NI*?=0/s$VR<_YZIdI.=9@]gakFqn4@on=`"Z"`/G!59#%^lhAi&:c-"Y1oN:dk;isr'Y7FC0`hEAoh6,2` Q-K*``XNoAc(gpA!A=[nB- r/\R;P`(=7j:UB/(W\F!L8+]h/#]*;tW<dP/ai#piqZ0sXqT_(LOb*8.=QQcln\CWLL&)aA)fGi=Q^DN$B 'Z/_^r$O$kW&dU39I"'[E`)$-X$\9 CI04eEc*'n(Pf>C&*A/Z0Y,Vgksst7)T^Rfi9=38]od>kZ\$]h*9cUU,DMlqhdQJ"?h^/;m:@:%ho@6ZU3'gmrAhEq^D2;"=8[O(h>Zm^,jO18*&>tSt4UreJ, +Fk<,;A1Jld[J(W2D"41o[jBL-P_Sg+RI)S6jX1.<>B rd.TsO%nj)X6l3Qd8@W.`WN6F^j+tJg]pdf4=?q@,eZg0&*-ALgS"qb*St>4bhsJcZWA2!A2X"Qb`'Sr@-MVjYLo."C@K*VCFI 7kT1*A_HBA^M1i\j@.^b`NQU\o/c?'Cs6%hCQcD08#J.2$B;aQm nism8,ZKpAgh%.6-UU;le#=CURN+:R,$5oPeg7<.1(okE@\UHV0`\e @4Lto7<1I-jC=PU*/0rX*jjAO>U=7q*/-4\lWG>#KjftF@`/SB_cJ1h9L"as=]ZQ'0N&0Kf`>Okq:oXe*]j'hn;[[dsd*q`5kH8_TkB_4-ESEqgMU7d02[s#OebDd8tBH+jo*MQ s)F$.-UKfl"9+f@4'bd0XsbR^=`NJ*#`.;^E,ftp;/6#AA1(VM\E9m>*4tY pe9V\+Odq+V4VZtYmNShEfd9s<a[$C`3tN%HWU?,p<CPL_@WU#Tnl/nd^ DaR"cW`HAHPW" 0#][5A)`'LTC\)%4Kq"\2p`O,;(n5TVe.JjAtWtt%VBs^<`ZV(m@9W:hSJT#%IA,j5O+pA7Nac7B ]b+__q9>JnP3Kd4,?'R$;$a!;PEoDHOL\GO3R\Z%*^0-7g_cpbSYgI=U%&?Z2JN*"c8+/g4n,MUeG.ACAd41bI%"%1=A->InkNKHVX'AU%LP^@0n4J=Z+:RtgP;#C4#r5!]4kXAh/rtSRk/tah0h#qq6*UTRW)`?9;_&agZ@<J"L(d9&%$&W:rIWCD;q&OH7<8@nC9:@:E[7U/&#.SKi/)1Hp#1CV$[!O:(Gceg60Y!a);BjF:gbLWW3,65%1qEJ Hj;+0)$rN q'#g# UOcf@p,^WAsoi&Y4o(ID6&l5%sAjAq-+,"`JUV/B5HY070!'F3kNWTSb[A9!gNFG9%3-\^*Ieh#e9'_2]DnEg3<:&TeN#WSF'0,llsE+^C,,1'6\LCg/F/68aJrSHjY[BI1'&/`Z08'0YJP9&<=m,jYFBl N'JJ+=t>UYMrtFFj53\c.Ane6QQY,%FtlTt[: _>\P`WVoMnO]E"ne- BL>nM?r_L(.7P,$l <'oV0+_+h.-Yl5hLP_tRUMYJ]#`/5@aW[0;rZ(\DmXN.XR@N&jW8_RL",/`s"4V-[l.VF&DW1%c.<-5p:fY$"bCl3CNM[-9Ji^tngOUdo9WODbYcd)3@r3#hHR'3/K&/DLA\LNkD dM:XDU`=)S3tKgZeTSt^?@Ye&1];%b;NI4qde#_^Q+mSk"caS%p.NAIU/6/Rqq9J/?X_e/^W6"Osj&3QAcf,A)+s$NA7=h2I*O PT7!jOd/(5RU[j/[J+P`2XM2JK+q_f$bGlJVM*B9C@IWNoD-!>Vf$ClFqj;J5\@PX i8T!PLA@M69mfY+$Hj&GV36ko?,P1XL#o#5N]+.>Z&k])W2JOC-,Fe,@o>@H+/];/0kkj+aTqAHmYBfDiW_:I!JApEq<`,oCX2DI3I8ls4ZX/CmRi+_LMX4)`/b+Egj3W<&Yb)-,mq:[$).fYR\230Q6N9J7pJs#g"EQ\:O-#lp)@e`NpB[LHo$_JbNJpt&-5..ct@gm_6)]A8qRtA-P1b7-r3X, V<^OHNB!VLciffttgVP`1XLDJ!Us5H?daa?nspLARhrasnA:iF[PYI4g]5E]6X3EUe5-3AQsMm.*[J#*El(M:SIf])\A@hJ6?U &*Q+sJmVC sE[ n5!WVkb!?+n"Ab00Z8gnQ?i=FC2B%gg5qi;k#Cg>8"2o*6YpO_5p7D4g/c6ESf&'Ao/TpH>WhrpA8U5tO-g#>t?SAgG/-h9<lAL54>gYZ9sAX\Gsc0m$lG^/%%H(gY+E#!.iN6BnR`Sh8;7.-ndY8j2jrnC92f6GmAq""UXsE8-(s+n_3rN&04pj]'"8#TV-W/etb3T;$q=%>Wf1S^CEZVr7q6HV21L`<pg-f\0`ifI`/fmVe6Bl!F!#'UcL 9A`Ltp$=bS7kn3*8cc<+3t6cr@^Rok=*17%(KJ; $0WRPg$7#h'--o22?aWnC29!YPe:b$mhLU\XU0&mp4UM=Wqrs^htO1\>aCI6X99s_9C_09XU>4?E<(Di:\Rr&n*^]DWsZAI[iXr1Nr?j;gfRdO654c*'/k-D-K'k^/)NTL5n!63.>(&`hrYB'/-2c4lkKq]G YijUHe@% bSaa!gbLLK,NANVFKeKsmA^pb0qWgWt6K2iFSc&h..4+l)q.%)F$C!Jg6*ofZt$h'"\Y''*`SRa.ct)R$ P2JRs0'eos&9V5Gh"&eaT&?HG.ZUBDEH*gD&TZQKTY07"i]t1'rY8SCMZK5f`A5pF-n`b)U&J=p8?^>+&SG'sn#.X(=Aqm^6S)KD@8mqG/(5]^Z4LG[kML3$>>rUX7]Tr,kA.s`RNDea#oA)8Vc)F;NL:JSMt_`9FMlVLi[MLLAU;Bhg4qXW6SB-6S+]!pkG&/IZE4.J&p\=b/Z6EN9*!Sd Q,S t3mfRlZ:$Cs6d9f j;BU&&\?Uks_bSLr<Qg6XoeaXK?M(U-TeeB@oFNK_ Y S]tnmL?\SgkPL CKVOdIkl40HVapSC& h8le+Ob"7 J@#(E>.`P`IO(gGW1$&)m,j8)]FGtht?s_B93RKA0!^?f4_G!tET9hS6Q0/33RC$l'-FfdHs)RAH17:IsPSD3Y+L8\e-)W\d`qWrkkoidqt[A6PhNX?Hc,kh!,?,0i#TJAdmoaok['CQ[(*J`8=@FQjRT@NC31hk""_>[IhkY3E/635,_J"A`H_8GP=<.%rl'dpY/(`9Cp&Q=>(t<$fm<6:/a!O ^Y,%1&0 ghC&!F0'A5dqn/LW?7ehD5?>^Q=)ZB]0&lUPjW3B^2S1D&%,c%m*f^ @NT>Be<9O0No`VlQOVYlRV+=.sA_&ll/5n,@@m+RDkB(0Oo-E6$VLZX5kAmnr.I+?h"Yte6A'Ia"8,(=LJWQ_b-#UC%m1I)6AS6$rJ1G$>Y(C;;A77A!C/B2X!Y1$L?Y;go.JT2WpG3O/al,H/Y4TP7\ 5Yf'A&^;(5d"kSGmmD/!7(C<la8B!L#:b!_UHm9,qcc9"DYAQ't=$jhcAQA3"[&tF3\rs;<"hiXI3I(#CMFk0&^73Y9E!aU:m*27;!4AS`,X`K9JgWoa?N>1?a9Tq/!BmS%(+n8iJ#P[C.9\h6>1$O"5mZ?=L>UU7+r7A)g?g;)Dkcf`Acq+bUWt;aeqJe&YNT&U-^MUctE8=P@"M0Fs IZQiji)(!)3I%2:)k&Mef.MfPP2-b!\287:Q O43G%D^9T1e$/B6-_8JZ[ 'JKt&MM9+?&d Bb8IX-'tSaYlD8.=hl*Rck:+T!Y77.9I ib2EtT'^>A1YnIIF(A?QPAL-]4,jJb'g^f@[NRVO\bU)jTfRmX+m0+B+^O)+FDi*4IYq@m:#be*i"F^8N8^f^TJ!?W7$Ho"65r8@s12=X ZgBnWj^XhnL5i],M(#oFKs,YE"=Q<(2.s:0632=M_;Dbeb1Ka3K:I#NQZ)92HD1?O%e]Q"/0iWXY&Q8,7!HJnNs3tY6-($@L%^Hh8EHL(s)tlpa_t;+lW,]"sR;6(AX 08Jb3_VEBs'i%$k."rbc]Y(J"CnC[ES"Z?)`pQH&)P^T#V^J3Uf%:B^:1PbkacUf)p-T8Sc]AF2:j0W:b61-]N1khkK;^T-GD,1Lj`G\S93cH;?;df]meBX"@Q61BW?;N\>HJr@b6Uo`e/FJ+=>Gda\7lQF`2D@pQ\rUg:_M)WfrR-*a(:?\:BnTFNmO3)_*741ZFb9?L\VNWbUQ\ iNOY<'=m[!K4<:N&933(!kAQO+0ZMh>:<^.!BL-^LXM:sPMhE >K<& P$$UKZ3-Er`ZUO'Oc010APmiXmC$YYLmqDOB:&JJGr0p_h`U^2!Zi$O$+qqr:X2QU7>g-j$rBtt$:=st_ST#WiWG]Bh(m#U?86]Ll=[#M)r'K>Y(Yd;*Z@OPnc0O6WBIAWqE%ChqLXP"4XRI6g>d%Oh2c3Sl@FcA+]9TN!1)5Z_4qNR!JW\(*OHor2E9Z YF#ZW3%GOHbker*[$1[)V/l'oNts%P3Yq0hbc_\G:!%42PVKSTEXk)ZL,`sRD1Z>Ht]ioAri/5?oa:%rO%/f\+lI(de*J(!W[Y:,fF+3`T2I12"[ceY`4V&'#Gtn\ H8MPfCF"l*d1/4iHnaFoJHR7tG9rPtsji[AL: pY?'VlW;I"31P ;SQsd6<_88#Vt?#0q-gZ?CY%]D]nan26_$07m[/5'm?0>)^EI@q>a N:g^9DMY!#g%)ZmtXr[T6"[]WH&g#Ds0tq9;WH9RAra!0qPA#0^AM#s_&OM0Arr/Ng0Ym*A"MY`+GmNeHKVI#Bk4& Q:oG-<J@=KXRgr0=A3A^P4BnL>oWQe9t+QN#GW57cYNorf(ETGA(T4P(^CIF;\0s"r.T3QQ$Qn1.mk6a,$m"[6d@91Qrt%s!4.c7(nq[n'"*c0A^I!JoZ^BlUrAA;li[E-fC-F_chc>/IW,/VqFPOM*1+)(f=tmCBeJ`CBc1jAZ<'E"!pa%_Ig`80;/4H ;$'Z%9eJb[?W5NaPtG9T"tfC<=HRJhdRT2GRK5rE#9*>)5kJ8KD,8ap Ap="lA*c##gWa4A-c`if_oLc$L387$c)*TNVJ`'\L?Ok8lsV!A\?;?]46HkkRh,L>aV?"A2I$N60>K.06:4XZDh=6MGRheK(^]]EIID7ocQXN4B5HL4q;QS\>6qp,A3"G"GJCo"Te>5ihQ3`3r<(ctdP&!s)3ET*8&ib:1Ak08U0G`?7rg-AAN7&"lc,r?-6@%T-If4`m`/1Nq>m-Uq\hr\tl=hM:DH@YrM+n`(Qo$h9[[!6AsA7(JCm4J"-D0Lh^=$_OpM##ZRb5-&>iT-,l](anU0gdZA-=&-ag<7)glW=ftg_kRNQ043b%AI=r\!Ab6T&I!QCGQiX+[ADl:?%J,AOm#HF5Y6>/6Ls(U?lmlXW\Di?C6[a-[%$.Gl$&]9#d:#)rk`6Q`HEQ/ZR!dQr_K?;7/]>l*VAf;6-2O"#mFDfes+.%=CPbXX"0s.=C]Zhq%-r$GDC1]fO('PM*K>qB.H?9h8T0pZ.l<9EPlClV&_C:lPmZ*P+Q0\;c]4WdZ%==5Lm/BXMVTH_-d`::Ol*7q1c]A*NNWKM=-/>O@H$a1c@r.=0@;M*FRARei!@a:#O9GAAO%Kds&>ddJLcVT?IT$-AKATC8^MBRmm(GW\SX/WOIPH?1imPf(^!U&2A=(nXd&^(]XQ"AB. =KtFE$A,-8/Rkj^7>cYE,f?Je-AF"l,CA,jS>l`Z?&00JV$_X6262,/n*m+enS@*k1IUG-1f'C9QR2lG,\NcdHf^*N$JZB_#m"4`Sl cpW/6,)5nI;j48=jiE%4X_PFnH:EK"QRW?HZt-L6C#?V6ng iia$VRY>/X,1)C6*aU-mO;Yp"`Kb\oI>?9.0_E3bM8F)%3T:=T 98'L^C2M,'t],;*2d=(AJ?AA7LL>)+cp^F+5)^?Z \@b.#E=m%WTs!3?5A+Il_aA)*(1H>]nC( [o9'5b5%Bc!k.I-(?Ed/Gn8:sl-(Z\LA irQ+LAqelk@EJ!C`:":bpGCT-%Wism20#Nkm0lX@fM1*XR.Xeh4pHSHn=0HUL Vf1_r._85CGRJZhi=Kf=:a7(_(=ARSeai-bX "*&9TZORq.62:6DcMOFA(=NN37F]q1Xd)W(^L<Hp!"DQAgg_XTqP/(0CoEDhR+@Wnc"@2Wtod;\/moOnlSqf`VCehK]cI4%5&=`MN558%B=0E.s&G>5mj<,CZP$KDAr_[0kb7b4K"i#>= "[46g0F/0pPWVpNXUHgOfiV@&b=r* %s2?([p*jG7&re>C\qtb^_Y.Y\KT7GS0@m<0E6766[?_(c)H7JSqT67AQd3&0lUp4.`jiQ'41[,CQe2LU*.,in47K(`d/$C#"qCDHs4?L)rb4,H!]Tn7Wj<;j(f`rI90'$HQL231/4fq3A"cCd]Ob-HH"9`t?89AhYoDV#<\4DWdo0;9PT+9ba;E&.5&(s,,TFOGO."Aq\gn3-r\5#a& FAVPE(-fOUcJ$;*JZmD\b1fZR:'2'dS;fkfEh7B-kqL;FDp#s+[T'tpAb+cMk\819^86`6@'@k'mm!Ci3J1%T; p1TgG1mlKRe:C>H@N&lpR>_2'RG-7')C 35)H0R\88.5lFP0EhdH_FRPRRA/U*7op6c@HrKbo(_6InOgZOL(I"d12 .7';]bcB=PA1\tD^J7q oo$"`"=AW7o5M#PclL?%Y>9P+/+4I^[k<,08C\`o!=?MQdHI]SQm$SGZ%r7LWGZ_]Nm[G1Qi9,Q`Y!bUF5o);(q5rdohKafk-/)pi-Z/i#E/1Fpn&3fXEAl2$gAo%!9@*RDtW/")#H&jF!o$4HZQd(k#bT5]1qaY55B5NX*qAkh;^JAdlUt]tG.%AK6)=G>T0Q[Ld+$M;-U5mE8jc7%!QUiNae55V"1LMVqO%C001oeA9\UGglJ2QP>,]j[F?3bV&_X?N>$ mZY<\Af06H.HP"t\*a8!Vck8PR2io0\9!?[!>#]lZh*i/l(2m3%ZkF513FWEET;5f@?OhF&t6AKbYOn>H2g,$[\F7Do9-]dI!#!!=3MO*])A2L`Ii5)hV]*\n6;L4IDPgo.Rtthd<>HN<$:7@K9:!=\/0t'$CPsc(lF?jXTm*gA_5+X[X)d@EOnQjd8f'+ho-P7 Bo&02Fo>BaU<5jFKWrmm*3=9:M)U6MtbAX9_;cq$8eWP+YZ-VsB7_ZNntt;!HY5o0%NUq"7Kq]D`r<!6"W7$Y2P>Pf"%!@7Bj?nK.t6L%(H(:r eJ@A&)sjLF"OI/f!h#rS%lPRV:i3fhld]%\*;C9PTAJs_+F+! Srnq]BHjI4h;6AA&,7&j];Bdl;]X]Z[;H+.IC.537HVN.ZM1WFfK^o4aZ4#f:.Cp!rK"n+Q8q_@+99&AEILR4EF1*kV#Zi17-M`+#B-%C(I\ 8D`9EkPjJ:t@\;LAc(P6#%em7NMI9HhmZ,]@[#lH.W%&ejsADRKVa!B1o%!RXJa)%98 arX7!r3!f($ZgAp%d:$9;8%Xd$1.a&kZEKbqS1 *TPbtBYQ\fY!Ct\- bBAt'And8N/Z3elFBm*J/J5:qY)A,o@&`f,q\Pp.fCZf\E5JB>&\`2H\1TP4Jj*&IZF`7"h7MgNVV)(Jg[2HC_O)ipS8L[^'K!lp3re'pN*E"$M!GG]_f-Zh!]jMotT(32."?4;=o*"&Kks9sBRc98c=gGCGoP_=EA0R&B4;qAQ>95+4L]mP>%,$(6=@G-GO'* F@l>I-q-RqFB>?8@7<4Hb;(R3Jo[Za_dIN$=I'W*r-/.Rb&.WK*lnL`iVrlYa(GNh62Gt#Z4L^L(o>pkCn"oNI6sF\%0U[tLrdpq,l&NWt4giAdE&08K:ar6nBh&kH+>,5O:EQij+M_[@g5tM%TFAo#^naVFUEX `cEs/Fo-D5i(WNQL:4`WQ/&#LR%%>t 8).'fUYtMl?QI/3KE")l:.7)J0)Rr4p$Ui/?rV_Ui%YfeV9i=lGNb-I$HmR>q3(kdPB`LZf"&*%+"X*O@>nim?@nj+Bdd\a@i7tne0:hfH7WIJ75M*)?FUtYk?GXY/I"GR]gl/th[Liff+Q=hc.U&p]r<7Yrl07:T=\:(A1pltB8%dS#//>7%e;K_""NbN($:BP-i.aC*T?AmY-NM"_oDFrY3-pkL!EkM=ZFes&KC\/+:b?iA-KHX"AESPrS(*A>F'X)+=s/`!pPje] \"(EF'Gc&QT]n`9CM8W?4kraj?*iYB,0[FTt"3#@X(.\VHE;20 m#_da\(c$]3@CS?*s<ld9Dj^AW"k0$htA"BDK`f,/B.Wp=1W)LaA'Okjs)U-m L[n3V@[<%e3-gC!Z)+_f8i9p.'p3 #/940)^4&P1SB#.66iPVn:T7c+/rtgOA-CaV$%8jEc$ 23QX9j<9lC[Y_VJp'1?l"577%U>>(HO?qmi\^\HFeU:R$Ik:^*C@d?Jet.3@`=Ws::id[qSspkk6He;"kGSOpl__Dn@"!&9$IEUQtUM !i:X'G\LDpeEs:h1g4PJ]GmO@d:lkc^t3(D2WFM/l_9L5Z4#,/` F^&1:bXk9C_0jM!bdcd.j.1?s8O9i!Wg_P8=W13AMS+"MEf9j-'Q)^,o$hnsl@)d#e>l&+Qjh%hO=X_ZrARVQlT3N4Y![N`7,h_VXkEnnP`nTt\!\7!R:QTEK+'fSo%)kD0:#ZWe=*FO3Sic]i`F[W1)aY9kRIaS`@1_H<`hA9.#+.W^`V)Yqq2Hn7f:.2;a PZJEKRJAjQUqDYU.`Rm4*LX$Z >r[!R2Y*.ROnXYk?+]JJ`H/K6(G+(l0n/)tHFN%$P,R5_S]B?(AZMH OPbCX$*)T6"YjcMQI^B+; %:@\&+A$KTVB `M+)<@TZ;7$jggJ@b]V*[.jp3;I)$" L**>X+KHgQ*N&PDG6C[Ccs"MN-gl;jPbg)fdR+^_Ds7'`UeMn1,@a9`A:SG]UO]rCqXtQ_C j>AaHtKV,$-cN@D[O`?-A,nU1#!1Zd!R7nb@ZG6+6P''^ZhCNet:lR";8&l=3=6m'p9lA7m=Ht&g,?H"A`ah=qK\O]Kn=US6cJBAt?5Ti)Q8!K.MeNKn`nAU_Dh)=Zo_,R:>sQ+]O+tX&b*Op5*N__mkJdO*-+#n%3pn7?E 0A/pS`V9:VCi+*40;nXU[WBG]t=O2aDBU9(fLUH`AK(TYD( 9JJ/[#Cbm19n'3H,b(Ob:rprqVFfQt; )b&@WZ(tgah#SAJo+W%?6gh6k+*20T;Dh,,XpS36`4"6DX-nB$7lNq&X;b N,f)T?9lbGVFFL$B%9ofD5\5o)CtthNA]CWLAn67h.VS\Qp[7++]s/iZc,ZBJoA1j,C,A#NIBr6&!H>d;F37(A59@btq5./1?S;.F*94=?6@PCIln`M1AaBoge7C18K%JS0m8_D;ZQ?W*4l`1Qa^ [[[^SG U%ZMXP:.4>FpGV('i@fZ`bD8S34<Q';J(")%BkV-jk2c?RljcE$Z"!FlS/( b&k+e+o(3](Mj=jl#is4A&R*Wda-UVGdA;NpS/NCB=3Z_m-+fs2s1C17;qf*]k:*EYe-5)oAS=%"g*_\pXGSAb&doD0.f\SUjKO?13_1+9X[\=KbSM!0B0C 5PtgN( m?%;gP7rG"-Y8,aqtBXne5"_7!*0i/hG&jNV7V5FEGY3TW=L$^O2flhW?7.T1["^Ef+fk=&h!JSi9J_+t226p>8K:`[l^[&%AOI)oI1AIE0A@2mNr*MKAP)W$>l-,.s$614h&b:hW@eWaO+qS7/`)EZk=P)@UtjI)6G^4DiWRB[GpK)=:&YY @ElO5-P+%BV\8;_H=0QV*En\TG%_YM@@7,c@%[3TDLVNi33!2i3-p4UP.$i-653qrVn0&A0F(n5tPm0o.l/SWe%<(9$pSDml_9JgoY)\SQn6:b_>TY&5/9_BmY->iD!@n(W!0\2kS!928^B  Jd%jKS?l+S% GiB$Bk(N74jEcJeHF_ssI[&E3T\R)NE0iqRk^c9>t H3MKKH0FU73U(MU&V\IW\F"A%5";[ri=#A`oPY$=Vo=/%il;!A\*D8_dHL%6S)Kk2IIXBBY]3s9F)H!&$ahAOhS1?18SY.b@WX,.\SJEfbI!78Xg!U5(=N<)iYWOJRQAEIi%s!#CN_[/ 0#aO\7@2jepFrO\^ToBUKf@74VT_rg6/_:kZ2R?,si Ks9_oZFd:A/@\^r'@k^mr'6$KICk,F$;@P]1H[fZrfpWFbg*,f7[Ln$4m.+(;3i:]/A 8#P&fU/\ZI*\O@Y)ai64fi"#_G<@4N2>TDlRMe-o$A&a=l9JWtY:;*5*L.>'rID!qop(R=f0SD*S"0j7Sh!@M@HWkOBb+QHbL["*.#eq3,j;Ri8sGq:#6JRj)Z4?m(WtCZ@DHo>W$<(=mS7*dI :.f$X51B9U`"d'QCCr7s1E_,GfqS)N4Q](>[:4m14*k/'oW&g")9i>F=mZ3YL=">B$=T1O=M4Y@AdaI7\)23KEcM%-B5cQ'$lp]g\1LLm4Do'I[[+[.KSY(hj,[=A'QAHtZGI)iSB8.O-pDH:K6Nqg_AY,aaeWo;9&.Z6!lSP8$WY?%Ucf*l,m=.J>X1(+=ro)$hWSRY<[R*ESAO@kYE,+ZE=B12;UBgB[r.`HektD.RXZfAd=6tMIr0mkAgXrBbm]%hJ$Ia>?]p]>.5>a;8!ZLoc-eC(KB?3(+^o^to+Pgt:LT4Y(A 70sos!rHMEpW@T [=`SA-,jTCB`(HbKgY(!]S=OiPMRDP_kLd_V\?s`^* a,OXlt>i+6Le`,t'^_t[@1,q:dqPA855MEc4&m65\1j3n.+_J0-V 1jej!PM4LYrW],HA]3GAtLF*c%NpR#eAK7W@.CD08 .K-4QeTlr2A\R#P6:t;npdCXPmE;=M)H.Ao2ki.Gk^X7OS?jRr9I4D cg7U]'e69-f-Gj'2(h*.js:I%FpTdhnfDI MNLcQk7B+XY\AQWZ.M;&N)l^W9g*g1)O>cIh(t]l=:g.8MNR[^^HpbAEKhN_VK>=/C]'e@TKAiigaOjofP"UTKJ4?g)N,ro=C:q:<=Sfg4pO#BtfCrk^4*<$M_OI6>\V)"m[8?)=9K.!nH_\@,[J\l&$o4ZS+W_32GH\QKWpRSPo\9ST>,*YIQXj54\O<K@R9ocIYA#a@n!X8+IUq'Dg>aWT+KqQg#rCIpL%:/^A/Zk0!&QMFDtt7ceOoco(0Z9$o:1EV,bq!hT7QjUBK@FRVXA)b#FAG<;c[Ad_&R41&&P<CcTR'taj]EF(fCsFb'/$Of?@1M$!(.'m:Kb`RAXh[X9IHp/ ZG35b.TZjN*!hb(6F+/qUs'@A04ik-#?=YWgjc'Y$)47J*>">oU5nkr'tNTC&bnc,nG*!W5[`8sfC;aF+tTG8t9>1jIf@nOAaEr]DU$chWZ61 )fB4In+i<.]^0af-pJ/C8RlP(ZA`\mP;T4h"c[VMr1X1%fmdpk)4BF9#i&*WbY+A OG;2"V'LML,qI>V4P@U6H\%$lg+D>=B(I?-Q+-$Z&+#mL8f UffC2&RTX"hk7eYXi,55tjFO41th)'T*cSD/\YDiRmJ&4lQD]rrF88apB\qZ[Bs!OX64<PGR$adA:GTfT70q[W*X^<0:S_aiHQsq2%tT3]HYs%IYU'm7Ke\Jiasl258g>L*9lPXApK`SIA49YYMr/D;%*1]8G1j:A#o*MP?N.+=4n=(fW2KLhMD)CQ000_A%XAa^n?a1!ts1sg/V7Cp-:6[fI(YQp*i6AJtf\):mj+)`"[G=P9FVQJ\H"LDYi/<\I#aKdnn3,$eeltPj#iEJYG\(R[*.s&U!KcS).Vm^tr;gA$kc\P\?=+AhU2%V<_Cj/KS0sZ4^QR]pVSZD\:is+:-GUH8i4HIJj7B:tT63-B_m9K>ChXigVt\MN@BUmBDig5A)4?;TjAPpW>6Ab(jdh'\!lF&IH,AN!Wbq E&=ZeNW6:ci%"_Krid<\`No2Vq^]KG>RW'C63MXS1o$(jWI/J>Xp5=N4Ns2S4d33ifOM1!A$&@4VU$1&#-btCrgF""Ge^MR@TD6)Almk!ZgqKC8OgppkZJHl6ZL tR#n,31n]$i-)AO4)LKM?bVV`b[*A.k^R8 9>/ZV+pP(XNi),k(\X F2)T9;*?$9K"-l^#K``8m<@Rd'\LCGqshA9FJs[2Nqiik))Ek.M fgWa[":])lE ^igSa+'4FQ8?O*(DBWH\?8L1qXY(h?k,=i*/=_]l$%d$*cW+5KP87`6RF#c,1r'K6Sg2=&74Yd@7,b`4"95bD(e'UY)YR#kX )A*9.q0sl,j)R^(O'5kP7!jMprGFM*!r5A]BJ'&pkPdeO@Q[B++1KEPLJ0`1MbqoS!GgCZ]-)aDiol)cq@5bkCAn*@8 s-JT!R*mo7PX'&]\A&Cm)F8!1+a!rpK6#dO8;0:gC$?XEb6N.WQTK;cS%KF0*mraSTAP-E[aSVO@7>5$1E##aD5&,aIZTkUE%#9W]C.5@=8(/KHW/t.iDZ]QQ5I=ErFf)HqLV_J)#X&FbIh*QJT[A_Os-/#f!Qgb\!KArLj!UGN#9gl&k3*X3/g;:n`dY-!Y&#RZG8Klc+PSQmQ:e\BMCgJHQ\Oi!jVO!-6g@A3rmb\pVq*B0@5r*ktX\BAdl-L,@@GjBGS7AO^.!jU%icc-^+@!!nTN/E#9)1"m86qQJ$)i2^"e>4*h'&'=kETF-3I(=5c7,bqY5Mc5c,'R!n0hr87*phBM:%t(44jM(!F04pg"-R]DIn@"d`'A4##B;X9d`,R1S%n boGUpSY!4helQV8#69MQRj.(fRJi<;'oIhK&Va@g*eo/k^3O+9tOA)V>;gZ*M!CGYoA^Mek(+p0M7AY9ZY:sS)&7Q+(h+t.NRqX %`1)dh4q$.Ib7s ]SGKn[Q0h]mm+G3IUS@/bq$C%<#2#k9scGN*V$/6gL!Tf@.FF//.r5gBY?9D[#mGbQ+paH4rlVGsXXBqJ-E.ZKeP0AKQX(mPh?W_l.X\I@UKb"rHrQ3n*5nk3L_jA&4`@SkL/4f&,UYsrA1\JU75X `<2QeJ(4,(s*SYAO5<-tNh>V:F^p135lAmDd"#FA2_U@raXOmOqjT&=IdAoa"88UD_5e*=7Yib-q=ier1/b>(\b_?%D)kh(A;A,9Y8ob.WQbi'S@QsRf`%C@%F]qsbq-e&il3-&s/`riH3;+8M7>amMpJXI/XoHAkPKpXJU71$-'?>eo:XbD^N>1J]NBq:Xj9aW8L4"+\f8[r(Nk3AB2Ca3:9M>>(>r3ZP%S7K:Jh5'_)JiQn"2_ff6>#0K/hh2,*,dUbS(UhFeRsr"ZO^p*qM'BW9p8 (/EOjJqM<[pbme&L`2XT/b&$ 4R[GI8.6ReDO#/HEA.2Md]DH0<_YqiF;]mFEX?12oq,NnE5qIV7mM, k+a*)D3SQY9*9!Q?=g[m!mTe:jmq&jAQeCad4Wo^c34ttXHq8Bf&_*11a90K"$Ti7V-LCJ$_\XHOUe9';=>pfk5TFBpgJ.\<BA1RhL6Y7^tP6=3EAG=JlK\e<Mj^a6c-[d=VG/#L-djIrjB._(/KosS>`)$rV#[kDp@M@%)Z`2MQp&=kq-T*-T!`.D7*e*_BM:oA$`O?/,$FB>,^7Rb<`>?QNp0&P?HH\6e\ZW"+]M.N3GfLPSJ,&$UHZQoT3qk<7r'RJD9oFYcY%X*LdK5l\M=VVG%Cd`1V;0AV:/@.GP@&;pMo/%70[36V@UbeR/bqp(aA;/8, h3cYKhm8-!X>`Ak@.=KF/Kn*Lr9A2HBMb+Ma5=6GlaJJ7D)VNsYn>kS+[1W!rF-2=/LV(7ee-LM%)b]Xf@?MknFlJ?6LAbX.H7toG'U*ZhALkX>'`/Z:O7Asj29LgT0&V!+/ABRn=aEK+qI\,oU0sMsfo0e\[YXY]+Spbn67HIJOfCgJR3<43tZC1KnJr=f4fr:.#KRfZ(M=;!k;@HT :/iZ_H.HTPn2VkAnn)s4A1'Y]1iV5#,mI=m`^(4@+(`^%-ia"oh<N:@Nttel]\]Oma*LdIdFt+O6aV/t7MJ0c&8Q%M`attI'R0ij3hasMh]VJj?"Hiq'GR4MWn5aOt-K+DWJ\!\mn[?LXWA?MRs9 ][%Q7+=ZfN>6!%g[_/D&;8!':E1NKG&4))ARR-Ar6=)@Q &&)>/f/=SLQ_#,efRaiKj:*4G.8Lc*>*BkJi#bXoHQr&^=aXB0\-m;?\^F_AF?r5oA\EI`X23a=8RZR3LqN#m,VE5+C,"Lhs*mrmFKG^(4ffII==VkpJ"f)T*qO_ja9,\J"-Qt$"AClXSUTAc/t[-dR/?&fV0E3r-D% ]M;SGmMo>h[H`iA%a@.N\D+eh@*-`Ap##HP&$bIY!-Cm14pK7X@T)^%b'bF7M`F;)Lh!SN9FTG*dY_rT\pK;8A#6lINMYs+JGn9Q`?-oKWN.YfE g^?#n@ZFI8"a9:sc5$tKmD8o-;CRJ92+Y[3cAWNS:Jf9/T1#Y=F-64BiIRiQB3qCbIUXX=p=DA*/j=nrPcOsf`Ja18I7R=_(g5mABgVD3Y&*>JKP')OWdVkC-fRrPcX0KMt2 C`Fol[nRllZriSWs']A=LX<3RPV`?cBfY#-A:#F?Y[$Y$5.@2sW7T?L`$;QH$$VgYkr4B_"eSC[a36dC[ cT%*a(C%<%:X/_R6Fq;YBAgd 9)lUFXg$PtnA,"EQrAq;:Ss+tA"tF3VA^7$\]/!*]2+8/ ,0ES-1??Wq[>_$`;2kf8^lt-fZ>h[#5G>j(BNG.'Xqk]?n$cLOOLhU2F?W%MOLM%JsHp8GJ$VO=3h3P/*fp1)hl]iP"32CFGM@_$,G!`KHh#d0L"5EeSn hj'.3Y06q`#_%Z[%7PZoZ;YgN)b^@&'Ym_,_l_q"#)gK(#6U`k7W,ie/W_)a/Q;r6bl-:@2c]KGGY5WW iKLZe)WWjm 0:;Nm[dF/$%U"f:DoeGgRmY-Lf:tf:a!7_>G!lAB663CedhibAW+PYF-,_"26:NRO@:B8;>dBk?Ej(%NHQ_2:p"5aR#<:N6+]b3J4$31\a`B-,B+)M\0Ramq(XMV>jNKA=Kp%lXbN+E;#EbCHsaX00jg.iAXL:q?\L#1UFRm_%K]h,C%9mo^h*Q,14#^+Z@m8]FqVtFL\BH.m$t8SqGpc?nHLlMJ=@.SCkXhjE5-lqg= BI9Rq8PSf;LmfJTa>jBUaQ,p\,7V]"4jf@dT+,T(r^B#)gk3*FR;'*mq5!2)@N0AK/.`^1tp_p^VZ1,\O3"S]qO9eNQRo`L.eG?/f7Dl.2nZYpd aW8o03SA%ZDLNP3G8*1<6:*hVoJ=TrVa&!t(I+DoLW6h0tkmAnehjg+>UJV ]JTBnm ;hN^l+)S.CG:\j[em6m>;TK5Y%;p=>H.8ZedEk=BN?\\DOG)PP.S-!lT@#&HB9)FOII[CO(e0&JLLJ7V=d(Lr:=dm]p3"SL;'*_O)"6V897cWP$s>Q*I\G*JHZY6/9c[/.!:31'mibAEiEkRa_%]d+?)bna.,ZIf)cfcChc;gFc.e'[)6.eV#/itVK+:Lr0HC3$Z4*oLk%0mYLj3#DU\4qWqNBsNS'_B9d-*09U9),e'>bYi?#&dAl\X(7?0%eRQ:V*hDeI84n"X1a/N,ITr5/N,S2"3Pm,k5]s5gf7WU`NkNrdFd(7P:,)(nPD=jH8c4ksI/<.WUfE=_OF7Up4H>qic<.r05nsEoeXfgB2$ ]MVSj5Hj=GsCs"\hA1>c:9Uj?%[Y=<N6*`QE*L9M4K'k@j!eYC/KDs5AbA/-ATEn5F*tG:KEVSKsbc%TMC"tV]j!LA[8EG*-i^TYY),3hZ1tlKbf\(Y/o66iNjIW-_g."piGg0kT7IlVDo1e$ai'iJ 1k$Z%gJ 3n(ZmD1X]IZYZgHj_"hP-a)N5FCL9c@s[j-9SF-RAeDU)eL0oNT.\nXZpe$,ZHH-:ch:.6:P"cL(09m#L9&g_F)F`kLBfC+n&`MaONb\L8&'XOjW&A5V!9FqPYk1:i9*J@1/=4jA^TCVaLePTrY]2IlGI?SXRiA\0loHkLs?`O\8&?<>3!?SM3AmB)W>oRDU$[2k`7_>Y,a,+C.e":sEb&fTD0EA5.XdX2#ZTM>$X93b37.*$+YrFTorc85839WA[A:7?4>X`VIN3`<5!ZH\h^4pFA^JAln:8Q'HFG`jnAnCRf`8WHPF]]$k[B#1;LHW?)W5IS4@C=O$4E"]4!Cl2GpA ^Cm/tJ *?`6pLMkVdd.iMlo#[/<l\b=JZN$S]G]#Ee&/pd.#16olAklO:s,1e+9d2;SA 'j@VP3BEFcAUh_9Y&Y!cnMsh3>af]Jc#Jn^tn?BefEJ]jMMkWIh`]sha.f+e< 80^_)6 `G0=YPUDm_Efb*\&*S?Op6kBI;Ae!C)-(DFT>2iQk2tOftCQ!M8V(>S=@$RNZ*n=ANm2B1kN#I)PC\G;\aEHjW#XrRo">"YFD(`pU5tf)_T^8SLUZqU#.2C6`#EpJtZ^KL\.(n/&-0WWO&mr`1RAF"&LtQ=`i?5opDmm`Aahli-r,H*1(32^Lc>n<,]]-^]0GRn$l5j_N#hr4;*.e6P?-$+Sm%PU>9as`Ls1-JINC"eFPC%5sATQF#,s`I;SRFCN@:- C?R)b:tX\:iVpK<`0FR`].7k:KmlBjI[,Kq"@QGa*QK.mkd$CnOp$5WW@GqDZnJ>p'E4,/j[_hX"1@)O=A>`-Qb1Re+b'!': $kUB`bgrrJ`&"9V7e/)i,(:I:7j5gh \,&I5>&h/^C0PctX-3s'VAdCB6sO(F."4:OL50H3+o("=n.AU13=OsE-Y$8a0jSp+!3OS0Kn%TY1VjAGI2EcnJ/f,9?RRWUhd^AHAcq=%NF"c_O6\5>lK<IKE"!6G[/=OP!)K]mIYCL_T*U;BmBtV3[1j%_t"OI"c@`#Ib2mim6e*#KG t3Xpsq\MlB>L45A?.jr0B.]XRc(?7?6MB0P1VWEc1n!'/N!75,.=!D>92_FPLHmPDB"qrJ'BK978B3g.6(Nh/-#\"SsokOb>DcfJ^eEa &.ccAH2_bdA"")'I)7Y$3o%@l]RPrAogDj;60"LXpE/VtkjV[%4rYh0NAs\a'_0/Uc(iVb_i%?>[GTP\5@9%iiiB6r91qf0At[t$D-_:5^M_7g?M_ZQX][6OMK8"S,Um8@S[Z3M&;ZYT)N&_LA.=c PAl5A@(\5jB(8O!t% c$s?+Ga?,JjP.,#B_DI8,PPjK+!e"^dqNKdd[jHL'\/_eaPifs[2CiG^nm:.gjV`&qak@BJ0SRVSQhtQQ2[A]?]k)o`lln\^4I>6*SfJ#tc-'aqt7+?h-.Xsn!B*AKV25a'NH,j&YQ[?)@PK8L'PZDPtK>n)+F6^Nnj,ZrfpjWg:H+_*>/6K_]a?#mn^dAa:8tDLa3hi2_bZ@rk?g9%a^s&eW_#k!9Sr(mM0CQ2Ot`qnBfR2Pm`8hq6"g#E9XNF)th%(IH=^FM'bso!)n7Jg3o?\6mQ#jlI0GU5G+#DmC(V;7@(^gs(t\mJ*V&\V\@Ed[b2[[>N^;#SIWj#Af-cF!m,=1Hh$R=VSclKEqnom[0,QV-s%K#!g9G;4o@c^?;D,jRFHaaCUh-L -4\6TX)`\IB4:4(+Adeh9CQf=t0(tO>n;C@Nh__?Fo&Z8]TO:hMf_+B D8?+=PA*bE<M'6@Y!^eS:G`apd(:5)Q>[JP1=Hjn aYs>SRl"ITj4qL)ILm$i\f^Kmg)atqED,]34Mt+IAA,%Y ignFm3&[4rbl6#c9+aW9/R+HSXkAA'.Ij2>1(OJWF24H(SBY^;V1%&Ora?U#(mr]de`@&QJ&(^Zl"9%N"`t_[]E98>c?sGjo#;nd*,kW=>r_Ddt!Q,Q25FgH72eL*fW2f7E+[hihR;bqmDooi9`jiLm)PM-(A:i=D2%P/MB)k@'dTBLX@:EKK4`A0"A)`1LmBr U$ql2)AtCmUsDiAVAWb8""#kV=b65,&CX!H(Da7sdd-<=hHHo03,OLCcC6* \?(_T)47RfWfPYc_eZ&%1lj"0W/?.=J?M%orZT5?9C;#*N S*4l6*R_70:fP>"mlEA-#DPXVdfF>A5JJ*\Lk&!.@CNtQLn74,gN_NK=h'I`RAc'Kt7^AslCRjMGc'j+[,W6$LbUJ0@GLd3FK)]81&P8b]DT;@^7??c:NA]8ptTrR&,/eX)I]MK&'q%TcPe(TaV-er!'3j.iXGAmdG3$GZ&G$')>/AhbOtm2T@hNq\\sfps -L248n$^ALP]ho[@1/.ZZq3IWG!*2WXPs%[S-$**YGC?($A-;.G-NOa>B&)A0_.`Cr'QlM_=>GA(Q%Crtn_6Oi+pj*iq@eX_As'nS U[LJtt4p3Dn6FHIY(1I%D4\>r78crA)E4aD#\hU!][mh3)ME5bCo(OlVLEU35q (fjKUlBq^qCn[%N"WAV_8Tb-EA3IM]4S'-5\phTYY3SFsCn'( F<TWXKhQ&!Q,Nj*!o"],M5_YfG6*EHcZ=P(SiAY%1CZmnIfeA;Fb(hIdH3WA#$?mHK@OFcrF<.pBUQC46T2'?qr5`>l<(cLB=XG#rVjK5P"b9%bJee_/_AL>D_Oa;XZs\ JFHRP"n+.#AY^.$a1p'j+;3@Ho4^)W(C<;J+PfKr'DW(qKn/L^lB@X`8[9\.$#i^,)RCE).`gMXC?p_jh`.d5$Vb4^h\b;Q5LY&&7"BKkn ]$^-`+S9M'=!f:Vh643P-OraoJQnn*@AE3n3%kcMt"dh'CRBK',l@6`?Z)M7_1*3gg)].:Vad("+gft$T3aW]q+3o(d/WcSW:_B2#e@n&mq7N7W09],V[Hio8!6OZ%nP=LjAl"]h1@&T`8XDF-3F,%MD=.Y[j8#Wj6>=8;2nLO`93V8HiB3GYjW4CBdeI<)W(SZ8cm;SCGgC`ZK!$)Z\CM>W!Na/:VK`MA[-YdoS->HZ5Nm+^R[W^NrOI-(c)J6HCC7e'M=-DaNcPf]4r;rTdl\0[>6"\1)kHV,IoaP2\F!PJ2jL1G-4Y?)ML"a:G^^/EkX`>)@_#r$TZJg6;A7YWf+rJ5hec<&FJ@?3%;]GGmB9DmInjAY@^AE24MZ2Sb#(:!ke1J3mU0'q;AM8XHLgrj3<&Z-]l!M%2A5.af>ZRh!qLr)MJn>>0bbDLRR<[hq$8oi'2h.blNaY .N'L/'h[&3*\Onjl/LUoMjA= FQj<2l4[>JGsCM:`Q:#[QL9/U9V>LZrfl%=9OAtLg3.'eLrH75.:Nm,i>Bd7 3n<2-q8p=?`FM"Em6g_ngd*WND4PtcgT)ecQe%d1"8A_(qPr*iW9N#="aBd8N3bKONV* -p[^^h`/C$Oc[b':)#W3>rBBtQ<;giCQ?/kSK'j.gMK8i>6`c^h$6rX>,2t#^r$6Ai)Z8q^=8tr]BdP!WAb*5=[J]Fl $c#Q*JPX\^PnSB8BBSZQ2aTH5qT;:\$en7K737i'C.14gE\/ FK$.`6Ps>k@6+l0G^7fAmgEb\siM4rVF?]2X=Y'(4]O)jBFdVQ#ER0=.BZ,scQ \;l`>Sc3Sej^,YRk+ka%l,eRoANq5+E*$=edWYdJo<#j,8]YIK+t/&6<5.WW2& 6J$i4l[gj.^R&KtPq:+\:AR:cpX4M30_fl77Q*j 196-t9i>PfNLh$/#&+-:tIq__jbj@fj@:.>e?Ysd?=WF`Nf:mSM.0he25-Gbb3s< &Df :$OJ9X%gMm"=`p,(otl8II&M(kn$3M!UI(M\Y'/Cmrl$@AE9 _;cip2JS_e4plaNP)S(9;76Mj]deeSaT.[2b+ZJ1A<oh_/t!XWI\Ac0#@_m^aT6Ng@0Vl3AscN,ib65]4QoCLg58d)g<O87SsN_-eUS6#nccYZrIdO(&&qJQ=J!T^2;9)d+0WXp@E9/n188"eMrV4`Dt06]dY`pX;hE)!PlT(CAa+.MNF3C@CCG<71rkh;PN]Co0VcY%biWbOt]tLB"__IU:L 0? 'CS5ZlWbAlG#$"Y[7rZs=4UiCPKiHQO[ai`Ocl-/R@a?FSFaEJ>%>:qhrPK7O!qS;#EI\,Z(A.nl>r:LY2N47la4e]obrh@0k->>sTFQ6L6T*$AKBJ43DHNtij?HMh r#d.WLOCC"@LPX`-_q1Y3bUHA0<\K^k0nS0O,?f[lM'Y(tBM$2A4Hq-F!3X+,X\"MH?M/6G *NTRg\T[ol5"V+(T@tf=a5'g1(iDWr?9b^D12@6PX1a!C3B.M%PmMNXI:1k9NegL(#9D,T]c;ZhqWj;:[CVs-nflL+A\:7L:1Wk=1e+%4`J9go(4ap9h(trBJaP+3!]LJA-e-lWMp42AfV",>7(5$M58/_UAs'9m$:,J@Uc8jefpVg@PNXiF/b^bV+],1];Um31DAqk"nE"OR)VR/^nN `giO%X 2ZX/S`&rr5\6Wo7ZN3^!SN'nq+P!$7S]H`.(&gAs!?V[6:GptG1Z(Der*Rb]1^D--jX(gPGZ4Le<C&.N2/no ZMP*IcX_A^rOeOC$To5YKg"%r/+-%h%iQ>^0Xl$\dX@I` ]T2h$kFhcQsb/VjV<rF]D$!-Q9BWfQt6V&g s^O,."(KI4h+ARfselg[`Z;WIeV=A1c-jfNF$s6$/3\ek;Jb PHk-X9WpV/"JMT1r4/iV%]"UDg7%f/k#N\!ioc2M;CN1:4!@+XY4d`K*&/Cdjh)KO5@YDm?8l3*2 cnSV2KYg+-S,?NEAF'7o8gE]iVnYNXG9mPb]g [j]1(>!(l1]j5`7E)D.th\X 8?G/dOP.)@)GRSn(EW,,<JAl,,"PthC@,(Ttl3]S+2e&%>.j:)0#[1*kD$]!+[SA8T@jt/^iA,AE@YQ*a/[BPH+HQ5 FSG*S:,BiW@H_MdBK76.<-k75-AR.;6"PD(%0INhS7ePls57q;J1`.aK-E 7_W.mK"[VZlAEPkb7kI45ibQA5LonVs7Ds2_!&;r%G"(!o'FPDT)NAbg/.R7FR[ll.f]#!1eC<@YqiCf1q9YsRA5@`^%EfYcdCjA!Y,6 IK=VOm&sLmA1kkC6eC!*0&e+L"^)pdKQgXAaXk3$mnG(43KDI$Y-pD+h>oC9F`RITFR!D'oX)=OE^eO1IOQ>%Q[5QY9O#ETf!\dc;Z85KXhpALN#4g*.Y q`O5I#XUh*AUb]`R-+TP[@Y+bm6n,N?5`#-hoDn']>A[]Ar?[r6tAA*1;9q/EVV<3*>Br_)kk#n2HP9j.8#c+B8\38($=M+';<6e4SL4"1Nd&.O4eVkT@;8;fMXBrj%bWCr[Qcj110"pWRckp^>qnB.X*cm`S27'f]\0 "l";j(Ah.CA +$R%%6.lk3BPTK;T'aKeY28eQg;2%:bi;5EjP^PlDUZEDQ9 Y%s/'AO?s&+4=&ddn24D&0Z$D>%W#[>&-nAgX;78`-5hj?^GktMm%W=,>KjVV3/a;ik.[@=BoF\+fHtBd3Vc'Rrpm&+PN+sR31AAj@kf*mp[IieK9OqS\=1NgFG5d?/G4`Da&k#!dr3n7jM[NQC>jk8g!5Ie__3"7)/Brqmk1tFUhXKi&q5[9UPdt];$tiMWa'l8mNDZ?Z(SDUH\7N4$F5Wejo]_^J7AngphnD)O7Kk:$;jKVE1\aCRL5aJDW%agA*les"Vk3$0pq?dLfi#2*'S97(Zg5PW*?8m5rjkAhhjd9hk(AS\mB(K?i#AYS)?P[9(bj:jEG' 272%!"*r;tD>"X$/i0A?NJfp`n?dIA9>nb\1TOhZ:2@l1Td?M>H#Q*)>1$@nb[7XhGZKln*7K%,Jb@i4Xl#,_sURb_Q=eU1P()+Xo_N&ON(koKO45`8 3pH_-30HH@K3bSIi7UW*9/%F'SE7I?]<0rmcA43mj*O#s-U$ZeU;pTV[lYbr]$O11l;_(*.D/A-H9)*XrX;7'c[XNmXb+YIgk9[hQHlU]_t'k&V.;qh9+N %A:A*VSRQ\:VL9 I4L.ofoGWqA\90>\-IASNB= 8?W7Ef#hT$s-#@rZH2\ESG2tgon`oM&+9OgEU[T^/B`Kp.lDr(G #r"bOdgjCf?PDPZg.s+5%Gt7lPo"A=L%0cfi`NE)U/&J3^02@-kI\=f0radj/R/4242%X$&pj1`kbhm\F]M2?dnK(T+n'>D75ZC\OI0Ocl0[`2:#: Zd#bWXG[IRSRtj6!r&L/DhcLQ5dl!4n](httJ507Zt)b\=gn2!giPZ0KiI*c8`dpG^`N -6"dl&L2[%\G/gOPPQTp6->6#-SpLM^ aqAR#"])_*BgmV!n7:VU%9`j83E$F[K>JBe )I&4hD"DPo)^nML_nKQem!rJDojCaO7hTLZSUFl=^"al.;AiZ#2;j"ICgk!>#E(7p/%Laonf9;qrK!7&+KeKI[`><'8ml`a=<]TBt>!8Tl#(.JAs*i?NWLL>)'sSpV>2qp0FUhOg'm/@8ojW'&pf-\/hYo#-A83*gclkEZ5/3XSRd`Ae\+7d7fN!8GO(e4\qA&4'N pUR]rnlZn&oWCCiG5q1o_"_@3XMb\IWf$Y"b^G%^,rGY.7/1&&mF0<+cf3jW-WbIS ?'-"B6iS.SL,OrS!+"cGX_DQ\V5[6^7bZEeVP`C#W@;XaC^ oK3gF]9iUS<,:J;r1&U)Af(,LV;`ikl(b+0@#YY2s)%`2Mc#ksHWVjk$t2iM[`Z$%t<PbTEZG@kX4e>4iH*!AlRrpVHE5&)/S:sJ[>U)jXMq)4HmT#o0f;Z*@&%-LB([#m3";cEA"jh"_'#Mqn1,q'Lds ZL`b'A2JOoL+5.aH1i5l$H4+ ;*Nhk*gEl(PA^a;ggATU[8!3$C;JLU2ne9)p<$NV&Ma>W"Ak2rDf28\.($7DnUOGr-n?$K32WYa[Zb^N6%$,I>[>0mN+rn[A#Ph.>M0e@A50.g(%eU-bL\.bSU&imF1^AeY@GC<8qj?Wc"+rls,o%,QLdCk&In%PQnaTG_g!)t@O.7Ak!od5-r-9=<$Y?:5MAW\eD(8R4MK:WP?V6P_OUPoYnCW9@#/>DKr%2q5PPP:?)8L#>.n^C#`C*2k=)Y'\?2A!IDVWa"cHij2C(g#ht8S;9<]Hm@.`$]q#0":;oDCZ^%-ofcAQJp8"eGZg61bW^-U&:t0!9N[caoZ>Ib%,2$.:$;o61TtgB$mUmT:m/K^k/sX\R9[5=fk;#E9+NfC,Q;R3LoOgoDW02QOIOQ`M/TZWXX%7\dLI&fk\n2-;A0>3Ua>+&BpV&LeF8_?QUk7er `+MKIMqT7hh5H%Y'!2ahrI!-XC!aDWd gbdb-a7+"+&<$\s54nDJ`k8n"A(SP19r$mM1ArGA\mD&8UK#o0S(@4ph^[IX]@I"Jgr[gse66b5[AEG@Fa61jSLcCk,F7sF+e%\UV[_0`l)S$a<2WGsA2C+dg8lec]'^3l89Dcj8@C#$Il88b'H99feK%a/Ee>Q)%rOWf3kbth,3V??N$H,J>$lPUiA/gD+#!cJ=a4]ae!aD&.fL0e67s+g_?D*&aU=P.n;4EM]Y/8f4qPVAA^7ML>7IA&>*T =LP:VB"Q$m_q7U[X5!@4Y!pe(UF.Z#YU"K[[2GA5N:a7f%B]N$$OPD_(t@MD3<s$]A"8K<1ff]MZsD(e1`'A0S?[/eK;"(.j9c<09/58p$5YbeP_LS:1'K5K\Is(9jT/;.3"NtA^"WG>r_UEa#*E=Y%f(@GAtqfV@d\:0]ZN;B?JG;-C*0(-OcqnDQT?AS1Zf[Uk4s\>`08cJ?h:*,$Yp$#M'A^jq'DfmVA=QJqbo''r<&f:&`*+I6m/,`Lie:5lgK1S+e',SAUZ0>2LOB;_%H?/?Mt`MlQQ.5[ga>tPdD]&&a\8Al-Yn5B]QNaN!dkJ*!`Rr-;%WZ5V_FgbX$"AMbL&CSYRhS*_WA0qZGn8UYIil:!.[7XsdcNLYm!=@kfg\onU)FT^[(GmW6@lm7=2rGD3.FO2b]+b'l+VAo.]c/sHE%LKr;l@+A9,BP&p##seO-I"RUJ-d4]fhX'4B.LAI+,eclYrVadm#aeQF00\^MU3R4eUj-hr)jTX-F(SZ3AI@=k8bkn"]>&.(Ce"fT\50#OAk`RedN!JqpGEaG)Dr@a*<]3`.#k/56P;lZoeQqt%olh:,_O"37pZX[B$Af`>r/&DL@B\1tso-;2.frdR/[@Aql@D95JQP0+jc#FsrA!814#c!ON2<$bjejUOZ*9FO\=4k_[[oG1L)GVVE.:4)P'^r(JHkV5HAj+`Z2,AHjJmnhRLK$=<;=]V^EV-J@4XHc=>@tYL<d6 XEC.sm(lp0UAp;2 ,OZjbJmC4TWLA#5,Q4$[.[-nXI_/Mk=0RZR5Y*?`4,267N`Ja'a)9CA:p67de'Va4ZTs5*:_g>P(^gn8T;ELls#Y0qZn%%KZ?"4EYX8Q&>cl1]5` V/rMX1?PcbEN=+mf?_mOgpAEB;MQSk^\1(J])oAdGL,F'KB5iR'(:#i<&f[r-9Md\E(#2h%Cg^_:6ISQ+(Hk;fa7A(60^Mp2(Fl7`^283p."Y.bd3CMbK,b#/sXc6Oh:pKC;VS(UI<2T9A%t[*T8V'_AJ)m/P- #+1i#90\;(!)e<3j$pL2L"#oi^9L@)j,^>si;LXOB3p;tW1UHlHo)&GEQMN]_A^DN2=$;M3q7%\\=0V0?FGd269qJSih>/acd9njGn-Q-Y:n%>For#\7'o@Df0Be._`)j[#ah"PD:-+&k0,onnBgH;U.qN6/jVT(.U5Rp),hC7$_b]rT1<d3r%W"L8!M.3=`52(1DtP-X%`dSHZgI*1p8@eXK^DdYgWOt59-DED+56A))BU]mU:n.>E"-b;caM=YaZA=VB.k4EQU9qH@5R-K<!k6qT"V\j9SeiEY#"bBoA;HIUof: B%ACMn&fPsCpBhqa68)6>>eimVRI&,)q(F:AaE^4gGOjb4XtUpotYh7:DCk<`G,d8\WDn@pnDW=%j6"#PU[&?1*9R 1nINUf&LE5*tk]L=q(`+Pp'A^QFg"Ff,!UpgX?9_FhQN9 WGn%"6/TXB0i=@P.]qGlBhG-TV.Y,&/gU7AG2#t6+ZDM<Hf?r4/`#5hM9U]EaeVqRm'0@aA!_4XWM3-i=4X7I>*e#4)N@Am"8O)!YZT??m@,\CS3g$3!2_V)SoXh3ptCNXA'BS?a+Icp$S0Fp,+:rO%TP;KW'f2Lh3ap0ngKVc[JIMRsXf LT#n>6G39k9dj,4V89ccR<&bCnr$Jft*ALJ+Kd>,Em4p940ItR[1Lg,A:(WA$d.Z)PrBJiTPn;kB>7(/=D[Wee5:T;n:2CfWM`"T#nW2X+_09\pr;KR0j]R;s)9F>k[oK;c&.'J<%,Atfb4a+8?#U%M7RpAT$7:!ir$YDY2$5lL,Gk>#JSbEA,ZgeQ[BEg""FFc.)5Gdm17UAV1@?E'No2ETDfp!(@>0=.Bf/o% lS(b[:Ji4-9RRiQD8IT.!bVtCSh\c\Rs7147GpTR*0g"o`D6 3;iHc\Qh8ojSW9*Tg'.RU@3]ai]O3Dsj-a@_0TZ_9Q?*<EcLfr>poA90%g3mkH+->"sD,^TWp;W`-3pP??NI%QjO?lVqq3-h(.W Pm`/[`3F.'4.6/:@%b4lqtnL\86s8@QLZ\On14Op:jRkH0q52s..Pk,<0%gq"2%jdS>(RAVi:=7N?deR`1G"N9D 0`c] 30^+mBmYHW(,o/:*g,VfP/?t`[:i1pd]g___+t6IH=JNUI>e8SCpa:g;OR:eECAj`6'8nlo@s53e\WB8j*DF4C) Jd`K#IPBX?#N2@#8OK*EjZT oMhTfLjt_TqAno*3`1T'.d/ R.kffa6E9i @=3k=F&h/D/n5Z,c tZ63f$=ma!%BOq]1%n's^k'ZmsGE4*:Q@7/JTY]iA&\KU1q<$bk9N9j06e]F&m\207TRX[4%d4g!3,sU`cXAY9$de]E@Q!C%q8P281s_d7d(bpA.*`1in,f^pnIElntTT`1kJop*<<2^r?G5Y1dP5BBYQZ!btf3G#1oP'EY%N+'MU2q82,SQo6j,oU?.D9? rZIdf_AB(VUO!M*_7$,5QTTX@(AY7IcNcT>-U\r!$.rRF2!d$=MBkBQ*(A`Om5)LJ:. 1*c6YAI/f4o&%OCp33UWk ,#k15.:I!@]mT^-<;'_ANt)H0)!FSjpBV;7[;I1/D">_4.!p3V\CL=@slelia8UIF Ra]t^X=mFrQH.Z,kVnk`iFl?mB^;aL,6DA_HZ6A9(9n0sZ<!2/@jT#d1GRR;tkP>a(q)[`!!Q9,OOd*Ua[>\5kXh,0Qa^j`Qn_Dc,&A\BF Z\]7M77#*e<X[tbhG&Zc\*j*O,ETQ<=$P_qL)ssU6k^mf])>'a>HGXk"=rbL4gF:E5cQFIS.0PWfh^/cMi4DZtk3;f;:]-QKmP##oD>`;KilN>6f&\?Yd-QmLoZs*7[A&UE1h*KCl02W)R#/c>>E!8TiNCY[NLh_aXo M_.7E9g9o]PCS`/)Vs4P9;fXR'3!XTO8*"LI37$RbVf8qYC]Dqp%BdUNX]RO;=OGd:\icQ)i )XP#,C3( 6_S9ksX7Ar[760bhT/R:r`Y-.\cr,Q1A9/38#YJe%L!rlC4mO;KCPMm2@p>C aQe(;9LdA.M .N\*A3,Xkk3p>HU,'f>J(m+&eRi`,.10dWkf#rJUAW!Mf$-6O""@g f1[Sm@@]d[nmR#hENkFb_J^QQBo@g+@2:e0Z2A:^^C5io&\?;+nC#RYC?-I*e[Pk3iA^\P]AB'q5)_ _C0h7r^mbr(VpO^>?0K(ATS5Rah[k j%@Z`[!Nb J3jAkf_S(\>jb-bYke>_@]4A#QW(M='_pm3FVqkBG1Yem83gB!E\XfR*!19aXN.P&@`V$b^+6PV/Ql1@Z(>`dhXh48@JClL=aFea=?dfo?V532QCAKYXbUlg8;_Ubm,!j+OSg?MJEMMX/M%[(\WdK :)ibP?LHj5)ai.pRQ"dt<=mA#E-`t7C5]DOVN!!mlLfC\\9&oj%AX]@1M"BB*bm\ >L.sAJpoI]m"IOMoRRmgD,Rh/k>_KT.m"8``%f`:2\bn1]!!B9Me5\@,?8]59]rrR>GeEJi$knYBNcJ7Ht4&TWEg-[end5AZi>8"WI!LEFTjp#e&jOIJtQh'%c^g14TmCH ^"`A1]Y*JU1JU>TU<#Lb4)lVVo1Lf%mJkS.g>VD1MTjo)-P&g^iL5YI8Li,n_!;3F3/e.\I<@;C3E"BIW:X\<%ULnr#W33Zq]KRYjGXCoU\mK!l.B7 7,/!_XK/jQ4qebJ/F9jh8IU.8hJ8V>]B$6_8NFc-bWtA`f.f,66;1o"QkD`1<# 2@HcgshmE,p&cm!Q_n'oWB'RlMl<9"DBtC;"D[P1:b^8gc!%-e(=?T2'_ZoiqWiA9&:57Y"PXrTU_'!UAfYA]H21M(lR57/e=AO'9SEUFG 5_^"^k>IhTkL<7Gq/gaFldm\F=.* (PA;n,QE/q@N9^$Vsedg+ar;;&AK\V'!7>1#:_E??M\l",@4da:][-dr!I6.'lrarP!TA06=8*k-Am%osAr;G]9MdLjSj1>ThQ^Q.8JGN-YT;3=C*a9>#[B5NnablrMirPbjlD65!$Of:@[I25EWGM[X \nsIXF=qc`Z-\]^Vq2kSX=G;$5@LQ1>9_4*"4Vi"QmAkDm_ST*7;drHQ3if`J7ng5ne`%8aL4,f:Q5GS`LRcp7Z(4XVd^Iko=$]@V/ta'o -9hdlF@Tn]%86a p$R7Z.7bWcpgT,87=ZQHX:KN"6a^*0A/ibL"U%:E$&= )bjRo.+g`%JtkiVXN(o 52Q]K,XJ8JLf=T=$'B1;JI^5*Al'A$$!*PB/%b/5s[M=77C3BWb?Y\hb$ceQ[pm+\:IL`Zc1MT3\a_o_T5603tl?dg?pr6&\8QkeVih6QD%-3,oT!$bc1[+] 2I"dh+QA1jrB>79Ud78"mnif$jMJ5qH>lr`ck 6[fmh?%2%9F8eCPJ/T7<0P%kP DFG!V4.N9IG"&-T%p,5PLA6PTA5`_6Ibc4lb9)#eLH("Q=jOq),ZD$.'55&rl;`54' ]&%5W0HV[_/=WQs7b3>7[I $j;SDo&!c-=P@cQ].GPN3D7coM=Q!#SZP09*d,7:WjsF9[6<k!N-/?QAfK<&.1$<-dO30G6tV_h5T(45a"Hgbse"TXr:W1XDcnUp"f*R],61TVIHW+0L$YUS[h1A=c".(D:^eM@^\&UI30.aURP?P72(17NmiVi)LGWON0BU\45;oaHcUOhhrT;T17Qcg6O@H(#4r`C65*m0R4Z1WpeM:nEjHZ)sennKseA;)h@)a0f1@91A:r8Re_p[CJ9[o8f>^2kLA=3"kN4Kc0al_W+MeIk"MhrUT>X":0tOfo"U[A?h"AWa8Hd9Cn_>ULQY"fj>[:]EBAQB-9YW4\nbKj:aNm9(Dpbc[jiVb".Y,A^,F@".G=iF6"$G R0[;L547[.g(A+I`+8!]d=$4IY< .b4K3&+0-H7eWgKL^34^bQ]*I:eC%qFtmrF11[jIQo-QPG>_XTraYIT#+T#bc]D,Y[nf7-l.d9JO%jq+=Zd91c]3/N%r-H=A)T;SMRde\KaV`lXS184CL.7LW4S+<^*2hA`PBFIUVXm3Ngfn;jCjt+VCOF(04T()pTfY*n]S^c0"!O5<Am+_b)*8*p[QDj:;/d+WeQYf^5b3^$CnK5MFBV'Q00JlLm_>d-6F/M9d.p+V1_AMJS>1(PWBZXG`hQCQ1]\7MS'im!Y$N\B%cJ*("f^Qn-XHj)$ehjA?TmM!rLA7c9N**Oq> DK5Rm@[jes$PclOsE9EmDG:)5[0Ct`5_,Y/,/dbc\:ZG4K&0DbM.<]d`YWcPqbnQFYb]cC#\JL:^n\'s6A^GJVA*.8.k)Q##HI+&P*AldtSe%O=5V-U+`&SDbB8iKa4"'1MA7*>/BA&m=W%U5"U!$M]l+mm93_Bs.&%VqA9%>UL'?l1CH'\#5D';FF?ia-pi2A$P=Eq+R[$\3c&%![H60R^2+/Dq8m6^rk.0`YeU.X@2LM_j-.ZN%An&EHGc4qO5/ZqXLU4OgKnr0AH8YDn*Q"o&YQhsEY'^KI&d@sCZqq%#UE?tNA,9_E8laO%Se\R8LW?HA:JA&qsFB2_HI]k?'4$-@-GrNisQ>$gaAALde9n?Qt+&L%1R)4)^Tar\fW(Z9f@%D,=K).sVO^W"WVP[X/-M.aN'.hQfO,N 7o"2`5Qfg3RLhkNjW#,qWaM@:\_=OGg]fSKrh=[\B=9C(t>DDr(geZF_l`,'&"*Ifp?N)cmT,6bOTRCr=A6,s]1sB3n,5PpRDC@m,,'jEo&:=@%Mdg:<^p=d:`8a<_D=bD`f/,([?%n2e\YK]"D*5Zc@\`3lnF5jLjKcG'A4RJI>J#(':t<rG9Z%&_FF[fj'q>LlO\$/L=/>\0^B&W+RG.iIhaJ8rJH5 sI9-$*o=@LKY0@c\8oVO9_OZK]eDqm]7!9";e9iTo0^XZb% 8gIpesVHaLrgR?`B\!40b:@j'Io>8&$fKts7%c\>8WkhB$/@It$:oAlR40A2&b(4"/d5+/'-k H4f=2UZi/QWjF QBX<"/ Cfa7:JNN&<E4a-`b=;^^G\'BTG8R)oCOc_@H,IIG<&3hMr'*(<a.&DhY5U(Qi&j[D]>qPeg<QN/o,!FJW@-0ZHG>5?cBiMK$l>D;mCQSJC? dYN:Q8rhGa4&9A>dtLGUkiYAL(N5C-/,NE;^lq#%c-GWh[A+f;20+i*BZ:+9=BrO),&(L`N^s!@e:WDD#fWY8i_^dYReFT4? _"9hh>)k,oE["p-)2b_j:)o$TRU3_4X@Tf-E2`1$&i[Ar)*s'-AZdQU9V(^_mW0sT1V*/W[m75A(_4jOjRAc+\Y9i%fH7$4DoZNO3r#^=`s;6(1-Hf#\'@&R-TGYKTNG-gn&"(jWpA_,a2`tFkM=aAPAt7)Xh\]g9P&S*qiO=+b&*Wh`OL[(g3CU3!d@."+<%?DN#5^YXg,^b+%b=@sA'-i"TZc6l0flWAGJF#pL':>)`_(baUeiis+5q4"s!VaH+X4I@e_8>^OnTMMEaJ7Aa4SY42kjoR _d66kF6iHA%eK&s',ib[G:>2 70/dLeZJhlsLba%R+9f1/XosAdmAZWbC[\g#_c.cJ0VA6gAB:o(`2>O*$NO_E7^1Eh!in[dM!Y8r>j@dtFcqZ"la>,d]49+e!Tf_J&A[QUCr,c;?HO%ji7g_9J)$6kd)ai-P[^C?Wm)M^ \K,RVU1)iZP9lmC2(Hod:#@$9cj6+-X3r)Sr9`97JWA::m;rl[9J*2XLE#F0U*IB$P]+\Fn>[%cWjdk._ tc1"2eWIR9#K9Y^5&%jZ$L,LB_K+19gB:AWdR!g%9?e>W/Emc26++H.\6F<':j#P9_kH_KGT88=4TmVGm[[N_)C5>;O3+>i=1F1UAE# \"J07pp!oq8d..g(((deH1[)^[,= ((s_9p*%(M_^7 l"rJT?l6n:iU*dgfaM r#e-_*+ADo%N`>Abj9'"FoLZ#db$&7Y_U^?4*SS>dG;K#O's7lFWA=6qH'rC:0aeXFB<^K(DV i%3)I*JAX3NNL jgeG7Q[XHVTa4\2OA@*5B[AIF26I]:,Bla4,I*ecIY.I9Z?8*)k`=#]88N;rHN\R_9414grVceT'LM[6IF]qaa;:NHd@W!`EAX-D5Z?gU5?bZ_TLR!llZkUaiB?iD8cjVZX9B^'(/OVNm0I_0&6NS0OD;;bK;',UX-GlB'gpj-n[fKaEn>sUb05NM^$HNR-<3V((RDpGKA-PdUA]s<)lV@r&7(n$A>M;D`0LM\ekE\Qjd.';qdO7 9KC6g`Y[N`.$1`raN?o;qR'r Vm@_'JF59($l21"`=A[Y%\(GAG\qIf5 )N'C%">WGA,Q>!-#RTW/?XRB:_n)^(RWBA]r^GF$U@A=oI''fAZ+RY;!EOV6E#sr<iH44G+hZ;`hR_Nj.CWM(Ns+_$a $-mrSr5nt;(0Y)fI)S4GEjX=`Y0n$B(q%%cb1 An;1nAi&-3\#Aa3jU!N`!4"^IqAU)[p$Us9q&"WLp:@Pe:Q?cLY(:Q\Hf"-V9?>akg=f$,Dcj&7AM5s-t3`N#Al<:"UVLG+c&,\k>ejl_qK?j6`&Or=Vd"%Np"b7q$8Od1:;*dfnp[^UJ[,6t)YsVkC@aU$>]3S/LKp<#40TGfNP*+8K*NUl!!]piG]O4A5#HQ@mE2<rXNH"K[jE*5g^(5R9!Pi?L3N[:3AWOUkH@(%kZr7EMbnRn395W/B57o7d*pN`iHQ hWbkC$j%ge:%dT#6LcPK81jRcAd[%s_$c+q>8hO)l.bbY&l%>Z^c6i>\Cr.GY^eU/rq2C"mai_W?,@ JTTS*lHpL.DD.\BBEe<:*W1db#%+*,Ql6?+X=M_nb7%,%lh[Q,['nTHTgdT7j?*ls;GT;;"%7+bnB>EK43GV(j"DQQs l<0A,/o (+G71o"@McZ%>0c'Uc.]PXt\>X@kjXWqP,,,V`^l*L&6(d\<*cc4L),GbBo.TmE6/@7OA^/^gA;!pPs`Wjk!RGG2\nG7aa>C\W@o64tKl7SMAX>k&L,0V19b.YK_:P[DGZEPLHX-/`*-n\AO'CjV+&Sr/!>)8r>&diAJN)I0aWj4m=&&&=Q^Wp#pU_-3Y13Q/g#"EQMpBS_1YP&9\ABL6Z6d)f#arHa!Hj?*X+W0:'WWOGV/1All"Qa"Xk\Oc UC>\AqRtCVbD)X<+9pXrR&`"Q<.0-M.Q'c(XYRF0^%>#TN-V1g>Gik I@1.R.4@"HA;hWF@Kh+X4kt$8*&N`;m7UefMH)W6p]ap'J)fQ;)<`BCa@iqjGCDNlQ&-A@^+H)q0CEYsfBs^9+$b!A?ifH`4e`5YcN4WR$q?i;hOgQTJZ%^tZ^3bV>;+FGPDO;Vd^"l,TA/^&.UI-A]979L&'/4bQ&Y==om?pZAVf8;@A(B.FUY4Ao3rcKMJi8&V6pjTW9 1L-$M^@?Xo=Efmp,!#2B0 iT?%d\^Zeej-I+,Etdlo;GeXtq5Ei;N+QHKEa>:p70G6Ah0t$DC[:IgmKiSg7/3hl#Vp0B[;2dKL'SW%pG1PVQ>U_N)0^D[ALc/QTOaA])brkR5&Kk)K8WAUkhpSEj5nB]MLc#(T9Je#LOR$=gn>EdiskF\p `roU>)7C<G$L2gPH`rmc-AE$3=D]UZ@:UQ`q`=sO)18I9L!pDZ&nNoiOftb^1l(KBi9k#Ek`SmF&_d0(@t$Ybj^jnnXCVAOft4TD_s\%K_IcT'C","lpJjjtl7fGG1;J*@]BZUl54j6VFW=+QjTO[1ne*GO@RsX=j4F /^nFZWSPS=VE=RJ[?V$21hQYLS[c<1)jMEQSj3p;s)_?D_+s9I!jokC8[3Npbd+kW fo)kBat,qpW_YspA_A!fE/7g@YVTODlV?f+9LKMVI mW-7Ueks6oe4AF4]Qe6I6W!J8M+?IGr$&/r@EA,d4-hU$]bU-bAapk6/*_ 9k(1)<,P']K-_?KtcGg>rm/YDhjO!3lpL,t*D4j"Z63)kB1_A17LJ+B?#(?9*:q=X)VQc\pR,o:J7O"gRi#Dk18$\Mr!:"m*_dh9,8g0YIX`Zd0XjB!S+-Pft(n.?'kD%%`K>'",Oircg1L^\+iJE]!QEf$J5l&_nGWLGI8[B:k\qpJV1N3(/'/HRLb3G57Hfn25*[:*\E`^< ,rr/oRh ##dl`7>i5"= K&;;2-8gsF"=(*FkCoFTd=_,7\^R]SKoRlkF8]sLMXG%Y[+im6_^`7fLgk;lC-)BpohMn0?p"6`ebR\'h"%UqBC:?A0-YHU%[^K.=pPMhB2K'q'oYgfnhsdH3:(LTqpV6;'q9pBsQR?X9^6W:F<5IQW#Sih2J=D"( A0CT9W_nKmV2,EH0$JWV*6D\s?!:8`4$)Q_366,!c(ga+Jd;lpk5gIE\k+&f]o"^m-R)A(M#8%rj"NWKf"NcE$%l"!;&lkQ nB!cpgJ5hBh@Be7go+o8fd= ZelUGrT)o@.,EQ8Z>@=elER?'\DEN'iJrTYV*7&EQXk2kLI`CJDZ^,!dK!U1o1 N=*qq8[>t"sJn9 r].E0b*>+S'Y`s;hpAZTDZHX+.DA6^0L;cA=B!12p#P=Nk8V@[7e7"9+YFsD[$F/TKo=>C8K<[,T$JZYs(k+cK?ZXgNtQ/H*9'h9@f%Ih>G%/U]V]VYXE_^o1h=a:lkC4Pb.L^eA4CXn>st4+jakA@NS4O#gD1V?5kOHNC heP&X6<>2UkP5J0Z&J?/[8ZElsB@[TMI^N3-85UZ /mUYZfSjGL]0@si:nj6;9;I)C20)BO?W;F$!G?<Y.:s%e5Ze3=7b8I#TbITfnK8nOrLs;*(GqG8P"HX(67Q&0I?8`DD;N9k<_(r0p#=P:FV^W,#& [H!tVq#g)rbj69M[;_aQiSN%r0.Q]$jAiIU7Eb\PEJK[(:CHjkg!U'>\?b #k`'>t"C-C'+YJ`@#Y 61KEb K?Z)5FsC>IIfH+RpL2>W"Q$JZg/2Bk;%Hs6(#a,_S%9qQ6_\;N_Dh"BGrOGN049+fbDSANG=*P"RoDQk91S'nQCIBeng42;,>&GA**j?edh,:>Aq\]5q)c[$E?('Wd-Z:TC5DS$BO PTUELG`jLS7_N> bGiU 76%\QC)5FQSdDf\D>T#"^"9J] n/$aA^8n#t$a]%-fW_j#%fH:JTF0=l3?oHUVZIpJoHlnM:ponE:,;">)l:Hnhg:@bUq's#DbK`L(,MU$,N+% r@@4W?cc[I,_)daC_?T"tSQd9^%`N__pZC:O[gWgdhG'b\^0ltg'O"koJB)J-V!iI3(1fjq7H;BrMlc0Vc"YKo(C/Wco2YTaU?s:YE2rFqB81/df5\W3[#]'0IYYp/8qQ0[_*tN!3KeAI5-4`d'G=&Z)hpqPfLVJUG_>>>-AeHW&9Mmt,l1T^hPoML&N@T[[deLkgBa^pGoh3rE66BW"?%K))Nn2X*=5FA_6^bT2hnC7/H%cMkZ-&MV'0JFf#_HRNV* .@j6eU`&l2"W=R)_EE0h[-,="/m2='J2>KF[Nk['@K_,\%BHY4]P"STZ@-Aea<&'BE;]t8No8RVf',M@34\/G<3jI`A(T0"@b,Fc0;,AfqSb0=o:a"I*5`'>ep4#4D&nQ6\=Lloe5Qn-ed&$4W.KN"!i03QP9DW+:smc2_$gO*T2MV6;';sd-06W:'ne-fpapE'j1,f2ieqam>mJVD0Km\24 _\ApdeB&@gq4%fJ3oq`.&tiR-(A bYiC([QPaT6].XVe'[Z-6j14_K3is p!1t_l^;?@SMJC;pJ=_6LaUer7ZpDO"@3R:lqT_(ac:bSd!EK*,sD^s8R0]as0lG17)r.(W%lA(q!b=J:E!rM8^dA1?Zk^ab^"c,Zd(@tD8 sM.[E96p.DKRG?Xl)oWB tD)(>REQCj(OlNi(gC]=!1ajYA0AHo[%2cpmW#=YIga?,f1E*W>9Vk(0DS[spBF,]+a8NWn2f3A)kOs$eG;5 *LGGH:3ZDK!B5BZ+bX][I,Jc47T7;#i2Re7tJK&]_N(e;qSY2l#.bU9mebC:8EE"U F+B.-o3GRnEtA%NM]7ICk(+h;KO`I&\LDE. B\VO+0T!-OiiOkh+.]RE3DDda0Mj:L^id\d#PdKc!Qt/W`:m-aH+8*gq\Zd)0HoGG(T:'8LH\Oj0`oJ(YU^_6ZKrjZ*t(S2d!8qMTUn 8Wi38sSCkKcZ"/_5n%fUZ!HRiaMYF'g^EXj93.-=(/oHe'!B,LGG9?cF[?X[WcE5\?=7% ]OQs6nJnRJ/':A6UGZGm7g/Ke%F[7p]Bs"J+>CCigJ(T%bZ"jnPIU@G$(++1S_@b5%mREh&2TbH5II@A,jS.[MH\1-b<"?Ak'6,(CjbRG94=qV%8 TJ6Z6&3(o?hYfKn95Wb=(=m8.IF?JS`Qh*R?@IEp,o7U-J4qZGjLnW aaf[VF(AD>YDU>0@ZreJ0L)(&F)-U$F@j5msJn)t6K-SGr:Td+9$PJ2j-s9EU6\:N'$=7BfT)bcHS)5AeDqbeVO6r@":i09:':jY_-2'ZY5['(PYtgge0LB(n/fK"i6?9]4)C9(;g= G;" AZlZW0t3bPYs^?t$OtdRVn:nV/m[@A"p.%9!p&AP@G&S^)g="qA>AVTb^=6T-HAJ@j+Tc;GU 3pDNba3iS3[$*FE<$UE(pF&@9a>)k&1MOK1MTY#1?df*dn2C>hH$;dK5>1b)=j"CNaV-atWE_"-\'\OPdRk;b1U^eIA4e=7k)U9rDASSEhs;H[*,Vef3PhO@&?,Ri,>BAqmEZ^tm._A#[@[9%jb!G#ft"Bn?:^0G4-Y`fMSLdelJrVb3:"KDAlPH#@m1!MX#.VDA6ZLIdnF(6Flqgd[GUtN:YDReU`>pUBBQlGhQbC:`b)A]:'AfM86]'K[A1G3[Yb"4oD.V=NhSl3JH)qA7TTW?)`2A[(.i=S0N0%!J1D:#";lcAWp>,#d+7MgM&[8%'>% P* kIrG4,JZh6ArHLiW<30`[U[`n0X":Z57 [N*HgZ$I7otWr54/Ok\NEQTXVZKt8D6,q.R3mp>&_IPAI(%?e!5?A/Qbe@ g5aGG(ni3aQ%8;=R7B4TgE=cNBq+FW\An6k@VSnE<(EC-dYOXi5P[Tii;s=l&'p1UFmJO[#pNbt8/q8Mq:I.Kl7[5+g8)\XkA7=1"7GT.4kFYob70WpJIM/7`^?rOW"*C\'\[Ot%I@a\dc?'cjQPlh\h5R/M@DqMap%_lgJ\f!Fn(UQJHGTlr?>6mA,VAb3793AjHbXFg`E"d-kr59p,"q.g1FgFVB?%[V&V2T:?02JO!OEQ8?_GKU!:6^lAL7C;Mb@2b o_s\1j:e]df*LQ79TSjDhM;AOd/9Amf--]#c?4Z4DA*h&/?MH0(=W[H>U,j'AQ5=Z84qS_]io5sdC/Y!)Ro/#1-8eahG<=VGleBq$GtMgJ'iaA&!0>IGh<Ar[[r(DdF1mRYX(:Ah^8=<_HA:&X:*+ra(p/_Dh_,i)B7 WFq+ZfD1/-rZ#rM-i\)%3a@Ud]n*+O;b0j3c7:&A,T=<273+Ib2EmD[`=N&`99S8??o&/@qoP?$"H#EL ER[h^aK(iFGP%TAeefT$Eib^ "eH`n!A5\Tl.DjW:'CC!8/rt;Xi`S_Cj$Z=H490!0#9:$A!52\G@WG =]X`K9CI4)gYNKW0]=OP;HJ/%pakp c>":0rPlQsSSUKaEQY2iD/7.]oCP"omV(OO5WnrAI[&&A`EL>R_/"r8.O/6cV Z$JsGlfKOZ:6t!G\[[;\Yjb42^6ROJ[TA=jbf9AG>t9_6pnNXioVqA=2<]-;[t7LX58k`<*K?\p8IQ0At;LEW0+H6+*fd3SaI'$abi7rAfNh/,V!@M^H@_i&]O,^,hNt"(mg!7jji^R\ 5WC=]M[q_[Mb9.nl!"BTOBj&Zkp:0X],&nJ$\]]S1?Ra^#V#X3](Q9qUlM2FqQefOt`oLUd=2`-ILq'kl';P-$m&dbNq4_Xmcam,pA6ZI^Z&eX3jLk'W0^hf('1^&b:oT=nOhOTQA!oh'^#R>P?3+L:XM@anPUHL8pEW+.d*,t`Q423Ea'3*,\8?[_7i8SQ,Z8-EeA(or+LtA^)r,Qdf!13HT>+l>jp'qK'!5\S+\1R[T(lAWG@*@WXWjiJ(-C,:$Q*g;ZAs$K+Hf3f,l'(.`2+Ltg=LlUj]A)h_.D4AVThb_:o"E,Ac[$r=`6CM WM85D/Sa&]RgDY7Q%1/8AP\-`Lla-5N?aXpkcrB7VV`E!E8ClT8gsmJb'3W`?C9rUFac[X^gUQ9TDjZ"(jmU54^H*-E?/q?8cIS:dL0@ b]9#DoU)^p5b8X$*I51q^WsA'd%2O*N$0gEfr(ZTj5]CgAC2n@"p0tBEHN1mYX"?InEGR7A0T>VMD`$`9?cmc+SA!/^SHKc6PB@7-/P'NLQ)s%@ (7\Eh$-;DE*hDtr/PG[]J69FRXG2K(MJRMkOrO(Z`KnNC<)o[<;`1hDl#((g:W$CrPUn(FVC =a9A-p&SQ-.Z9I o(1,pIadRJHa3ZLTVh].bH;#MkK<-en/H^=(/"fsg&B*bOAQE_X[??,*N/ ,7=',iAYKN OnML3[P^e;$Xq/Y-%i@[)P9cim"-8t<=^bh!srU3cB\&^^>O8IjQm5HNC/dnKsYf:Bj0dN_)i26qR\k8k@Q0]_tO[dGBL4Prgl'n@/>Uq32\"I/pFTG&X`QZDM/,O t]LC\nSP'mjQ:'NA=&ln^;D\nlQL&M;kAniTD](c28,8,18:6!M7n$&RVZce8TeHW#o\G^F%2_XM-/U5UZ9q4lg"St_'MSKisb"#e#NfZ,Ce(=nU] h/$U.Spq*hc+e[@1ZC^=2J\P3bp8$c58j3_O:0k6WC##3=jW!& .f!B,H^\e0S;adAUOo;6ekIP$>Rh[\-nN+,ph ]3C1"AntH(F?`s_SB6CLBsh7D@7 ]SAJd$j'.-aoYTsN)r:=>*Gf:U/! -03/6n&B$JBQ'70?@&G8eDUk:-tPpsa=-lYS'G6,^t+WNDdb06]"EpeqtZ"fq=P'"pUgVY*r#D"JNmJXs1t$;P0;%$ORIhWYeAbL@ZSB&G'n4QD*L/nS/^GS_9?9>N]3fFnAGr!neR5=_cYH7$)Pcf<Vf[rh+C"(2A?.m,SQ+:A-I-BU-Kk6prA&+><'ls^\6#l5#gEl0o5l784M_U3.=W_qGAmQ*%%^^]6j$/S,O0"1e5/YmQMqj?<-TR!*0lOrtSkQA99kNQh.%r"dOm+eGSXYY8- )FeVXEH:P@Sa##kM\2&7EY$WsDC30'l"h>%Ar#"]CrI`Y2\8o#-\A+qnB[3Nqq!a+'Cab&_3WC@]2?kr66f$mXoJHVQb1L;/"E/[_i"2A#O_@8!_onZ:KfIm25I;qhK"A3L@W2?$7>_J%UAKVto3lMX$-(b7s#nZRWJ C8^J.dqq^X+f;:nS.j'7',)boQ07P:be3Jja&_SjlSF/KCf]MlAj\q8MYh@X?E9PZEAhdOI9`bB0)DN3M[)i!`5iE&/6cP,K8fd$Z;6g0ZR&MA+m"ikA`$A2.0e5!2g==^N`#'j#rqt:\ _q.1dcbKhVo5QdUjl=<^Q%pF.J[KsmE/p<.0(?j=(@bU7 V`Q%*Q-\pdr%W@>etp(Y+?H+WbnN;JBNA)3Vh91?M<9/f7_j,B =E28rLFmb9C64o?NB1Tf]a4#GU:!(3o?;79.Ij^jkY+e7Q^4?[f:@sFiqGiP%`n/f*IHLa0CepA>VB3hJgZe32-'2hf$1) BHM#5PtgK/B'5D_/qY1=%*GQ40 `k-S D!DtVCL"a9kLRr;^Z\S5?4S4abC^_Ji.9=:kR\r=)D7H=.-1r.OZa.N"T7(U\snk_BLVsX%0AJ0_%V'jK_.e;o,A=ercfJTZRlB:js__+O%m9/`Z]`[CSU4%e<4T=F3NGa83EIc^MZtk;J[Yt=&hJ'$PTA#8 F?B]XWF(CAKpLX_Iq5FWSe5._?it'%Bh7EAbZA"95NAo;_[WE/Z/0bGIP'FkIK*/Ie&la!C\nR&'>'c'n2C(t-ZcodJ" %s04ZBVLT1OpehGq-lKmTD1(1"Ds^"^Oq(P?^66F9X\HT/&MUTcM 0OA;\<[A=d\TRPmia>:qdh@qi.IOBj]HO#"0.h%nSlXOGY[$mrSVp[Y0NICa8RL-.!ClD,90Hk^'k6a6cin/Zb!&je^@+[00bfcGFG(LY81#7tpAeR6Lb=qT_H("eb:YOiiI6hV*SF3:9iQ\d qs2h->dl6OT#PDQEbJX66i)]FtpBF -g/J^S\sl6n=G'Jr2:#B8)KM./9:S]Br[&7qh*'hl6L;"4f'[e8njR^#S@J6]4DAJST!XpW>?UcZp.d64.E#fAR#AQ"CFqY2BZc+AOK2VqA6I'YgjrfqW1rL?F[BD.fRm6+@2nsc3/liS%:$83NB]RUFI5I; M14H'Nik4^<'eaTB(=6L E*d$(CG@ >mUikAR:"3Pqd7$''eK1^GU`>aMY*;?gnmc_E_1ct+b6LWJpR_AJG$b&?iCaD.R"S7VkB*8&"h`YciIiHg_3%54DpD51IWl=V:5@t\EJ5I^8K3%8#@l85N#[C#<7]!*1MpRCS44&TfRhG_?BH 5;)CoIJsT&m9KBB;C<;WK$?9r(h$W0X5=W:_B+@W>O@dJL cU' fH,8;M!O(08I?W8S [oN8c\,Cc&'bP.;Bh&(+$P*Xq,DmW)Tt t/(Q(EtlLC:fCY&XD0d[BZO0^ht[APo#Egl^c<\Z"FUY_A!K=j8?9#/N30Kc)n78ib8?b^7cU^(fT@q:%(W-k-FdA4Q\_8r9VB]%SP]?(:>DYF2H@);(A:!2$'QhpD:B40!K.BBlUk-,W5T;#QD7=Q;k5,$:!,OF>XA/N#+ia]dUIF:!i"9tl:a]$e2=CE&KdWFBC0mA/(%d$qgD#5=e?R=S]\$M5jm)EJE4McR!Y`olVI#D%AAe[?*KXS,b":;275`hGb7QpHA5/'sqb,m@pXtWq#WC",L35mH[FD`P@mTP8-m=nQ5lOpVobKa##,I^iK=Wj8SN@^^sK(]2\<@W8oKs:<Ur8%E?i(4?H5(,5GiqX]A4:"rD*\cg!*$*(DN[2IaG:l7S+(K@%G%XGLW`5ld VRXkrEIJXk@,6RB4RBbrm%i9rYsE`]&^' $FpBbgjj8[a*F/,7*_Q0"3V"e2_&NW_Q2nM?E@(hjd1lm4O94'_6 IAJeXbp;m,!(J?H6I$k;(n]H1a*p@P:1+hdYQbTi.8>:j.H]q*N'cZ1a,a.IsC@c.rl"*q[s8K,kg:3PM?:t #s81l&,"5]]Q%N1H`D\WUS+AA!'\2;4@Xt*2b:JI2F@ERF@rem +O2.!&L#sAsZ[U]B\O$p^=;_WUPcp $-W/#_@jmh-kiq*5-LC*i>Q1)>7N;k[_jqJ!p^%sYC^*h)k tMUVh7E%P&TgZP\B_^1/SS](B=e7C3?%C=f$$?D+R-R2W)[ln`(Zn?\/k\;%j*+_;/AK9iJ Zb&Ic7UW&GU"b"*sU_@D 3Q"oHbX5;P3`UAAqF,keZ`8 "j6_fld7YUI94*YMRE*K99rnd$o78=?O>:Zh_ LpQ9F_L#^A3QCQ$Pmt8>N^W.)QBB#b/fefCTOO\/C[DbqdJN;iQc)_2K)i>tEN!t#Eo7EFcDQM*/Q$DVq73A>3q"?rs,DC^<@Xa*UNT)3eJ`p,0@eB-^MdL]-+AW?+k'TT"=*QA_6N#0QOFGW\J +CDa"d]!*[O+l[\"D)aLG*\Uqo /lpZS'`25':Se#*7@QG@>i1.@tN\l0)48QCp,Be"c7Vd8C!NOj7,,GA03+k\JAPm6'EkqMBeqlI`0o=jW2AD#Jr"eLF#K#DMXTA?)p\WG.+)@aT5$rEkal[sh#f)7D1:N@J.hLlbZ5gld*A%!]Nj+93+Mdh;e8oRR@(OQdp$:KHVG"_>S+"/0$AKK"iET>q4-g$g`'GQA#O`iA Qa AP+lgoob, QXf&Bm!5/(8N (/Ht#*%2/dPin7^G+o0+$6<8RAVppX4`\eo>*RtAe7)'dO9B[GH:)cl<Aic(Z-4gZeOn1Bf]g 9epr`)8M;m#ftY:ZEMI_8UJdaqj)q ,h\piI:L:%#+*+7o.GkgkrmKBU"`WMJ8$XMWK=hU/AR ZC4IUaT'24[l.XLM,/.K,qtV(2cf:]Y#G0O_92(ALUY:.'q79aqZ4CV%P? VF8qc#^Ss3fGdSA>8SQdK?;MTW_UK"kj2,F#_OA/objAB^k_BZ%re/blK+3Rt lrAJ#ZeACaIA(jh \(Ne]R_`BNQ>b8A\P-"/ABZ[KA38!pWd00d"FSX/]S=CB=,)FO0QioNX76k`K:9,YD5HX(arVUq_-Y0co*V)Z?h`C+Tt1o0e"@m7SVai']@hMG\*)P9M7S">c+bEkkCS>Hlot<dEmi4$KCat_n#)QhYAUUKX-ZU*4O;D=/4-OkOYdbVm)Ng S:Ia5MJ),E33_<^dHQ%j,t*#?M6SZNUT#CH<\a82m22`@NpdTH>(1[6)^ZVlAKE5i2o(s)rskb3MfU6lYlss3&96[M, .fSc`*OrF'.Y#MpkH/pde%<7m:LtYY&V)miFbqegR7Q ACrslZO^J@J*#V.H"r5m]5j.A.U7#82lN*]3'4mC2fQ]*n*`M>JZYCoAr6m[s7=V9Jfb3U3o77(9XYT;A!MY>ke"ni<TYVJ$6k.#. PMphNC_J*bi:DS"BTb[CZc92qjomnC;Xd*iHA3@F*C^Yp?Fa6>S2[0 r*ch2+bA U@j\VAZrA<6[4b08g*:-c&ke ?fU9+5$ bkkDB#9?FP_C5aTLiHaY%D7#empaDa4W%`KV$<"tD,H>GSLPNO'TEj./\m,jt6TWP:*hT'eP[?V]-Sr_AbFZhABkt1n?t0*Es"WQI1i',F#/=?Cd<.?!LhStaQbW0,1DS"<A:Y]5rIq'R<[j<!tYP8^mf=,n[J"]>V<@dCam7\A-[<&3qo:RSSHB8\8qVEAlG8n#$fbnV$5RHEtbDJ-6QA%J,OQ47n@#mO1'2Xt)>_^ocfoAT>Q`>GkdZ$$aM-Y"6acopBLJI!N`qA96bBoap9c5FR&(T;as,B9.D)"6n6A#-Ikf8YJML?$N?eT@_]@Y!R*B!J&`0!P#IW6I`eUO>qm-NA/W#hJjN!M\>=%iXX)Ik6;G`Rl.BJF7b4+Sd7;q-Etb0Smtp`7/02B^]@7>GHJn9XdWE1LL'bon0j)f7=9-I9'5gi)-RHhV?Y+gWL .W2*XAT-qg6VW,)3>(86YA\cIc6%s(/M8FM`/3>#akaIC>"I__#?ls`7PJ*Q@RZK/.-%%9toT/m/V'"YQaV1kf-Pg+$;\*grK1KD2aQM1tLp`T -V+qXm%=$@/%'k(!f?'HY"9")?KZ]<13,lPL A.CXOJN_h5$m`%a[S)fi,2j"C(aAsK#?db:m2EG\ Bhq>Yn:VVQB`VMLIK'P&n$- Scm&j=ilONY6qSNS?@j)'s,(K;K%\1m\A$Y'GHCPG_sJ U?+S`cXCrDAM0_jq3.q#R/FMf2JekA0bWY%UPQF>E3g&TmJZPY1 8bj\Gj^`q@#!DMA+`1rhm:]n!D!V#.\kA485=ACZNRP]m"]fhcJA.@&14C25=Iq]FdO7+XWe+ )S*qre%GN[ 9=$t8,g! $l.1$[MO+FUXqq8o$[dpAA()4[8^> 5p-9i]L(Y=g:M%.EM:nCF6[O&"B4;MQQq;\E@t'/1,NZ>:iXc6 *QXIbbUMA"[jV`iAVA4i%HCStaApU?fs(_(&c-`?C6W(TD:QAABR;-=p1VhDKoQC=Gj_DQg@j?;_"Vm,8Bk#OZG8sCYkii2AHa7'-Eet/>Z`(hFCN ]Sa';LE>#qn5:!a#-WGAQt!r'BAFI:B'r>6nqngBVHlNK5Zf>9VQ9o\*Xi(1t4lJT p#YQ]1c37h`mP-8J ?qRg['1UY2!KB./E,`BP#Ca-RNbR5+#o,npPUNdCp]@0Yk\D1*X/+cog&LS9?O12P-:.9gk`)K#=SWI0]RV\Hi]-b\^N&F;tUQWBTY3"[94O!8mc`?__6,[ATkf-X"-h?Qs1hs\1&AP:d9R\!Q]Ul&r-NgC;&D'_ gdX%j hX[hk:p6khM#7'8s'/AfS1.;FFji7):shg-1?LcP\*0cVT^/g.4WU45eMOms'FX8+ihJ!\ip/>)Frb$pXtIYY;U.]q`XC8'->lm2?0l/_9d$1R#Q "MCPLgc9t M/hASnmMmK[nMXJ5-Usj5^I?Ut$1:O@FYsRm*V<@2W8EhOA,g_Cto"2b#p_"m[_^`Yr%O?g);KE,/C4+\;drM)$*$UZ)7_.:DCA+k2eAk!sB5[I@5m$Or_+:#^`M#L%Mlj&P$XtBA1Z>4S[rf) o;'?;E>+$k38#JNNke[RO*!XBKMq$RaMB%a#]FgtKLWndl3d"OF;/OTY'2a56Q.TpOnBT'c#52Po"N jpRV YaZd6\4/R0E/ZY8@G*epS7ja&_M4W&OI=UjQFmR:]kma"f_3CrNdepp6O_-k&+Vg4-A)H/d,@ZZ;41X]XB`;3))Af12R8d%nqj"9g"%XJiKUWM3'l`:-9<(cc8/OAUK,G[f^iOMoI>t.At&n[(+Q0@pq; l4ket*a10XhApT`(0H@Mtp:UP=5M<$SJFm%r!/J+2h4?:e36P[]54Ajm^#+*R*=eW19S[$&(psdMZqX.P5:'G5'@\-&NEk+(Ptk/t;b7O"'H<+Mg4*Kh7(c!nZNQ=;i_)3iE:gDgIl;a^f/l/Z!7j$;p16Z4rqp5]88j[[>1\?psffh;Yq6DBt7joW#+T0E$b:i]L?&"LR7`(N1cS^a57>O-!LOG^M'bH3VqY];-:dCetc4UIM`ciab,_Ek18dYU"g';'"HKbF ;>fLTPi7@sQ-&er``/-X5C/A.G%q:e/I(I]dWTV/BAj\HjVtZ>aO,gi#o=(;1D%tds3@\T;ZDC^qLV:Wl[N9i'=VWD!j9P0hBZmE>1dDqS][[ABO)H(%E:'R][551":,UD$*U^`lU&9WD=@eD!]R74X#qo']*FEO3tkId2eEb"=cea?@04l ME%QZ7oji'B/l`r+.F>9@/c@dh:W]E9T?e2S?W"i>l/F;f9jF9/do%]S1-9Y:sn[8B.!ss^bHB7[9>TQt_n7W]2f&IK3KZBLAR5M`-:SQG=Nm!^2O=oXjQmN**Bbg82=,?%1 ZRb;4:-tt1RM5T`%)5X6Yd'3`0c"UT$-$$ ipE;cs9ng;KA&- 2 p\0#/YI/D2S=p7qF%W8kD9.T&E>4[d_;s=(*H>p,ReVWnLW-U)X!.A.pI'=Zf*SapAW5/$+fak%QqgRL`_U"CA!@LAAfjE-Cj>A,`<?m+,,W3XOVQr[kTQHY>@1$PE:LSf!'FjLjR;;g%j?P0?LiC!fU[AY>TQnp6[*!Pf60],b_%DI/%`CqMgDp[?3;P`M#8U2BRAm_^PQ_8,cFB!O8*ng9o#^::F^AU_JTUH(IiNs3]a9V;01;<7Bf-WaN`)F^"Be0RQ7LX)oAFlTL9krLkY`V;_8qOj>k#1;Qg=@sNr)I&/gAgX lVbhF.FCEGo2ChEgGH0:&@TBik&Tb7[``d7T>L7-_%:Xf2n.ldtlj>@Bd= j&N[s[R@5cQA*o^WAB:%A=kbN?pS14eFM#Y3Ls[b](spXdn>7[1"(8XY91\g"8jdkQ_)P[FE`O9A?,!ZGs&l8>%1%6EMTA_qEqsEZcH!ic:.=[IP^7/q0"JXId2 8Hs+2AtK5l5ZW^%h8([?A38LIPT`PAshLUs,''dC.6i0j^l.'U%9Z!"YEal*$6s2(N$nM21&T')KNc];JP,K1AZ&HgQ5g0i;@Alof@02jOWXa(mdOktRImheaBTF"+_G9S$6RSn';FoDmm?QeSKHkA7.DfA]b.Fi1k1LBMXk'>K&Al..qA1daLmIQAgD =bl(WW rKQ^kg!0_HL08,_&coL3"L)8Zp(cm;K#J5-)#V*._78W_AR($ZKHP4-:fPm0@/k1!8^[BXSoQD!o:Yrn2"2T^"Jb9s=UDLX5W@Nr@'SmXd'1c'VspfP#7b4@btdUBJN3!^Ye@n\;)Sf#HeATK9mrVQ;='!-::"IJk[^1n2Akm>Gi,e,aIAZ783dI&Ns93`,i)Ml@%l^Z J-sqj"b*a$$9Wj?h)>a6(0a4@^a`NoF>EA2Z"%6O@'9%.2PaXIDk-MB^h`RTrFG"Ki-]4k,[2kB63/da"r,g)*cH;HC-daTZ_,Bk] W:? ?`,e2`=TCLJ@knRUkoM*i`_Ah9PKTTIatn#:pp0;T_kfn+$c?Mq\S$_^Yj/?fOK^&Q$-94\0iF%'8D/C*3@@XfcGZ;K]E*)T%llg]b^SLSt Vrdt4)Q>?k0SQQ6:Xeg@pm0]1>,TnkC s&LKP5n:EHp2")g='d@s)2;-Y(Ud!A-'AE4R dVZL>MT)q4<'9Ymfs*9?Q`d)b2H]Om:]r+Kn`gt"_>:)t7!GA;&6'h'-.\lr'erd(b?#9?9Yk?T%;AXE?=09Y[DSUh4)8HltINi0J#b]Bdt"k,Fb ]NBR2/8_AtKDN06M,(Q*0IVE:pG[%)2l@A`(R$%8frtGF^i!6c*[)*Mc%?+6q[0@Zq=V^]`#/U&BT_'6FD*mS,AHh["]`N(QVo'7Z-f,1_^s&)nG!,A4j53m`k,%Yl0i]A2S6"DHDUN_,kR.66#dN];A$\_ggOGpVsS"p9]cN)rL#C511GK*j9H(K(0dqSJ]Gdb5A!Gmn+hFB2]jA>'@8iscCUTqIJ@^Sk-GT'pR9<P_Wql2^,(O&'An3QidAhi-0VS=^@dbe%;!On(OYba(j[*dJ>5b16&<;>3DZ2G L0,]6V$0)Q(fK9o6g&439WHT?C/W&Mkc&&&7g2V/Kq"_LqJeGEJA,U%Z`^$eT reZ34p^FaPAKF>]3RJZ_,)>=r\E1 I-K)$b+ -@[&ZT,mc0b;C4A@T3,]Q97>AC% ZHN b"f8D *a(! YCXb+^Q8j4V6+*:<]j+De"ZeR(fL(/@Njn5'&JG`?@f.$AL%Ht-:iLUCa*hl17k([ZY\MB kDRh#JS]J.jt@S?LBh0SVG`AN.?!gqAH,4DjnOmK&iG#[P2X"H!fb(35A[cr$HLcY`cp^Sd_7N[]@o2i9,N9Z7:STafZ@E>,"oXL>W""!IsW`n'9%>O9 .]!-O``>qCK02AHnPOAYDK:f][ZX;^E.mF-#JpSNM45q;7Npc;JsgQVtD@dnT9n,SN4Z_8V3ML .Bd1brK:0]9[-'!?gqOl^$g9#he@F/#0AFi44-GFOmX;1Y:ot=40rm%G)rZAp*;A#$]bXcR)FL.ot!/ HGcOY6eboK>T;c`Q@YZ2)E95k0(Q]Qk2mG!lA;3=?"f+s>Z9gOJe:`%EA]IsP^bL%a0'Qns/V/oqN*X\A*SWV1 7H.;U)V,f?6l26J)'r9%S8DHKYBSA'6>d#Y5bHErPHIH)h ; dcmLG9=WNP^dV2+N;./c>/.'Yg,G!Z ^"c6S3H+AJWf =i\^@CX$IFJnC(,AkAGfY;jttXd;0K+,#j 74DomGDbk'5OeaYs;*0R0b]$N4L+#f"s?8$`t9;OG%Ya@kQfAANhdLr=qRH:2e"T)/b`Bjg(gD( 6Pc+^[&VdH@`B>"qJ8NAa]8A@t%qd>[l]RHQ]pZp2\In6]5?]l%j`&A)5r2IQM:;Y9rN+PP*lL`ZCP_@tq:r%T?B_$39l r\hehLm38iF,_7?jQ"=.\Hs^+nEs0Jp3[d.3mjc1]OH#`oM#1ikiAL`]8p&>Y>.AKBB4KGA2r%(Z0K1\QW7!X- =.BLhN=d3as/*B^#MY7W>5hH,55H1,tMY9]Cs?H4/6da 2JSJa/t.(Ms+LPPirD0MXP0!NF6 =`!+`A`RfU,&d3Q+lK`,e)6$IcpA]r0mMfncKc[1WetLAXiV7]U0AHB3/"nBr'kYZU_/3:joQ-*(OE.2,@L`K cM;WT3sF>(s3=-i`o!-XdtHROf@RQKdIh<+\b,GY!d$r.8ho5%KDtFok?`?bP6:T+D?(qj_=htP0r*[6B'WEt"m',f^<\`noMW!_e!c3Gq")i?spm/#Yp BAQ2jmc9G "]FA`L@8h2aSZ9X!Ym`fKQg%ViTALaF&-3%q/BE(s/%`A7q_lf8DJrfgT,'o_(dKBR7j=o'G2Y6"O`<-OCWTGRV/=f8HPB:d_/tg)@'" DjV?mI%[4fE^MtHE8eeH"h2pS./3#@Rt0%T"-"X'aLPgmk&1WC7^$e,Sq%Zm;%.+=c)2MMg2@k1JfBNFJO20-$D=@abC+kKf5`\-g9L:tll4(mq\6X9jH(?dUVK#t>9J]H0?EtAO&:BW_pV(mCX1qoP1&ArT[oU_NWphc14NNs60UO9]gbTH` >n!IH%IO*(FaeHm-ePb(>t'beip%>6(FHP-)+JGN`C>D4ffmfcYsWcmJXBpOVON4``0Q SHQG?@!cW/hoZ ']MH'^0T!5"(i)h]Y\(9FTfJV:4Q&ac[Z*f:,@(pL'T@0:ooO73t*S.S R?@3gc+=bcCM%M[$P:K<;o$J='rX9Sr h(fI^fR\'E/#][^@Y$OZBe;-88NUnS._L,N\$5cs atk#T3A$ffIU;''(A$%rrsBGD;)f.Ar(>3/\BQr\Tp@LX^_71-\)@q"5U+dG\m45Z[RWI,RY]=UE=nSh4\4*(F4K?&Y-XSFAP-irK]<">lYQ-?o.j_N5>#L:^aaA?%Vn8VQ3'@m*sF#2Cr^CNV!f"S_WMCICaMih:_?p]%MLTPB6C3o^&L!<13?gm_qY)o9;2hGRSJoD;Dt-#Yn#e;<1=OL7LD74Srmp5&UAq(t2;"bQ/\5n.@$kZ5VR*(Pd -Uq%T`9j[S4J@*g14fA-LLted[D.m7f?"#0olA3Q8%m4KIoI("&Ks,.d@5.m%7S.D*M"XSC<iUQRKUHa%e%8LWNS#]I6]](9""8pJL'd'ba\l%9Rcq%n^hZ6'=pF7^rYsoBnGcg_T+MFV<k0-h'*YjT[-#DfD/L`6gqp<4M^M?<`Dt9NU^!=UXV*Y7'P=jA.:-^ _hP5oYKAgO/-VA];+43=cTaOg"(G`@$6M-J*C2.jPo9)Z%IOq7K'5",U#XK(WTc:D*s0oSK%(pEl.Do3Qof+P9A"Gs &o-20FR_;G3Ab:KV!q>'JBX,2'^>->L`,,8odNI"\<&PEk%E99kZB'#\R:.bgbgUj5**>=NE ok7F-:0.&DXk1Y_h(3SI4ki"GTe@%(rc=t4>jk#o!@rTC97+bJtVnc^[*tVpW*6NIZC* ;kAf*))ghWh+T`47Y^6h?s<P*0ds(h*"8Cd$ ()W&_95S)U9>t\MZHTgTBZ01;3;TQIMbjC\PA]r0$D8Oj3>n=O ?N\)E e>a@\+AS77?%N1K[qjLVAgob#IUGIFa8lQ%tCBIYXCjf?iH.5]j5+*!k&DsG_E_H+Z"(PJ$+l'PRmA XO>5BpmN(MqiNP*A,@?9Wi44tbi4'0'W55LNmM2AZfU;DGU^l,g-XENS,rh"ZU$E3\=S&DAEm9r;iK^N-]cF?I>n*ZLbA`2<5[7KBDLZlA1r1%ls9R;oNZJ.9R,]eQCnhBnF)bUL&L.?RYSbFONNqAka]OVF*#biD75m(&]@k6d5%dNiCs#NN=e\=^itmKL*UX )q\j=hb'J=.s`QV2hFD1K r(oZ(lmdXR7kK9`j?MN7,ghZ`r0N:_>A Z#kS(V*C Y7bAeYGTpK%;tl6P!>Q1W!SKT\FS8hq4MV*:leK^H;N>pFkI0)F9K7MZ1Jpi8Mp2T\_(sjO!b-Eq2r1:[4%3V%gC)pmecS,cs0GP(/(l?X260AgGL9:&)hbAUX0q7Wl!Vk9$D3.X8#,COLJ^a"B.KbmT.*%eJLl'HM'i81@)>>qfq"HJ4IZ*e[&CF_FgnM]WT%;Y.H2br/ir>G-]="3TJ]/Z9&1i5a_DArr$d6ST?+ 606gF.trN;AQg?2TXfUmfNE0P*Tt&AGpK"*,,]\k':dVcTY:GPXXW=6\cf>C$F@-KJ$B6n2ZR6U tYkl-'1D\A<l=2E9TBINsjp1(&tsc>Z $"%O+e(QUcGiXAO8JtZ8 !K-O]NEbc&R*G)_:D^nfU7p->OA(Td05*?\`A#D1&$Z,L7 3Qh9i)b=L737;!*a8$%j?Snd3\tr>gd\5tXUWs$!aB*-67+&l*TL/`G;c:^\L j=pV5:[,pE`tKNIm:"r%`b&^61IJ)$2Af86;=AFkQ'4H<`L/S'X.3[?VXa7@WiOQl'oV?Eg"j;m4Zj@$][-.4Ak+3DqADc8+<9rZ+h/%:6+OQ=4-(^Om*s"6hnAW_3tb=?H5>"f5k$bD]a1ULOWdf7I$/j6YeaFq+5rrJXWkAGL!;Cq.P&KD@IJR1 ah[nI- kM"l5=bj 3O4F%P8s\M4T:#aZB 0"dgA.V3*9L[n s>F+RW35/TO<.5iX!P;X@OVeZC=p&]LO1P!aGRn\!MiYF>n`ORkFbOenKAD!FKg.RNAl2jiE t;,;,i#k]n;SD$c+1b9'j471C!/0I RFm?:h,Ac_Pl8orLp4&A@oUX65JFZ7,;?$ZF$c)!Li9Lh/bLr]gCRKA#U)ZiE>g?jIrAR-d^Jom7ON9Y?^kaokCpR'QhF8M86-4g<TF8\clNT =K?Y',qiqE&3F4,T VU8f`K57\j@!sO(Lbrm$c`GYK%Q$fn0P/,telXc->@[Bn!UB+l')=]A54'PjY3$-4870FO^0+/8_BDHd.2^4.`(/I.dOY98T0NA>)t^h;5*:+KJ-6#@`=B/t@hHR#p^m&k!;4K9B^4FMr &70R(ErANQ^7U 7E123;pZtT+72f69F>4;HDg`kAg<Pp0IBJU1]+cpM9Pl,Ae8X5Fo[Z9[r(hEd(>hLH@: slgm+_4Q@. =qXge<."NP!0A5]frD]s%/;TTUDfZ]*\p\c"HW$=&-#,MA_VE".&+o%3*P+O?E$oE>2o/&R.ce-ST6kE<U.G^PPZG#;,8:E?b<`3QWMa>!X6NOT5CtIc9D9\h&YbD%0WAPh@#3KK;UgB'XOp0SP9/6T"mA`>CaBeebX4eCKBWtOc"'HjS6[.*YMZ5'm'R)_88g?P.cEnRBb+C7q>Q@TVX]a-DfE,;Z4n[0ZV:TGQF4>cc\IeJAlhNJ3`m4A.4;fOtMI]E/1C,%>UrO,spXDX^7pZe/B5@='S7ChLD1DiY]U6"VJ3"pUPJC!`A"2Whb4]c:.]4B3"#O+Z*4*%aJ8BkP+7E/jDcH!naD+iDmS`3QS%OBM>Q'cZAaZ!a#Hh?A(=H%k!;]/:AnH5o&JrV8.sZ%c=S0)oA-lG[4_Y2TT/KW@:^gtt$eq?q]R?)ZEC`Y!^O&/k,I?A3:]<`2:As186Y0PPBfDm34gtctp$8@F;BVd(,4h4[QAY-tH!TA*nY []?mQMIe^R"jrNMqs*?KF$q*00tT.l7t0M9;S>]MOf=]62.RG`arrBH.`(ZP5&3POn%=,aSEW >Cb&Zq51r/^MqQeX!a4U`H2]$$4OhKag8jdpk-JALjcp8M^J7*ga7J0!jTBPa AfR1_1aD"4@CUe9) k#T(*3WG?j2%-m8$3>.A02XQ$(P3>IC7AL:kO$7kJ'pdWi]A-)tlA&3 9dh@ L-!oa0r%7fg4i<\TejfAKt?FVHV9b&3Kc;fmBi`TF9f'\Sqo-J%`F8,;-&i3=B+F+>qWglV;!\T52SeM0X^D7nYjm<@1i4]j/X2Sj[L[5-8]r*^h2_Ega6##!9Jpr`a%>+1RDg/9"G"@><97=!nW>cg,r=HP2j:8Z%bM,3)&^R+=dqhRmLgL*p%Qd4cDnTJA_\kT@E=_^t<3 TbBON/N4p+ohs=)8d0AT&[[GU6rQ)U=@AS3!O.:ae%$^a:eF$E-B*)NC+I]RMb(OP:DcGh$/kmKC^Fa*(aQUa%aIhe@fTj`SO3p2hf^cXp],Pr+?^N?qi7.+PdZ.Mc7gKP".^,^M^>)Tkg,15F*OZebWqLVtmjP_'tX "dJgUs^=('a99?t%3is^Xc=b?$+R.TVfX7LQ_4ZsSs* V<E%#6d69WI>:bQRrr<="DSFR;h[*=Aj4j:3:3:&n$LA'="tGLIqr>Ho4k0[/k;$_abW0=ne4`NlXo1!VN.sA'5'eZ&;%9kq)#s!IAfo(KD+?ds*nYSVcOrhn%PFM%hQ*Zh&ArDNHq3p7TS&Ans>Z:;@:a3:8-T#rQfUdad/nX&B/1%4SK\2H[]k(42sTnPa-om6ofNB52NMl('Wf\R;G!h^WjmtRS%`R's ?A^KUf<>E)aHs)mUo/U_-,1A(MS]C,0,3Hkk6QKWYOCBhMp"o.T/mi]3Xd8e9%296>X3>Kd):Fr41"T::Fg&<ht[WAFrshW4"bL+TmSsj."XRSW9gV:hBk&/'c.K_&G8tf.$o(W^'EjdR=m>k#S'JBX4p`d+5[V'T!rHTV!fbSRST$kr8^*s_4,n_HRXCOUb:Qh<:f.^A*6T@nb!eiPa$77Q;:-2lE=FC9"Qg<9>8API'1:-B=\_X=)8'UrRgU"'4>V7Jr9k+lPGT*tZ((i.OfYj_N\PPQHXA23G5pC6NgFAYJs0#+'Ha`1hVf/>td- ]8T[c:qm^IkKp1*!c1)m1lYmKj@V"GcI?^ss;ZJAk%SnNfbPPI^>t:Bh-BaWK.l>W!ChHrtKEZ>ee_\MC^\C6]<:C$]Aa=PnMq(l%LsV`b&A/?iCoX;oXsj2Eh-NEX_'"$p`1SsA+Y;@/U3R"4TmTtRS1PX2-N(p(tE%E[!f54H X:=RX]04.tMH>kd"_qmXao4"PhQN [)2E3X5^KFGUs^*6nbXPPB>`*m_X"bPRr_j09<9&MUXsHee&m=pR[d4; GIhr[^A-m5:MN 0BfKb"V.72m`$R[rbZAk)o r%KqQXP;kG6AS9oUk`rt#i\T4@'EhXWqDk)s2%VVKYrf]>lZf;4CrH&LMT-4_(AX"amL?UeerlB:f&+"ko?:K e4m2!=LI55i;jg,-;NXPU3gAhbO_7Ga$,1FG<)lKK27]2468]I9NKi>c"&B4E%Ga!qWcc>A0Rl\EtN!dkfkBM@.+dS^`+nEAiaE jP^7"k5do[g*R"eZ!NM1_oeq+?E95+SRZbZW#mq/-p#jL65sA[TfB+V_+8YpG%CjS/R=eX]F@hf-H8cARJP-s2/A'A[s%+% _d_roE_7!J] qm>F1&7,=@0c%0o6NGP%BA*Fc9@jmKL_"Y9PSG"'FJs#Ki+T'cSb2 8ZA?:kYUQ[UTY_Cl)%9.'YjB c%[-c0/h!S>fOFV`7pFcXEo$/.k^JA:XAPqg@\ ?tl A(;C,llcO%HbKGJiM7);(PK#*6"df'QK@7>%_ils n(J=\(=2mLPK4#@.k_RRKX8qAeoR%-'4(#cF!Aa9^kiF8gInAM@1J#cHN)D]eUSh%.U=4K#<:R;]ApDS!N/UAA[@KPPQG?j'-5HoMK"a"P+=6E\#a)\/'$XH:f9AK6lAPk=HH6)&a=,[L\[00iK8Jbgj-lqA2jX#fp^Vn+D"'fWg%pGM0L;eLW-]]k5a/fhh,#7`75hhR/a*L0;3pQ7P8$+le8YQ0$lGoObrc=N@fA`_m`^S-C-:e"!/GZ@"g2;(+*7AJ*K8E''4_Bh(K0;,)3, g't>enZq/"VbTGnJ.r`9Zm\P@MV2Pg6b82'$X5%C*ccs,o8>G'2Vnmrf%7- Y<^>TL#be(V*ALae<3r30r\^=a#^o!OA"@F9=CAgO^nUC+*_%b:VZ<0ka>XB#,t;4]S'Lf[3j)7,Yl=TrK KmJ1@%QebB.J7 ^F=g)"QP,LH>45bAF*l @Jh!ObUpj;;eH](mN#gAiYNW5VrcfCc6GV*aGnPh'S@0@0;K\it@r`lsn`hWXa!mQ"Km gtp-:^;>O-4kHE`*MrSq)F^0RI<8mBbo$=0e%;)YT&2+?(!jjaT=2Qh+nr=#078':9DA9m7 jH3gh5YM\]XBls%gibpM;bm(T)ResJ$LGs;W`!GNs7R387UL3@CoMX^,BaUT-Xaj'6$,30i/VlT08Ftl^R M>`ltK`/?.N,MLGN]?T:<Hl):)U/dG@X:Ap'k16(AM-KPd3]KQ%/=eGFLi`UUr\:?>A+JMa=C^?&(5GchU!AG]GlO<`(qinQg/2t7;E[Q4>8^(A[>$MNj4=/K;S53Kj1_[(7%aL$.t^XltDja#<0,.#b0lYG%$9SAALMIcSoa7Gl:`G#W)4\mH5"MH+WL7FF0EtR6K'.^0Qbbb6pkdB>]6/Fk#`MPG5BC,V6BfQA`gpEEs(*M?rl>-RI"'b=jEAtl9J5Fhr,BS?EN5#83F<").-s^i<G(pF/=BbrD.o;hgGmbSC"0Yog9B8i,??ddI#/FD(WZkI^?(G6,$2[nE?QF+THAUsc*SRE2QaA;Z&'d5QFW/F/K*HB]%VeNK6_'XQ>">GXVQC] 0cAL$p01/sK\ !gR23"/_nA g5\"'Q,(mW@hMd`;-S^A\d_d=PP2AP'VC48n=&[(jA\Y0DRiID>6$hAN@ M9=;=Do7=MipjH\DMefN/7Yt/h/e]AZr'6XQhPVL5b/.?Y;S6h-cMK`-Znal'^>.E>BSW"<*!)h]TgMVSBeV<-0X&olt*fk^3T1otA@N>Gb,Hm*"MY/%e5[j6g5PFUo+.qO$i_1=s8mf]I4dRSW:4da'CG%"H@m$<_cC>*#@V\k<CUit>TW6+6i1&Fqa5Kmd0LQH7[EV``MZnlDDoTjQfU[eXQ3RN=SF+pVc5o1Q:EH4gojn2$Eo&Mf3D._j(`fcM;'gQI>6Ec&qO%55jKt^'5AF=]$a".(A_Q(p_KhMeD(mJ2H)=gm$L"`ED1hb.FY`kR2>FcS6Wl4(7*=F9l,4`TKEB=(5Rr5"P ?h4$f.@p"gQO[C>n(gPR&l>gU/I;.PU1dF4DO?%^m?AM,aUCGaP@8_>ABJ>/jW)m4,'jUWTFga=LA9A6GnIr[*r9NDRPd,8\S%JV:b?8J"Af8(tf*6LS3^`_sh86/FZD0h'.OXjmoOOipn_5@6EhHgg3Em/k9Z>C< jP;[EN4iLRPa$\="`RLH/7NS?OA /kCX/:Kl6A[qZUrl]dgBfYB^WjFj[Ho&`9:s8a8ik/ ]d-=[6F[*>30 )c0"JQ&!n1pde8*2Ug?0"E>S_1+lL,eV_>16D%8iWW%?^\cbNC?hQ/mNla l;fbt_!NqG!!2rO\=pH  fs`.=XdqGr!AA)H7H0lsAhj;O[I*F^[T"Nj <,8'1F?U\': ;JB=E @L0B&&4E>k^=oC;(ARWB>RME.iU,nrF G_U-IM!MjZC:5h4?tfT_GFe??DS07>U0RJ(r6&RtPR]GSi ` L!aebX\<#;-L9ZbAR3f\cs0aXj=/I(57(P27:)?i,%[9WC##2I@l/MNB Tq4g^@PX"f1R3`)c(G?AWG9]UUE\G9&s&05dOAJt"nmF7I0rTe\U"eUm;H&]Nb*J ;k2?fLYAetX7.FH;qhPO34e;dq?_6 4W\pQ[-b0]q]f@8rSkAhb,[0)N3t\CM$%I]T@J&1McJ*QQbK_%:tH`2AAGo/nAN_Jms5N<P>f2Y0Qs3k`<9p5Lm/C1[N#OGK?42e(7Zg>J%"jT"LE]pJ&fMAA,Up+Jogd#?A+HI[8m75=C5/g.SpQC3bkVMlA-ne\9Z%^Mb:G_*P>s9*?l'NU_OTLIQ3lgp$`T-AhF?Q8W,]t;j?m^1"C0%L`]9l`WA%A?AEhEqagE]l*c6;AK7HBsZ!O ]!BSebksPB,p7T@Q>5CIsRh[:1Z-*(g,s\I8o;ZFbE[R)QO>&.1fXW;XUG#7,ibDMQh$QA#,cO\pa&G]c*"2!rZ//k0Z':#"mt&!)[(./8VSA\X8%teD@itpI6 8lQ/1^_]a cKtH6o%*C=AOC*G+Zh,7K,);9iVc?bm:VAHT?/_*U\mAfAm)oGOA2q!6!QJi4"`hsjR36p4K+LA'pt[J;1tEZTs!h\V>G<,pVpA0B0"D&ckk,QCRX]K2]*BU>8![4U:o7K#F3$H4mI"t?r=%3rj7_I._+CBYa]V_"% n%9cN\)+FH2^cl3mE\=`)OLeEKs0AFIFBlGtd> kT`s4Ql9A@m54)'DpL5J:Qc3:gK/`>1AfWHcA(+6e>P&]9'/0U`(NpFd)A$MIFPM'ansaARG*TH$dHp@@j$&T+]A75M7)+gbBDI]ACmr"E8kDqA$JqXpEtH3Va?QOY&!A_=/=7p.&cG5_K8Z?+H$rdV5p?3ATY+.ea+k[8-Q;]!V2\AAc5g24:,^MW?hc= 7tAeqM='\hjSp.?p:O2BF8$TkH>#=6:Ddd9,RDqm61SIQ(+_d4">YB9et:P[4s>6>ZYeL*E415.\=PJ;eWJ+kJ3':`s^H,/7:iY1=Ek5UK^8CnXV[@^ dEACT^^;0^H\GUFTa@oRb-LEcKo33\Zl]0*`lWW4:"SbaDkO5)"+3X_,_!J5c*Qfb%X#Va^6oV_/V^[%IVlYI>r)@,*D%dY;U+B[`\L&J/XBhMg9CrTl7FrJBJ_$sE**8i2ae:E68aGQVX+Om^q\GM6q2F[m[[B6'h"lQ.Xejf,5`H%[Rh Dhg59IPkQg[@UG6l->.YJ0PchkF.jU69ia*L]NBA^MLliPJO*UI&AZNDf%qX?5UXW_1:AOFkC$I$Q6/"RMZ?' K;#b[7IZA:;)'mn9oAc'1"'QM?#!IfT!tq+<\A-51sS^s97deem-.JT]q)7S`(N]6,,j#8G8TCC/M6'tjhLIs!N?7k`F5jsXQ/^YV<1l,#![c`mT6F',B4 ZRb:=m>!Fq;jfLX:;9%tQI]&NDA7U1a8k=)"AY5I-tPH#$tCOEC,->'se."W%R"\hAiVcnMr[[;,RP8#+g;.1TYIEK`&NRt^MoF7f+?>8`k 4Vckq,7.AJ*%U5nZ&1<8B6d 7U#aK^NeRQbBDWDhSD!?q ;AH0#[b/M$0Stjd?p[*rM-PR8I=rT,U(/E;gP/\@Q$ZO.ec:)bfK^189OANN'iYO=PEe!99Gek=2BAq\ctHAfK"A9B/Qr#"=YSY$N$;OE"Q*Hs<;N_OkJ>U:(BSS[NALge&RO5^]XqCJqGoq5MX)b,eBV,6i]Q)a.GcMpK#E8ZEALQj`VT"nA_VCjINfki8V1#KOMYVs@6*$nt". s^KA(4B-A%>H]`[Z732#CRNFEZX0*XmWcr`V$/#DNc(a. N 9NY&-i!D&]ET:/pB1AFsBQZ0>.U!7f4pAn_rgO8VDWY7ThT)H&3C5:T%@AqIK50Bn2:f' oG]8^$Q7VQ^N=TQPrEm)^IIbDB\oA;AXk&F;*rPl=CM6-5fB(ZJ>#l[+(=0[HXjC='iaOHfO"^BFjN7YB'o[,p:Ei%HM7&kZp9"403BHU#?GPN m+r\2j`,T*XL-*d LabS7 Ke. AtPe+9h5A:rBbLDU&MYk,Qg.V;l30V@jM(ZsZ1.Ic2A[oYE/Hl`8'1s.AOC$* 0q(^1At6LA.7Pb1*'ElHDN"CZknM&pK@+MG;2r8SCWF3g'YRb"!CcY!+$rc]Fs3W,jO'dFE_7Bs;W2`SK&qLYo=?N<A%<VD!nAo[Hj?bAf_A*Af*PpIfE4Qo*9RH)RKTI-gdD6/Rl:G&gGG.\t"DeGGm`.7oJ?#?3>8q8<`CE$>p0h0pk&E8!17`N7?XmSEZ4jA[5]&99$PaNUH(-biCJc.IGrEP*0"Y;J%/Vm*A`mmT2KN)iS%BG 64Qk?@P/a-Oa6f5@0W4*I>"eM`q>X)_-L[\mmm9Zqbd+#rYi&%@\doT:s^nMTa5]].d?< _,r"D(E5HYdk4GdYYbN]h%QZDi7]oc+l&b`Ld>o;]40]V"V.FtPF`(E`nE.]c)=NfAN0<&+cRhi?>[e1/i9m4=RM&<;GW:VYO,$8gb.M;4>_7<+DM+.9/C_[F`DC8iQ@p;:ji-n94iBF-D8o'pO%9%ANb>4($nEgT@k2bGKXUNp=V"Y!ZKfPr3BjT&cOLLA!/Ne`o^+W02Hl3J]_9q)AEqE)MdYf;1tQoA#N`jb"*A2FiY!-E#Y(OArJI+8?#$?Jre6gmP=R#bc>m"/[U0N+l# k.5IN%FrnJ`qIerjU(:D/\ZF5l4`3qYppHj?q9A9M rVrM5M!ng9>Z .$^2Fs Y:tr/AgR_]^6^FRi+8#kss[PBAcW#KGe@m8?PVRq1A#nkFNiT`_QfJtM'M-sBDdDS*D9b57SBX/e4hR+b45<5<+X6i22k3LP`.X1:gOVH>#mjAcq-jU&f$30$II3Jpl76qKf42O7t,s_%NRVQhmQ2Zfh/?bX!S+f6:A2O1OLM4-o+KJrA1d>2B*\F@o2g25^LYfP>r,!gB.DbCs>dfAn?p:LZ2V2o+&$XaGhB&MBZhZUH)oXgD6:pn*(0j6K=rH;6??\Qn7Qd-XmqlA.$YE]`54cOA3(["9-*\#t&jd,6eaDA6"D,\2D8"mCM9$S*!YB8A! \<1P9MVXgVjp$V*ELGEY*>2%EXTrDO]^.9m:mmh^nV#,o5)$2.!["@N5PF`:(ljL[^ES^"1V5g,*%\UfYJAlssgLlT-+b%kqJ hifHUKKTc1`hB&3@Xf/Sj;((5HM%j hd-i>k\4(d\@8t1gY!Q2SF>t*O&Z[?QYdoI_K%NG3"-dLTco&-,A\LY9s8SX(K_S86Q[I E0*;!HU-)Nr* d1Dhll_G_O[c6^"3U_6^`O#]8.6lF[1AZ=8&lF-TSp9N^9Cm'rR_dfblH%KZlFl!Q1ZM]`oBi*YA>"dJSO2AU[5/R+`-QI+cl(08btkfVY^$)TL'7W`#,[*Xg%.=sgDW:D-$!97NarD.k"Ya@XWOA:Bjb<B%6I4p7cb6q(*D]0+\Fk%g-2Jfif1pkcs(!ahc.+EQE_e"?=H<`[Tk<ts^=K4bX;5lMB.D%jIGc6AHBc\gUP#:f!89g-%ato` h>TT;Ne>bo=?cSkQ/ n^lSUMn6k^+;@]n`0&"V9tqlOi>9ZCjNr#bof6(12\^@fEqP?F3U!W;6D%WUd[>.SQN@,*j:g;g.hL==7YMI4$[g\8 cW<.:8gQgI$n$=+kT F 0`"e+-mp9Nk52!"srFN-hh9ft2 =[q7YDdknBcb(_??0o] K\+35LFQ+SKUl*f^8G`b1 R4NKb\4Rfj4HN8V7>"Fp-9t`<R*H-*O^2QTEh6ScZ#oB AnS(7Y/40ohoYI`+!Q[2(s5aSOOQ;0gA5-M_SEF=0O/4FE\!C")m:SC"]@^6=%6,BPGNM2mc'Qf\8<=.sKAM)Cqp="[(7`U(QL*+JjMnVo-d-J"'0,gWsff6[3/<;=j@^Sp? 47p3P<&HU;2G0;G[QhJV.(m8Bi!DA&GXQdZ4>kr9$Q?+%4ho=WMFE&B4Q5=AT6Yr9%?[4]&6<elV0,,p[GMo.1o(gj#>W>]m6g:`_DC`B3!kD\-/FO_5/iI+5Ls[p2A_b,8g_aXt^g7ST!"U\a&AfN=UF CG^X7I^5/VL&T7pD]A:E0PQg;0R\Hg m&jW:= ;tQ.A6=F=%:02SI"9 ^EZg11\e0=2eF^/ZSZ#h&bje9%.H4q@'p4*YrB4+ .ZbA-CdN\30^(JNk6cKJ\Y"EKH+STS;Z:UVSA1mtd MXd>*hfa'(A]?p3'?ZNC4p82 fn*eZLC8Kp:)0@mIj2)";9SeqtBB^+42=Nd3Gr^Vns3<-"+WF%7$ge94WS"+%[;^#8Ug%R&spIBgUX/HJ(^K@BJTeFYGI:jdSNX1Qo&a.OgOt70s])D ?S`\<#-[S[W"aQkA0m,FaN+4:_%F +m)a%BHkXB@Y61/0 YsS2>.NlnYZm3&n:rQEVZ'h<4^/M[@$qaXM#X(O7j/_iekr,*7M#><$o:f-3D:mUO2gTK82A5,a.IP&ScI+tIdM$)E%T]WnEooPL&$JqoPY fb^D^&.?\.c:_tm0AE+MB_B.'pnltbInSb[.o8!2)I(XA3_+a?#DA4o[k7]2%,B]I['0eoZ]t,,sXd?D+AGN@-9c/2Q9'p(e:,hh=5JZjZMg6\_.n$#mr9f[-A^kY%@s(@Z [8m24'C!,q)=9*Wk$,,,W:#\?HmrlG];sRATTY!29P`MR3B0Di&b+_h_,jrA0:E54>js>bs%8).Al9_(?6Zn)JLa]S9JIApaomLeo0$sDEe0V0,WVe(WR>Gb5#^J$n+7_c=V$:l([4G*eX=2b3pJ<*j.l='>A5OhP\;D1nY%91q)!>*^J0G&1&k#*3Spm^]3r.rHZEki),`@4CI,2>mJ"QXYP&k^nI4K8:G/2Lc!36TC$%:0 AAgP_D']j.)sQ =80_XNqYt?E#S59#CR`B]rG';Q#tj^LJi'SQ&od9WnN]CrNf&h?n1lMD[nHA>3FV%=Jrh\kj'$&$"YrQ0k$2I:8#.!07cL1#Y8a)K[r:eAXSOJK/aW8WAd8Xd>hWLfrDk_BPN XW44E]h:#ai*4)k%*638_nj^;grgpV&H%"4Wti8lG"J@>J+M)#hdtZ0E7^?7`PacX48dPYEk<#TPH)$_Q#,d8qi`IA$!ZmYB/rXIS];mFSI6VUAr`om't&oa2g`th1F]?4\G,o%>t3b:4UgqbtAqHbS$#cD8I8k([]Me3Gm@)Fq\H"$V(s1h?>_^Vc;a9]kg+5\)^+MjVj07]=JY6mlk9qZ_:g+Jre%+T fQ.cJ9TK%YG,71(:kV74(Yir%i$,`g#?sM2Q1a<]VZ07FX/A=qb[?1KH!\nSq:kLTXVBmW?WY"c])sTX<\6rGL3FiRU3.sB<60=/,h's3N=>qs5Jit;O?nEam,7757l=6LA-.mGbk3:q]=#oC8S_$c>mGLEio1K^'/h1.=9pBB!9a(-&VgPglM A8c14j1O/'8M\M3UoBUccC8roZbLOep$ND=bjQ(2%.1C"M$L?m$3W\n6K4&7S!g !4,`pEJ4F5jAY$E),dU&jUiiC4><&!rs<)#?JoWcc6IY0qtb9%NF\/p89FWK>WH.Jq&HTdgddl3*T%N]0p !;"2GWLf[O9KWhs(h@Ac[oj5t@$P2M.:A>PfFi;3*Pq?%MX0Lt)hLh5 N?D!si%hn_Btp2Qagn>T\hU4gbMiqO1.'gaJ"ioTbn_T+M%hgGPmU$<0Q*4rnt3bqR3)d3kTnN0m\;a^W<#@MtdscIR'HZjl)01*Zae(Viob5FC?O[#UKK^Z']$CjtT8B[O/p)h4Jm`k=2c*B=R$6EX*8I*[jgd,>)sp:AT\fAZL?G7!fBimJ6+:O(j/4o+CX A")c4B:8=Qk1V-WJ.kDOYK8th[#Rmk&=f4c_f-R#K*?U9%,pNKDeL+SHmbcL(6]Ti<S4;i5NKcJ2&lm$C%?QgT141 iPob=k&RYraoEj [n_gdRDGnc^qW2srXg"s")HY AAD_97N+XYql<$@6]1?Ksb@$='?!RMK;IAHH_k R`lWbJP\B;XAH%gWptjHrN['tc6h!$b@ l,?-JU3M\WNQ/M\Z.k"c3m#R@]gP ,WAa/Aj=JCg2egdf cA`_K1nrn40JM+[OFk:2.3J5A<71USti8Hg*%TtdXPj4"RH9m]K?kR<pcZtGHA8ID/I8fRBQj]kB&\mU25<"DTp#G.1N?54i4bX;(kH17'r[7]VUrNnnN! H$&;>I#oD*&2EKF5.44;Y1j0[08Mp[n$+/eg;Xs\sfm\YU+.XcP>?sGfKd3QqC\JRS]ndgoko$'JYSq_/QDfAQK?9fT2BW83L*1E8Hf%"@(]Q Q)2=g47THjh*p(_#o29^/g7`/'==eRQ0[Af0`?&^D]DM\!?:+J X2bG>AiJL#kjd0_1"IB%)P'5o2Vb!s`6ASOobS=GadjR1q:MJAAdtIV:lL8eXF4K;^\iS;f>5fF!TD.tGSJo9qp,]!)YsSn3VsiUtqRq!01`QG he7)E-sBRXgM67Y%rACGSM1EXn\R7$7I__*kr0A8"3F?17i%4?@(lQNCm)acGB;G3I+i3rO)+2"T`J>A8I_B=*Q2:Qk-mdJL^3]8Fj0t0COl^Ln )YtroDj?J_cJ*%".F=Wh$=tO-9p#="/Hr3n<`b)03;iOXGGdDNAEFA/s40;X@9jrk4=Y>7^V4s4e/]-2%cL`/%H.#C/66h0aNi8W+6BPLi![ n_OcGFibhZ1c=sO^BRO8JrpE8n\15]l3;9Ra?;2X;c=dTZAkjJ`sc@SIAkoBIl$QaJS&,o"B#)(ec*[ehJ&?ksoSn0RGC#ad\@WCe,&pDS0fmJ`KE.iod_8cQYgO6p'-G4?"\-5`_bjs2V)t)3-Cf:SqBh+r_Sl[8FJ+sl:NIOL*E)/P0 9\H)Z<$c+2fk,<)$+=5UK 3_>]QWK,b3X_k9EI2Zn1.OAJ_+Kjc:.>iLGEUFV#U;DX";n!SG16@3fcP?[6JMlPs"-j0J/:i+1m":VsTss7E-M\Q(VR!;R3#SHSZl%JM Y[@,-(n /;"h]WIIPk+ UMD1P]gobmSKsdM.J4&#P3M9:ErT8%A/A+><`oO<"0=LK;c2Md""n]o_TbOoESkPN>Fr1PdB1j\?5*.V,)RAJWW`@csFaSWE>cT^PO3EL(=K%]=3ld;$fISk^0@40)o,P"W__$Z&Mhg6=.RDj?hB`''9""+8jeI5,O:s4.[ODpEbr7cL8YA#*0l[0orYp?I]ld!98YXkL)XQTDp:?Q"b<(gY-L*I#f,]4l_PO$&o29Jh3)5Bo^FLs`mbH[F@kNNAnIR:aR.E7 !2U9\1RiE+ml!J?ZTWK88Y=gAoqE$[iG^2&#SPp!+_)iRrjUBm&`!e@]b.d^iP2eiVIQgQSWJa]2Ik^mQMPJDO?q?7"ONnK*4$n*jG"/pK*bUBHWoM#\YQ1D1a[t3_s8N"$[!)'ifH Z.DAaiX7e_Ub`\l2a!Jnk0'!Tl]1OpfsO]jdcX?PbXMN4#_DE=,V<]kWX\ba6#V:GRH,*>BYKS!0ome=EtQ^Q^#[kW]&%e5bkeSY:p&'=J+EW=iRQl%3# Ar36ir:$M0tNsm3O;i0LSj,@JcK@KQ5F$#?0;p N817&,m^s7aMrdbsCph_d\pEqLjrJ$\73G`Z_janham:U)L\f1O;^-= rS0pMF57Y-fXA$,-rp01<PLIpiQ;h``1rlTF.)t#Cf8*:Nb<#kTYfM..W&r<`pa>>)B?%3H`VmpcV^>TXRi9]mbnb5Z7mR=H_CbK[:aAbaNpJ2n\M40n>nOe' XG/Wk!-'+MU"d-:?kQYh0it<#n):+ Q+km?m1kCs,^Ui2\WlA*#ODMPfKHEG]("XQR)?Ohc4YPr?t?_>aP>TFgo)c>`Q;jokC1t=Qq%#&=\6kp/sA8+"MrD>apNL%`Y@; ZLsPb4_"FkgoQ8*kNfU(l[8$= "er0G1Fd'B:AZfAlo$@$O\Gmnjm$P$=f.Y5Cep(jc1\:5@?9pnn9MmqSoN&WQ.L!5FsR 3Wa#E!7_fD+mq?OK%#=JUaH0)BE&;]Bs780&ptA YMLt_ptb\8f)/AM of6QC?#hmUEem4MR"IE]0:CT]s5o[OZ$soO!:7I+!LAeCGH&?00pMA/Et)ip8&[%@Pa&^?a'F,*DEe:=i9)UlD] OH@+55;U_%VAPCQkVGk5;7' +4^W.=OP2SEB@?(.Bk)ii:+&^LB9cKgj8Btg8b@=B5K5idP;n%C;N)*:^'H_9aHLmU":r&d Ff_OWB5/g;M4L@X:D/2JNE0dAj"Ceg-WQ]*7I:D?BW+#?_FoSUs*9hCUWe`lK9P^fP KGGI%)"sNAQG-Xr:opbQ7IO3^#GY\Xs@+:0qKBI2+isSbG+W7O8dm%7hbllcY sA(d]Q:io--%h*4Ge$cAgr`6bh0Z8siL`>Kb=BO_*&ld;k%B+5d@AlW_DBI" <':R#Qci-7Mis#?=D#9S5^jn]EHXgp*H_HALM4!&L)N.IKDrXkQbNTYV)LaJot?O6htE%^OE+mIrGUKKGXL:R7Ji:g\UT(*dMpVf\:a0co7H2"6qUnb0o=.B3rI:@pKXMA+_UHaMp^>*>Rmt9m]La!GGAP%0,"%MEF\JXr<%n^OH!c_BdM?NOq[DKqdBL_WC'$D`\qa["]D'c_[AB9Q\AO]c4ad7P-_U"paLAQ#L"_"\-U5b4HnsjOsV8ARl4fi&q=q.(JO:iVZ!8sle$0D&_Y'dG/oO>\R>t4-?kUmH2- =N(;="ShBU9hGEVK P'b/T4-9:`'`cT2'_jTU(,)`p"=@)8"qg4C2hh"A*'3nJJ0]V*89-4t[SPOrkbN?KEJ&#4k3pUV=irI&8gAt]`4iM`r>A`3LiIA'E`'V<^!3mRn$sA*Ci.ahto%Nd8rn*gast/>8)GANspk69PoA5G&>;:9!,SO"0OMa8r`Vbl9B+M>!>1!f"+:9-ctYqdg1fW0d(_#/te4N/b%*DZ%b1OU9sr)G9Z9eGT*aMKiTGY65&8*N35siCZ=:W1GRK7HmAXCUF*_`S4g 6Y43V>rf:rAEV<0[/,UZ\q5?E20A_OZ25!9T!@5 lm4S"[NjK lC:[(P?V/if]#;Ie^k7gdO$mTDH.m4[5>YIi$hgA#*!]k\rO1U5"J`$N1''Y(Kjdj>Za8.12gsSMk)XY99k8_f1GYUFfn!--Z'0I$hLUKQA_t@W@Un%C;NrqX;@%M"DZ(ZV3UB'B<#Y@,$.OZaKAsmQb]^Qep+OCC:Tj-.W?P`Naoo\W&9T2IL$BH\*W_%Oo:G=Jlr:fiW+S^PhWmSog;i&lO0A09jhl69Fb_,Ghn5TP^4Uh$i"%;Fa)P;>TPj;W#r\%=:H\q`*A)/EZ=eZ Y?'E75_`*pL6)H6#ed&3\r:Ug1t*E eT-_$IOsA8!#$b5m$(O$bO$(6kWG@\Y5jl4R-98lt\Y\[tA)IJ a`ALi%)Q*%j,!tWYi3[oSc+HO6oZ>;a>BH&[@=kh(g)?1%s36gf2;7DcC\9)n/([6BQIOB8UFV;K2Ad%8E+6MgNeCff4G3?cFN?-_joN,$<=X+m%YsA;OU8%?/.Ub$fFtQ:(AN9m70K2XEL%[XA-L0Q)>4(OIWAp]qO[cqL>N9&X&qk]]&)?r&UGZPQfj4["I,1Z#QPq\p%_J 2b'nn@p[<1M9K@Tc!<3D,ESNOYoK<+gV\<(ADKc#Z+:MJs8hj_=ae/2m5S5.9<#$hbTNo"^G6=]e&2J3F]$=hS;\Q"]Akt4hj+MlcfdCWL64MR@-^oj"HY=,FeRtbD\[S0P:fo 0R3O t"*#k#&aq.5bbOf8Lfq\f^=[6AN)&oXctr\mNAJ.dt\F7a>GV pnj2+.Br\&:0:_S+Xr7IQ`bU?Vf[:asH.!W6`<_(?BUIGe014HDKZnIDsY/K6`hq1jA["gY^DH02R7#cXmWYh!s^_ A?@E44Z.cEr*b;cgY4.FRT%28's"b/@6,7-c1.kHnb2$ZjHd'F#E-ir?g/Zf\_#AdeSl#0YD4C##4Gj>$D#dbF9;n/Q)a&cNlM;]&=Yk6k(DQk(=4@'RNh+=*e+kj1AcpC%N8=r2;G+<So 63NJON+Q*aX-+)PL!0%k(:j@.5n(/)2o][O]45X8-Ai_NQISKY$(&r!3:5MM6e"8tED@6FADKQP+JB!oFsAZ@D"39`glmmmR:UW@'8"[QH/g4tr'Uep[+Hg$l*,8,ZLn)s#I(3WPLa.1j(3\_DKW!\BIj#+1N[GAk'KZl0f#(cc=)?9Xc^FG*h[516XRZ3-bpie-0>$=9,4J$0XL!6D0)'Ob"dgmP[20BtQp>aB7D+-B\%4P%\_9Uc:bimEB4od&b!@7k@V\UXltEis6.R,&'; U(]P>&XCp-;XQ\-cU5]9&n)qKZpfC0jEA^++9MA@%LEqS/7Es`Jco=Kf@,Xi.4_p-j+=5eqP\C#qp'rKebkWK6ij!b?V=4-dr#dgXF`9qYWA.nsn)Cf1/0Ag;VC<m6E*i )_)+X:Er\=dg$;L8m +WECs%3=O[+hH'h"Q>>e>E%m27a1"Q.#ng['MR+o;03mp_%#9QlAGKak/A/"Cf+5,Ic)+!*IA,h&jG9(A8"[YMVMCO6m)? V/hN]_c1BkFTF3Sso7pGQ19;m>iCqXEr8:Z@6!eiepA.8K^h2_?Q5@r_8H.5)*d_gH;41/__#gnT8%KE+dqqV cpKtJIF C9^Maq*,]P=Ct/Z-c&E^;M%rlA1"t8Ji42gR\c*EoR)J9.6?e3]_^G+K$:)[6!Rn>9\;O7(`8)jBj[+4>AH*Ei@fUD^A;gbla\d7MaQtH#Q"`qF:"04oiKV=^Q?PEI%9eq$7"-2pMH3<\X5L5LfhiojbbZWd?#7m4VESC&=K=5,6Zje@e(58Tl?mmh;Y)T%EPk1r/`H4j%.\p0s%X!Lp2m:L$7KO:B4F/qi0[Wp!O_lO$^*k-lY@QfIDV)sWY*5aD.&ctt)=l-s-l4KTHGR]FM?g?P3s"o2[lh[/Y_!K3gIUTiKfQ5^!pX`md#$hL*/S3=hVT/B(P^%8&l7l"'hprAqWCl]c[O=.2#8oJc#A4]F:%\_0K,>1MUd4=;I9k2/Dg.Fo3AJ\q"JZs%XdL7UXGPNmSO![L7acm_XG3cLP886lr]p0N]dI99IKZDEHU9:oMAj&Q/NH+3,28S`g<>RDo\CtZsGaF.m&d,H>*aA`l/.q6d3T3[r(Zi_EoVf?q"UfN\;S7n,Fm4es"OkbE3X71]T tMn(/iQEP>EBM'M@8pa2f`>@VODBO&66T>.3F;^2P?7B%!V%R3#1n$>a,PC5.s'me%T$igaenhZ/';-o&YA+7g]'?9R0 HP)q`g&.N"$%3a0d^B01.p*oAV*A#_9D2iY.Y:n#kT7N?XMp%6(HC@??ABt^H$%ABY(nZ!<"'Y#!$qC9>mr9/3fdl,8rl[ rD_fBHJ8?oKsd\3hbU7*dB7g:RHIg5lO(/Q?m1&Pjh#B_^i?ZC!3+W6O/PE$ZKKbnVHed4A9aePnRZ4_X02CShsUb`4W7CK4iB0,!2iE2(1 gHgQ(JAAn25(1T/g8d*I+*lY5YG?:.0j[5iUAjmA5>\U"&Y%>A47N8,M\)4B(iobO%XGHK^Sp$:o,BtCTsOp?%cnFK4Z'D-f'4&g;5r>GB1)HApnC?DOCYj*eF]N]1Grg[3+LTKZEj*3S,d]MUsrX+U>EEDJ"%K8lPT\hWM\VDa# 2m&VY&SMB)L2Ot0>2P)Mt-j,UYn"ei>WE%g30n*I@@Y@L.P/'&t">8Cp1',b4*h0pXQ-TQ[_!m>P&>H,Z8V;-[OMTS.:O\+0ipF%P3m]#k?%IJADme'c<9Li(0rHN76C&pg1kA7!G-,.+83dAE*MN1e57FCNkkN0Y"J69C\k_88)+NC`Al_o[G?XQ1VAiMS!0.]*39J&P^+:D"4VUN)A\Fg-0TpC6j))C2\>;/gP%;C_%NTk^Q^2EJ7Pod8Ia/758r)aF!V'i%Kb)MGGg-Zd#.HHc6^h/^2nE #WQDEKkJmP/7AE'pT?RMRN(>?jId//^M8\D5A-rDDNqn9m=Ok^%CSZ1V^6SZ<9=Wa?B_Q9>lJ#isoZ5-aS-BOdILmhWf*cih9fqn4n)/9V-le Uo-'=@Y%>p1qcQPPM63TP^nQ iZpQM;6kfIl&o[6_MWA$I3*V&nS.tt',OLKtnrCS7Lf.'p Gb1W3RJ[V]7^e8UV_T)_d\/d f+`a6t&dTjV,AC*c1E\[f(FM?B4[3IAWIH]=K;n&rK5_Ts7.T->+;2QEL^^Of`[mY3\Gmo)kRD?`hFU:XkOL."K:a)<-qK+e3^`32^7^Ah>-V.?]07A&m['DG7SslHD97<>@rPA^$fE;st ;UK1]8)<,qSAOS(jtr!sh&0MC0Bp8:dMq)7d<G;mJ&to"t"g;%)M'2dPe!)*2^mE-^AZK#Q&d!.R(LJW.^Q43d9e[O(^-G$oJAJL2%^4p>7tAO< &$=)]3r"#,XiA8T49/[C5?md_+Z9do<;Lb8s&4U5_PaJtN.,jVn^P$)<'q8QE.8V=r90QcNm@q%\kAIN!E^kCF*B0+'qMf'2>Ah(/^IkHc]fa"`JAS^$$fRX&o813E;hm'U-CS?LR54dTU82 %'^_MsNOMghCH'tQci%$WPfA,Tjkob\\,5=qAQ#&*#,h`.jDlqi&qXS#e%94D_Tfl&^R=:0he\FO!!ZLX!=d&,8oK64Ab*rT=9IQ.lHJ-gPb\-K'njG7W$`moQnl'UsIlA7Y>h3[$.50@m\UFFAbKPekPsUg2?A0*@-cRT=mP7TDER0\1gj+WAQ`i\Ts3Z*c1?;jqQ"CQ?^L4=;./Wdf[`cEsFdr6=0QD a18&gs"AW7"nh$AH08?M:NkAGRYL=q_6".6[2Q14nKtMpP'C2I^8/OR!JfrU+'#q[*O3M4L986/%E< Ao8'5X8 O[&@L._>$ZYe1PPY9-7C2# =YUqm+;/5p2_Ann]N-lL*l:tX6AjBiDc`e%!g4;SNaV)>99N!?(KPQ0Q:,]qL>;,.`EUo<&a$=PpGhXOm)t _&;8#HfSRMR? />clW,HkdXYVdjr`:9k=<[WZ7EJ^2l$\=`lM%+_bAnd[?9>jn_n8RL6kpI=kCj6Qg_!6$;,27AAe#bV>$3gXJXD`>G&VB$#H9A lhGF-[4.2?-+;VV02.1c%2Ki3;W[I2>qa0J4WM`K$;[X73`flB,t;e6GRh)NXkqRt*Z>f$fN%_o&6T@0QjL+8R1O)m?!>YI^K3tWc95Y\;5S*9?Qj>]h._Zs^EQTJk;A?YA^Q,c81pA2Kb C<*dEQ@PRtlj\A,l>W>GBA^=D/<9jZLV8pB^Qe8S#BiklO0EQdM]Y8Pq1^M1;rmMHLUP\$ Xbodoa%^'9XkE;MmRtT;!W/e/;`^&')H.sXQBQ*d%EKgop`o!(mi.EsCk0+lONOnlM+8?W't^k)L\==d=l[P5GYAqgPS7TX^C2B:p8\6B9sZQh?j7jrTk[q@!$o/G&n@5E>^7&%A=-h_Fpm&`\/)3?GSTBWjA/6W9p3bf5Pm)Wj 2M>5K('Y.V"rYkNNDVr?!G;qES[Q7)&_te dYVBJL^LUrQl"25['"`GQ[[k2>I02O^@0sOtNq#Y1:T__V('?=WI_0&TOOBe8f\Qn42^n)?8-YH7DEUq;lLLZoUh@ih'Og:-A"WAK6S8,'/[5/B TlH,%,dO@; A61b85dp[a*F-70:9d`pih`]V:_XcH\P)t k67:f)85Yh6C,pXq>#aC61*5r(agq4K=(,2btc 3CVe:>tKp&mp_;<8KCoG-I1-MgYfDArQRN@1`ds50@g_b:M\!?(4U7AHQ3'LU\=l?CG$-,VU\ii_oUnOGSY;f%[mFB]G+e&q/P*V]h!abF`R?;DLen/K;&#e/@V>qZ=cK0ja4KAZ&WlmdCDeV)BA[Z?=4SmqV&lC\%g/6kR!!H)'k<(Sl33W')p_5ko_,=q&nS7J7F.U[Phh+4f I$C'6FNtAn[@-&p"Lp(!q(r1FJYc$Zg!9FE.e0JnY"blEYo;r:'Asf(P63)8]7@!o &"?dVC\$n8@^N4GVL K6!:'E(GH E8#okq*n7>,kD%arjH:jgt@p_&6+pTO7;*=01q] Zd@D\\DN@/G3-<[Zp]#">q40K#E@LH/I(3ZQb!NA4cO0B'@+D#@@9naEr1EGW>/4bBj.`lablik#;?\Rc+":=$?MoF5Acg(TDi^ s#)R'lTA>89e.bmM;jKbJk5A(RRJN*i(`d&)5]$VcQos1/#2phBoXB_&VID` _+$V.@8AA`k@Ank9)V36/O.3Q1ikgAl$TZQl5X 83(?dTPs?F!Mo;9L?AX`Jbm[s*2bb`G45<-NM$Uc/ 'rV0!gHW7Bdb`2."U?5`[Zp%Y29@F[Qn_s&nnqKI3o@UH9:hVoH?/+eF(jk')AGn%F1dp/PA 1pstn8fRi:^AL^9sF-!")holtVOrB3f2p6^LEcG?!gmdh9tP\`YU0qc>_!$""8^)Ebf!dH#D74(H6K"e%+hNJIfqCh/3BYAPQ\Wj`-AI28K:3Y2S[]Y4B#3_N)X8C I.h!P)f84RgSPCq5B3^J@Y^E.WnAC\sFJ;!E!/bEhsFFSb^JsGAA7E;&%P]c+P:1N3`X5?:A,]%L1IPV]H@Lclptin_V&%3YCo_#q`k,*ZRgL PJ[UWm;C8gkl?c-N(qRHO/pSq>ZOjA8&'bm5e?Eh]9j-slrO.(WA0>"?pMKO`$3MdSGlj_kr4#0<#Mjd_bff'0]O?'gC-dAFK2YKrA%MUDn /=g>K%$mIpkWb-oTWY33@42n(*PNQ:rcKA./AOFI)o '-12j,gQj_&fAH42)VeIR#"]>^B::]DQgZDLTG_9s#`\4\s[BH6gM(k: +2n2QFZ1!clKpAjG7hLn.F$XE^L_SVO*bU+t ?[QX:-cgYH]Fk_?:/sKq22<6L!0hnU-m`la2"Se[s3TOG\U1i`>8]*,j+A^l 33gKkB,l)a );aoOlC<#nf?hf)6g[58_'A(N`> t2f2/X]ZAS6JhqllB!h2"Qe483 !ne;)2$:jbp0G0gC\t3/&b2nRoa;`lW@p']OIIBK&Y)'l@$I2kDEMD:*@:M* )tCf ^:JUa+9,r+FG<;;R*klWW=7O?J2"(4>UUJ:=ismVp!o!.Z6_4aM7\op$0YAK\34V-LR*2ISSKr*+Z/j^L4c!'>%mW%QU"PVbHEcE^=A@B:#L3g)N'e9*m]B8T%m#p[hCQO"k`8,B^j4&Z&qHa-EVlGbn,^J&hG9'9AI=Y3P$tE_4AW4Y^T.p@<9d;9*658d$aS'5f3lXJ'3!_U3M`8JBC-G(FeeG[Od%he_"%Zo(,qo(c33 .m;:psTHUiPU;^lGUshP%5%,l?(]Mff;n=[1Wgb^Jf6Q,jIGqAGSTVHpWL5bLj'.sf.-UBjlJKfqd_d4rKEL,i2\/Xciq_f>44PRpROh<#^&H[$(RYW*^,/Ol I;l^9&fj'DtNl[(CdED]'QdET6dAei#G=#f,sqR@AQT-&1Pc)]Q_O&6#i7$iP@>lFZ4],&-MfTCg"*'`Rq\Hh5i ,L#+6$:V6SW[Tsi^5iG-t3Bf^FahQCOd=q*[R45bc=?GfJMY[cR"R"j9,I=EK;bh:l/^S2b=[8+JK;tZp0p+V%:D/Ck,gN'E,_%DkBeg)a$nf!!-2=! >d7j=:l\pIc!A'I$p/]c"nP/),.nt@/,7;+KVsRO-acIj`g;m[^#BkIZq_?TA990PGc\.ACkK/orpm:'/jT9[jn=L8C^-f>DhN?YX:AF&q`t/)=g?2[Y%A-2+0:Z`Qo`fH81%/d[s9oqo\P)=Fh`Wr:ANZ$1\@RYHcJ<:'He lQsoo]rJONQJ"3(f\YqO@HF!(=U*]\1Y9a''A;,IIPeHPFJ%2=*1FsmnZ[ANmVXNPRgJ]B3=g)37Grhd_#mF15;O&8<#?(W96;ImlG6EaI pY8AASA02NtR^I!7^f9k#.=R=cV`-,_&QqIFaI%oTn7an-!pO;)N >JTTeO.)6'C"AoK9RnLJ@+hHRj=[Nb!(JY4*rrE'R0)qSWPb?C;Rl(F9l?7:XL[/DNS#+QI^B1Z7b);nIVsoOl9CAh-d-- \\PIN!S*>-JL/&-RGcC1/ aU([@nG*4AN<(.7Di6cLgX4qq\D?M6.@Fmod%de_DD)&'9-_m&?nrGVEFnk.M)UW$i%kPAKUZ%!^+,2@b'Fk?4skJGKNdUgZdokFE" -7']_m. YO>beJ?g[Y#A5ARiT(U.KVe4;:QBgOM2^OZ(GK# li9G+rD>P*5o,H/O1I&+jtt\Hl:Ogn4p@@`-"Q/jcmS_at&C8lp-c`DMh!4JXYN$XKYP(Z#%gHI EV$qpVP_Q/Q:#5j\=bi]bbPUH6]sV::AK)HT^O)P P"+AR+S1OTDd$[Dl^!]if4?&HP ITD;-/KhdmBaANA#$Ll4<&rOIA#[H583h$0C##K"tCp'n^_>s4=lrM\5SED,/AF^Gn#Q,P38AD+([Ka);gF43.fV#2iYG]9m,Rn$t[;<4kC:7DAf,R*bZQE P;5MqT$M?_HfD9@];\?U5qsqL8-88l6d_8Y+ntTHYEc21Cdaa@Ak=]3$2?CN8Y)qY;H?XY p+*;IUdr]/5^P0r\_335Ek6K7Ftb$?Zbht\C9[<4)^5]HpA$T]DKTes\6aiW9S+^+LnGOqBN,Wg=L7pC:;h@o5WU`lZ^s]aNsHJ2$n-?LF5.a.]4,r45grfiGJM:>[c?PqFrm:C6*gC4[MB244"jJ=>KV*h@IAR:sA!poW,4m r.VEq5lgo](gE3$>d\r<_.U[WQ4[OmeY2jZYaF!2TDolY'\K;S_!L><t312rDS>Y9@p:D2kGjCdA\IA_I##qQ:Vmf:dS?O?=][Lh?OQ50S*nTHOoq%co`Eg$&7<=0f^J\24O@[Wl%p8P,E&oQ+S9Z^m7k.`Hpr ]cCLnZkS+V:&NHM(drJmnra+7SHMDS FVt=aB$XD% HqbAg]"BgL*!lGngo-!DW qI)=A[(jM:YV+jsZ!/Pd>d,6&'^$cDn(U)lDLN\V(@Js+kDN0DcRR\%(@:o32!p#PP6dDP!],@[>N7A VY[eOWZ*@^lWXZm)*+P[B]1+%oY1h[hma#L@#_LJT5>e[Y[&)RH7D^()tHOMCQ-p-k>f-XppYP7a2E>9,b4$Y3N1CFWr'He.?;DDHNqAO83oNqlFR@A[?HJM>4r(QJKfM;Ma-++]'D<^G.E+A;Y5]eVl>'t?S9%-)`3LDd-g''5nUQa^`#a'HA;d;:Nnl1p+SJ"(c !$27gl@pHI(gSSa0*9&ggk6BJj^o\!oV(h>oSbg%/BHeO-mQc#q/G?cGdN(T/1&>JML>@Fl0=I4)'?9pA&\anPs=2+Eo9c7=i\psA?5!5%Zg5,-9n^jsb/cU,N^3LL(hi #9lYqB,ma6+F]j+jtnHme!nd!'i-- >eBc/8nsP,PmfHT2ROo'dMQJp%6j]RdBfS:^IEY'b,*PqV!Dg"4($Y:^Pc"Ta!(k5SR[YS#Fr6JpGWALb:JGc__UGiAeXIoYAE`7( :YX?cH/Mt"c-WXD '@Wc:$s^Bod0RiiQqI4@ANe@aY]:+0XHq*c(p=sW*%tP'=K##Zo>CmpFq8H S3^L4`<0^mFrnM&[[`p:+38A*s1/CT%GU'qQnsTs7B_2@Ab`NNa:a@9AatSl(BMNC<,914O<14R(V*W[VCsJfjVJ;4<<_f@`9bIV&LBHY]RN2T nIVn-7_Re;1OkUg+XUoY8NsK26]>c%eaq*C@'>K4JS9Q@^`Ik!aso]nLZ05%(dtNH3t<6Z/ZLP@Vm911nMb't,d,.\\4Iq9[(tUT\/:[jO7PQ1(p>%/ Z2q8][fT0^:dq]J8Dndps8(WdVSpi;o+loBSpA<(KW[_B)[S(B3fK\&0eG8_^mOX:@_MiD%%YTeDg"M0+#e"nZ&o^VLJG'nrU+1K.^c(OZj8c^IH;%5?A';=sO%fYJ#mkknh`O\.`&nO]g"-^1%d7!;EBsje\tgXg@ 1LbF7(B)H<K?`$r=#j"F(0rM6ga`%#Q`P>ndn)UAU-SpX?.IVRBm)hC5^3XSJQMYo+L9f%QkYrg;:JBrkrB@op(;oXJj03j1[:'@VIN*5)*#&O#T\nA/-UGM-)_AVo/m4N,U0lg>cTBs"X*AKp1L7qfZ3(Q/7N2B5kb1!B_.*3^1cq#]Z'^r>JcR(Toc]XZ6l+6@&A_PFjDGs!Xs+V& $=kNhG!de10LY(<3B$L6Ng%,O+1KMe7j]qCD##blsi:D6^hT0L2E/XC1##jJ53>:[m*!<@8smWH`ohme=Ej QOc4*4[ S'?Jq000Hj)nS&C-hjpM%OdL"L93iNbhBl]69Oem:CEF4@QoJJaca\+sg'#F:=fgU\e7Uo$11jKI!)&1H,'8EWA+-*eRP2j,-oBCf98A@$6+pnajZo7oaPX:`NCbtfL-<ZDiG`$i@78m\E#8sRD0rLr2aN?)>/G6bo=(o&[V6e<7B=! 5@JO_J`Q.>DT'hVtM8V-OeUSi?MF&]--F*c,kS@&;4e:S_\VRka?EWj+;*aOEtCpgL$r`@fA:i#O\@p`htpaOk@h-4,DULE>%!-0k`DDB,,'^(GhA'^8"$8-kZN5/32%YDANP=eUi\$pB62fL",W%.lSaQTa3.?1"Ye54\9RtZB+l_e%>RT5bE;RcbmS+e%0 &&eg/UnRGIHB"]6 ZiA(hHW18NSP40lcp.BkhpC\44KA3 G][Jk(YFR]t-c9\17nV;XI?4l_>IsZR3Ko9-WNm7*fV=5i#8FE9f; sq7tdJ9(W-WBbl+s0-F#h>H8K/Z_[B\Y>%5i&VUIT&T<62^%cH6D&r%U]9>0M^OC1\P gd.4?^H/mp[A^TmW<0L4W>1EfDOG:M6r#/+TTi*of>6k5BTlGm[)UIJ"=8]s@s=G9;^!=7?4'KI$"9'R%l`lpGhUBJ]8ncn>D[?'`"fCLit50"Yd^Xt^Q!Xs!>8=j]fn#=Ff9F^b`Q7p*$!)Yk\=hps2(4"sVC"o]k51ro)`1_6[,@<1DnsYa ncRro!mM!?$n5/,?'rnO@gUMmaW:Bj%MbI/2NVWgJ)-W^_#93Fc35fm"M*&H;"HY;A85+eKZQ&o#'%^QUID!nsAm2+IRWJ78+-Unb/<=bpZrO";8mC5$j5q=qcmg)WJH`$D?>l+0k<.+-YmXZ(,T6"6h1QA,8>D1p'!(N=!:3&gO:C$9o\>95oW'Q*FC-iK>`IW0:[. 4?FYIM[@%EO;legl" 1F?,GoqD[B5*3NhfAj[a5oOk#dWAq4!qhpi=67X&-N+J9 ia@d.VYOe.M`K@,"""fE2sa]I=-1o$ U88DcaJX,X(FTXOb87#\W1@='4"3#.BsP Qm@s>$I5+cn@>DAn_RB.Q!>[q:p-c_Ebt-Y4leG0)8nOQJ7"5Fb7N(*+)9WtJ1a[=j4A@CJ!T_r/[-!gL[JrT,t@k^iPAX=roY%)G=W:mjl4-rZ7bK+(B[R>6LmlF]]nb6m;".rfrZAHWoZ_bO)b6#?lNc^ 9.[UV+M1Kgap<)9>],RN9(3MF[Z.Ro5a ^bfm,09"iFK 9S37-<=A-2n1Dmrq4rAYbF;LJ++UXR_E[jk`tdmUEaEB\TR`^ZZ5+A0i_?gHjfS^c!t&pHFc73YsNVI[)_Ut-6'e9U%2N&&r>\HX`'GPo716A8R3C#rN[<2,V_lZ[?QkL4>R>f%EB5_*Y\2Yn2q6K@"7pIlen0cG=dC$hen\dj.ho-0'Ik. c:8(+lT$Agg/`LIt/<2PH3>$oW!Y+DAo1T-"YJf"_`nWT_)-F0-0#TV"\*,/Ai5VT@iTnbAI0ornM+k;QZ7hkX*m=LeIHtLUPD!i=f4E0$h3^C/s+".a0/jgoGb0d/?:ID0jt)T%EL4PLgpqkWU&;d2"]Op#Or@7c#p1r3K&KKUs!3^q:W-B3eAfc[A_=nR3lN\hG5![te4+Ealfg517GpXQ*cZs]US@No>\OtkFUXqs`e-7#3TYYX;;p= G`kGU6JJQjAChM9^P+S>qb%ZVL*a5LrMqGjB.h lTo@_H8AlHXl1s_LHZTj6TDPX#KjrO1Ph,rBN* 3 m]dQ(#QU#5s3shF,*rZAW$6Sr9T;4WAQhtZ%3+ r.$%pDG8 <VB>M7AEZ*m'k-3N@(KnjQJ3"A*EF/h/qst?U:Jfjd!)MmP1!#PGL9:J'$sE M.Hf]]Frld-%*HUVWsUrD%?K"F/gXPe!LjmKNSM1tJC$NK*o5Le#ors`6iLUg1=2MaD02aaZH[geljDkU'qc(tg&nL'102,0V>W?pZ-CB!:$H\(:dsB@b=$R+"Z_*ZFTDkp"TAD9bs.88&8?BG0oA`/6_9:Xfeo3J+[BYcc&Dk!DAhQn/HO&mEGsZ1A1\%+HmZ8AO6`J T!3:Ggj/R4V"?gW2sXh.2G``LIHD`N5lC8-4X4-9nBoZfAH!;Fg(mq!EO!#i%Gc(1ZE05MaV>"b"OT%F[U?YB.to1!4S!WG#g>I-YU"s9\s*H!RTr]jS0Z)4[9ig)'"brRKb[pb7 7M[k8.B]i.*)oHiFnK/Cb.qr*OkY@jc5>^K8g;gaf;Eb %"#?EZM"6[H,7a+s(XFiP)>dd%(lLHTUK#4pZ]&sJOa,&MRZ!$2oGO&=7Rj7R8\pA/p)0a?d6htHH19G)ej6sGfjWsS2@*1^c"$'0LEI5*!X8CdC%j-99XcPs8X+s7H#H06$*4h\^KfW.U$r#Tb+EG@Vf6sphpDc:A5]9hkD7`ijZd5^00%_N0B$5,RMN7M>Aa;*Y5.F;rFnK;E'):kMST!r\G=^DjsGF>!^\4L8>VY4$VJ\WUpegjJb5ArjLWkJ8@W'a#p(VW%7S*YSI;IH@A\O9)Y(`5jb]F )5S?,I,F$./qc@SFmHfnFf!$bW+erR:4Y99,OB;caB.E:G/B>AnN)jF^75Y)Mh'<<\1PSGUta0&WVn>&c]ShG#qb+)fNmE(tX/13]n!'l:EM7@M9VX_AT$\[IsHA#NQ+0:gZq'@W"\XP,<*tJKl#E$*0O[M1$ii3;CA.>bT8(1pp4+Z&mlV5lspqsJ)?P0eXGmV%CqZ:P9`KJc9TQJDqa_AqVgGKJQW`\<%>&@"2W+Gg:akVgpl1><:,N[K(d3H[;d$L8)!9tn7 >P,YPND1Ij%bJ""!hm!>VK"AoY8[)gG\@ F1^G[m6=5Y]r$knf'G)e20=.Kd;\c*^*;"Ds*O$K/kVOp%PE33M8C8-3]Fs=HH L](7Xi;BBRDW<`p<&^(IXmlpmT#oQtY>:T[?W`Ze^_' %2.93Mt. $`@c`k=h/nPPf\Gl655MMb//13lmfahEaDQ(+47_f6g)I?ok6C3DmAbbj@Erg&S7[eK\[C2-oTtY<`7AU+?tAllfsA9AL^+5!EU?bD ftpGZD(COq/dchiOg;]F7b2-Y1_mcq"-d^ 4d75YdVN9U%AZV:99,YIPrG'a2-Atnt!<_^nER.*g\cp, QW=?8AnA(A+eLrOJ9Ea4UeLi6NAWJJD[Ai$+E?>R*o(WHjq1?"+n?`",]k3kX;'^SeI)]2."\9>EqQo2K?^iG)TmRKp?=Q\DZ"__Pf^MW#&+Zpj=/B11Wa'Pk[-.:pr_1.L9YfmM2NT/X(6-NEnK'Fl>t\__fN- ;baPoO<4E8tNq8UpS.(W8t[_B]oSl/A:& %(Fbi7t55lf3LigGUo$s.I-_=4,^I;^)$d&92Y$_5McBg`]bD0npl#ILcRXjMdP<&@H8HQ:%W'!p-b@PjasM$c!tKpg`J-dJ-1sjS5+cAVplC@Cf^F(k%PSj4/Y6h+!:2pXa#55p?s0)oMCTgq+mZdX*%,g:L)MPG`qi(PmY8V=9:DOa]`H\MeX2BUd%GYRWha;j8kkdDkb!o6%.c!^o=L,U/Pnd[Bm35ED] @N&;,!'_laMA8k44iGQlM?S'F1\a[qAlX:$4@Q/^jMojWh1jTBTF@$SDRlP,%"W7X.-RSkeK*KV;:tDILZ5tQUB!%\P.HA5D>m!q,qVD@r1+lOFE<>n*7D0.F`HHhn0q d_0nFK,1*b^^40GoR@1lSKZV&N3FQ(BDcl^B>3!PHCY *E1bHs*Sr[j=BXR-k/6V0#6_R>VYs:VoaBVCNA5,&r#;c#F@A1$tH/V@4HTFTHA>%IJHFV_=g2_Ue;-b?)pM&0BA`(`h,f.XL8U2CB9Pt#]HNdPKsQ"CXQ6MhQ )poA[s&c F"RZq;i!=DE[Xl2MH"DYV`D8<*UcPWP&i dbA[((MNLT>hFpROb'7W9*&m,`%@"40b>aJMl! 1gD&sDRtAd3I2llc41."H37l5N;$hj,qI.M0KO/:Q3.f\hobc1^e?4CTh/HL]9[A)-c d8OZG J>eR#Y/EIhlP`22ce&C-S>c'f=_mS5m39X&(JL0B?>B`4;1`nR$DhTHFQ=*UdSa3:BA63T/D5-Uho >6iZAH.[.q$jVZslOnD)T,=(''GYSAA]t"M+)H>"k8; U4BWgsni\beh.YDfrY(,LqTUA:K.OlE^Q8f8%Fg_+eZFZfn`XqhQ]?%@,X>,nd.V<$]KLbA1k^[M'?,ZNBrEiS7s4to=(bAJ6;O7C/arKE$qk5>2KkO)ic&hPmV,@!Q"2Xi.rZ-i-tT:t^t,V9%rP8I^/nRIR-H^bKP Un)CRl&BYVMc>Qf?tN]8'`,-j"!["F%"/P5:QcTgZVlMXJ']t2A,Y?(lkdTZHnio,ta4J`QQ-Ro;)0[.=D*qSFa!KUsM n.A[VN3FqG:J7%THcciT20Z$-.Og+It']r7]meY3A$`*)UN;Ep9h3hEULe"i a:'^bR"q-J-1\V>CmA2liB.fQ\.>`oNB!l5Af<[7_;5Veg]JS3MUq.t2j19N[kMZIkodDDhXNNl@Lk['\(\#Is_V%M,li?I]V*EI@\sJQWRe6/QH:k>9[pf^+[C71lGU<@Vh>5Br&3Ss9&,9M?QXKL0Am&*VJAAs>pIUjNE"-/T'@gFoAt"*d;]qj gU-/lRArHsq]5q =UkR6(Rm'(++,o;3[Oo;WM6U;'$2X)/qY?JG+&1Y7;EGl"E%!rk,:]A@j8*]A!3'-rBrKlpBjX[&KS[\@0oKa%/@F aGFpV+Ak1$@"YBk/,e-Fh"S@JP]IX[@ZRCkVb9[_ks`jDFpC26A\>A"lg.q_q/?BVN(PrBgJ.(RGYArD'Sa.1 UAC]P=_1_Qs6%bm$UgJ)..gWeGilHJSqjhYAd+'8jYZ)[YelNG2%T5F#."W:S; m_Jm`#) E';U(]\\hosFM&ib[@OdZj,mdF-MHs"mI"0]JST6n=e>s^]>*A"P/a)#n+t9,V-aI3Djm(FQ70R4E:g@CJ##3IgOW!qe:hNGW.m`0._f":9&ZmoaYX`e@*eC9isRL^iesY#gjoFR0K?$!\Xl8_11k&;+!%V/QN/;G"g"7]4*BX(.F'#[ET0[b8sO>:A:daV2\OL8nIQ6PVqcVmTFb)qs%$D]-:Am>re,n6>MI,4DZ%;CPf%51m?BcB%"]=snZ9BU9[ X/d8-Vc=tqI&P*pCTrS8=VW2qQ[_o'*'AENb$ac$nTZ^6oMUl>_EH)S(8>Bn6K);0Wr(cfhGpI=8& on-C)Re4A%Z9&L*XsAAWH=5:tXD-)ApKHW;AM5X;dd`R)3<85dG>KD fF+`oDgsgL$knXJn!(`Vs o#5mg=J*@DKNeAgTgPEQp[(]me.4H=`:\HnM*j!eg*ZIb+EfU_op"/FWl.i&TI]gU<&aBmh5:/HG7ct`aFABOhS);p$q(M(%85[[$X(Ab>=%rAZ^?!>D#kmq[OA;W*^Z*R#O^Q@]HnV(7T.\@XpomAO!o2fP#nsdcZnIl=%eA*YoA>W?^J+Xt>ZMeAcHLs`D_1JkBtWt>F;06h5#4O[4+p.tC5K)L1D/(0:^d(lmalVL[Elc)cR06B^%J>^s3DhVi^Zo*?C+>T/"J4-6'J%#A(o/?N4*lc5mOfS3N,$F4AfNMj8f)l8p iYFiO@2e"7/nE,GCblomBE7AJ9!p3:AMPme &Y`o_Ork6`XNEMo_otZa2N3h4.+c$!+4dT5C1os+jGG@pom5=sbo+'2TtjigZKr5m/pMP3@/+#%HSt=)SfU\329H^*NA+,J\OAZId;&EP_j'j<#/@a,%r=L'1BPiH+.LgHOA%'%?W+lO"RgJ)e`o.[WPo@$2)GEF1BG5%lZC2N7JCB,L5h!3bIX@AMj5%W2LI%;Zf;fH1`PTIQD'-r@48"V;p$iP3KJ.U!*E!n76L64O(oW7?CV7<8:ZhPPZ\E)AL W@5e%8Oe2a9@BqA;>k%Xq&ocVJb,+UBig5<$7d6P&[ \-oMN(V$L9-Zh:Ad5:BX,MA;DXKIfk/^N*$=Jk.aH`0@J[!j$2=:"n`MBMQ9i7^=3*,1C>(CCb:d>D$E:=+H^Ap.th9KA]j*FQ%\FkMeNiq9+?D"mZS<[Qi(O'Ra"22/:)']K/@NJ)pTdka:"5kfC$/ljl"[[G6A,o(r_eKjHPWiJt0iJ@3FS!^'rcg2:]^t/(6BJ[trtWG+DP,b6;l?K:[]/RDo?>!a%e'*NOcmqj #^3N#A?N^M49AQ%-cZoMAm)a"F2EM3;Aa`_\:D+(c137HS3F-2T7VYJ)U6'Gf_i-NG89'R'hg+GX`j<r:K$VK6I,SdL/giQc$E\Hf[^C%C k!7"lZo8@^"*Y[\X\lI(pd>-B[5PPFK3rC2Zt\[q->#*e"$f,dN$[k5k&V6:C6KI8fNAD_SIW>@!k*o Bf@&m;H<jhQ+U;+gACds(8qTm2#CQ7J?.CWAVq?7Jce5H@(CQ$IX"7$mATFZC@i>r8C]IjVF_#Zc>q'5P*H6iARNP1B&)$oqWLG#en5kT,em!Q"c1J / hZP _b*6-pp-0CNBP#?^K?\&\a:`T1Y.k:hh:eangGB8K"HY?n 5Hg6^8:oo>=8tKoIPkWsZUg<L5jc/AZ,:A$]K%oM@"MBBY=\P6:;V`!to2CFRDeh6No1/R@n$7rI+2!]F!;VpFaY#)f%#4\<-r6CKbfohI+sMZ Gp/"8(4_WJ>SjN,NIY\nhf\S$rl<#WmAf%j8rFg,K4F3`]8$H=8N';0n+D$oGnVNKU.F-Y7r0Hd*&`K7A7E5X2;OMSf9,LO0Wl]h8U/FW_d ?Upf>?XjPaO.iN9:DQKA&M>t60_t)/;(,>^LK&eIknR/^DW#U/.m13+4a"V?>#ABV.>*^;#k9&^ZC2.sSo:2aH%=iaA;*TdSZ+?NK:O:LS.[&+_?>`W&7Y**P56Xsd-gE3rO_b=qHI"%^]X76o3 Q )2^(Y^@ZsHYJsq@A]&J4l+E]HO=T7p(`Vs#/bAsTCLE2^mdoZR(,.A8pshE(kWn=EtMh?_h2d/=-bUH^F<'q4.f%H;Ia-BYA_q0jfH3i=C+jmYk0+CYEhH&&^D+0 (X9_NUfNDd.*PIHHhL;pma#bRED'W#D2f!P1^k9,#<32j+ Yk&UMl,tgAG]Q79kf^s1IpK'1b9?P`:agbT!eLS@+IiIHI6asRAAf,`4WaiXtZ+A<BdQIq/%UH2CCiQN%BaDrAc5pa(OZmb5!fBsO>i8 Rdj/D8UgIo6=g7fc`*YoXU*L[>H*lBtQTA)=Z.OA'f-F8:jTsoDYLr?B<OC0djT0Fq4$qR$rFha3?4HTMIL+0EcXa3iL2;3YWgee]qGV^4J*:h",BA\>]/-ns9,F>^<"F(lH4KmOV8I_M_#ioPU#Wi;;2r*h)a#tr[">j-Abb!>13#]!WK53-A368__:9$hC9h7P?tnB.'O4D*9>7/(nU#\pAGQ9'/ N"H<_f.XbTYln786*;mFsQ.0hP9X'27a8047@Qd%E>a^s>L$:M!Ej07sZ[/IOOAiU,;[9FdG%Xpcnh,\:qc3:WS^JBH[S>AR;bM$OTP)2'QUo1.7i5Ucl?C#p6^btCI0) qAl#l&]p(00.8W\at&1CUAa)Dj ^^!IY?d#.K20Q\rAhXnj1b;Bm\")io*SSVTd_P*$+>' jQP*#]re`4@FL)M2!i;HYZ_k pN US1gq*%UBX1fpgiM'+7KGXF4o`-RYY9O.; "g>`g,Vg?NZ3kgA90(#Q1aqkD9.MG&4DFnhr/3Fb:T0`GfgoXL T'S$/X4_8nb1I>SY@9E)6?7M)iS>QfQC*;r&lRCG,Kleps"JCo&T003jGAU.(#"]WnmAG^rHh\h>6qcUC#ldB4DHa(T$^$*rO5[hlhLS@q@ZAOlaid]-O['(8o3=.8>?gA>jM=tPW'pX!aX#IgNAX,@)]!e;Pk^"\-:mbU*gdLFt-CmZ@3W_567]2V.I3ntMIYBen5YbQVaAX9] rc.Q#K&gC`Q%b`NaH1FAIe]A0%qlG3WhTE13oHrOs0(A,[X/q6G8VAT.%gk>+>;;Y#B1,1?s]sWa`'/gmT_+Dd+lVGCLskmrf;T]FXDjit@=b.`mC(LIiY mK&YFUAi$Ka(,,JTH!)9p^-NkGm1HlQG/"%r@@@c)>]7TDL*G$_1l]&=_('hJ2VpX&NE7$(etCjPf"nHDiN/%>KM\@e/;8C#LJHBX,XKl0$tKE4.:KL;DHF52IVY-aAmsZFX_&7=_Lr;VDip[UA2D36E[P=^GPJC(:N_[?qZjrI_)ttY9rF(F9 #h"(<@k%A8%"@ktM.$)>cSd.1KlK7WkQZr[TQ]MK+rZ35A5il]IMnqMJb-U92HRGsAXbF_&[hAV4]02&;Vr;l=Z(I4cG*0f/91;r/1d*QRY//(WV J_tY,EY+_9eaYE>@tGN=[ ;K0#E3OeCP1UfSMH14#P;(A&JCod>`_qB9H!kDG,\GPVr.>*OS?  Bg>,m@0r f7&GXIsjJ?]cK2?/^#)snGVDjB*hmgik?/SpPL<]$*,HkGbmPJa7Z,H<;l_"-//L$Df25%(g +G`X>HiIam< [A%dkdB1856D3P#dGQg1?_a[Q8bnRAmskmAkH=p;?WMKgsGB9HB"YDEZN/=Eb[]C&!+Vp@^lGRH1p$G_FG;O:AA*hGoe=4>6:C)ABX5!;/o2M+X? 1t&>8^FmUO\s.UmMO(>a@mR08HJA4)@dEP2mn`/'&+]k!e8L2Q32*'r,Ad;D?ACnc&*o9p@rEV^D7JG$SZLS1i2q51:sgrDtWXI?4Km1c,NHe&P2rUlhea.f"*o+ksBL<_F\pf+sD`n8](PWH$h/G4df`THCo7-6,&4d,C";%*UFQoWOMWrG#T_a+[dQH&[1,\#!Freo'D1">W)d[=bh6YD/@YURLi]GDU0EX1f!Nj(f'^Kea5K1+UO#f1"O!q,hA`]ior/]BZ(iQd#H_2jj.*kcAtq[Bk@hhCpB.Hb+Ud%@A]NBY,^Uh4^m)?2ORP,C$q#pNBkU6NBB#_YV"_,GeZU-'VSU.RRPn5r3'rm3^mXr*&%$"diWq&[RM$G7(+PjT/plUcS\Q*UA-YWn\4;e),MoMYMXV3Q/r$MoHnhrnpqn/)#InrT8:G\JRA>GRfk@t(FTpr!OcjJ_=K8(,`_FoU[-A<4@Ip3c'M36V+2EmLU/2sb?Ad9];d>t&_NEGhdbs_<#['6:N;tnY%Uk#-8;t;VmFEms(!&07?`?2"0VR"7Xg%/?A;k>A\,(1,Aj,srR9)%qJdji<+M*5M+pU9H"eW?3jrE`apa!;qV0UKIT6R?\TY,a3oWBl9k<pXr;.*r&[MmmQAA%$oLI` GEkfsTPN-%5r,"]B=Y[fd39P`"HnPA7lAGsHW@NP&oN!>34;P49"mtO/RK EP6mMmi9HYi%TG$AslA@=M]cN8A'M>#=-[bGdLh9cOXh1.N)?H_kHo4nH\6II>Lq5'VWI&56#\'%qn,L[EGALMb<q#4nB+NralWhAE\]fTQpVrbO'((nJG.^]=bS]'A3_YL^(HM%V-GZS@"B[UtH1\%)-eN9=R:Bn6S+se&9M9:gP81lj*h(8RWj`E\Lq"L2$W/rUCCI:Ylb'2XWA?c&=C8_5/P86_fhg05B<=NLpDcR ;rg' SE8'L%mUI-9Xa**8@6'WJ,TTYjO66V`8A#olMgs$2_b".Q23Ai"nNI"4ECibgbEnr$8OD 4]3b=#;A@G-.VYKM"PKmq0P7,-0eSZgl>=Op60pU6=;A%U'LW4 MI;KR#qa;"ILAqjM000Gkq9KkH+;(:*.!c8<1tjH$A=c@Y./ikk)r;ZV*fJ]<(JA$teH/'Eg"Pfo"+8`/TB-r(% l2K'E:_Wf;5t!rcUpA%Fr3#5(\+PV0Jl;;Z'+D''@FS%Sr^Pi'=sGE'&;ATs`;GiaSBTjPkdiEce?k/a6+16dKP.?n5h3SXOa,c@.48=gqN/!sRpJ5G$)J2Y#.8no8d^:fVo\Q30HaWP1+l/]"K.oG;H_4AE,rd]L'G5(:CgAqFsoC:2DtH94<,D\=!CiYV8d0(j9rt-CaR*$#'pL_kZm????VMfoN?tIlB=cJ>HOVH:$]P-1mHoXXZ"I00Wdq5j]E!)&#S9n=%VV67\@B*9?CjlV>AD:J8/o%PG9[lBV'3)!"]%Z-p, -B#[a9MkZNTQ(V>Oh1+L!q6?]jc()`?20W"6I8HA\%4'q9J1S]rAb`Pas.Ts%7lWog6XQ\ *S6dMc,-Rd^C?\@bIFq` 3jO+o,j-29Wp!mN%e3P8_La[A!*UbM+mhJri`a!$#8=\,J.(->;/%$%L<^MRThi"s%oPQ,=?'4\1;SF3b@/$HeC]P&,(^;Sg0V6ZJ/O%k_qF:H+!q<)b(]3>^VC(@e,FT1l6!j=Q\"rVSSZjR9N]_<\s*@15N#06gt:J%8%4EFbktD1BZWA`RK/l@K43K#1.W:;jQE)cN1Cp@A?@RM;<lHd)q!oq9[W O5UKpC`#88Aja0i.fn">`%>+]5[oDL;N(+Bitm"Vk^6VJB-[rJ#6#GMH*je^)pM).U9lZGQXE?h?jkXoZ .G:T'E<\3#0apXS(#()fj@^0A8l3S"e?r3E/A2]hbSU\Y%JY$<&Zd)"cHs`jNf_8)*K75EGXaG02T4GY42/?X>#HNEHP?]ntgZ'l=I2CTa"TJ#fELgaMTZ@X/0%?s3%c&#Xd"$Zgo[oG?)?TBSoC9^%"\5)4Ccs$l"k(skSq`+C;D9pCgi$PkmfV,sBPInTf[s) #"q=KbP\lE$Et\pfaepfX@<=qHrj1) E!A2W:oFRZUed;2ZF4V9NqmU$>/e$2h]rHJ2bl.1H61)5bZ@H4I/e?T.3cN=YA3<fpigZ"fJ$$!$n&tQ2N:fO'Gi(CHMe0L2H(Q8M"7Q\<#n?gHFi)# Vk+^pp:rfc`cAqarbFsQY+;Ms_0/m&d$l-.+SaG#GPR0\K/;H/E9S-9llAZ0Ge&3-[X>B3m[^;$r\NlKb=ZgkVl0P?OrNR(F^^NDQgV0\N_K$8h&.1?QAE/ada%f\"NL&VYpfk_Ah%k.g$VrU%15WYcA"bdAKY<KP:fs9a6db@*h/<&O5t` 2dUJD@Ai. [nKs:3.U9iKp4ANWJEMZN8n?CrqG_Cr/q+h#3L%\)HkT6)OP4o([CsG9@L;-0#f8JNGYFc %o]n@IjLJCg>af8B89D0`mmRsTD6QPP'2EUOdV02/23/07NX]dBAC^CHln(7b&DGV4GdSVE>5MT@:g'<(I%E@Eoih:L"D@)2[rg)3@Ctrb'2()Oe1/7MpO"2A!57c_[-A;*]N_"2&;A/k9=!Ha7BYAq+'1(N;t_DA32ml09.J4RXaI4#NK'=8>H2P8g]9g;_#E'H\7R?1'%l3RUl;WT[i>.YkaKU#1IH4?YI,,CLSHVBVr=S@Xk4TA?%K`q#\YjT$Bq:Sb#U;R;%WZANs+Wf/eWHj*.,ZRi>mh7j$[Sn7m8H_&gH+-!e(Z7TLDOqI;pbJYA,aF<Its&KI5Q?;_E@hONF:Pq(rr`smD9UoHEaqdoj7 qm3G(c+P7Qcm[o&:+LC7]p/GXXH80F33??MYp l_8q5s,)VkZeJ?#s)cq(/fAh"g\n`j$jm;afp.&SqD$&]X,EAK^8D[Ag>MX#t*/ASaW#+)o9gr:/]9>XE_es6dO3RUPQC>]HS%)#b_%[Z^g0rm^q5W>[Y424TcF,mi0<'JU3o_eGcqKE%)Vj8+1MM7HFt5.Z2YcZ?WW4W*m$U@(O1-"imf_%1kgAVHRJ(:GptA!1id\<;'3mV][Q,bqEk%8 L/[KbsDk\h`pirL5\pp/?to+NK=Q= .s[OHR. 3>*\Yt4=6G5&2U1Oqq+bm8dZEH.Qd_Gc)(Ze;&Zn?:jC(3^2-W6*m*5:GrPS(JE&#MDIL(Td&3nrl-ge87?mtq )"(3$r_JCWcj'VRmd-24+.j3I4&X5fMb[sntUDWci$*K 3U:[]/YZLn08 %hb6GRFRW2U(p56 /Nq-Z]3r81kDG#p+E'T-Hhq$"5G"e)irQd0J9"&QB`ZffD&5!e]$];IfWsQU?gLS+9U08.4XroA+;s?0-k2d2R8`.m/UlS])l7$J)j`1:I-tffj$DSX)t#U;KkO/P'0^o@Sj+MO^lF!tAs>m&%XS'RYdC4Z<1_FY'[H".-;[&NP^ ]2nHOm!^RO:V9GEm'8sifqpcZ>l6Z1OiJkCGse2B!IL7\YP'cJ_6!CEg.J)fCi <5.UfrRlDY'&""3e`O"?sD7e:YrWai>;a_Bn#fZF)#8h_G5$Bisde?Jomn^@o'1>5LO`NbpW6?NJ!S5'iVQqi1862S_)o7><'O+ p4$/d!dZR(.&iplrrV7Kr@Vi ^G8?P8sn)XZ4<T^qU .j6tQ@a'n(%*?Grc[>)1L`^F/K1Q?`'8lA;DLDDmp5VMbpi+7GOd2$:pD<6%AM(Mh0kg?jD?NBSFW,6L&[PXNo$YgY//Ac[2+A7X7R7ZP#1')sAEN]_A2[K:M9h9lVE#\=;+Do&cnCp?3"'S$0YsF!7Dt><V:!X%lT?orUNR)A4#N:Wr'FMKc7_fD(e1g_hkV^'-Sa_MIp4BAFOHZBni2f$(1jQ1@C#no]N#j)LV*p6MT_)Ze9rF9ql89QBsGj2>3%2<_@#.W(\G+mcm'+[q'*Oc4a%E/A]MSncGaf;B(',QCGP2eL@%7D+g0%!FSLl]]L*.F;o)qZ@63<&F\).cDE<&2e -(5O<;2G8X5e[j:U]G-5U.WM)5#40mQAUSr)E":a*l7I&W[@*ZlT1ESJ3OQZ1@1cL*Ac<]MJd+%.USp+(=CAcI)_hnADV^s-GW6Fm+r,?$S28i^PJ'GsY<>)7<+b$PWq c'jtT#nr#AXVBFX,pcM`%OeGKWT7/!SqaqH9@X57F#JI*FKA_/1:*s&H#XO;-sOOS&G0i`]P"^1jo5W6>$%Bs:HgZ.9,WK3DcQ`W,aP+4:s5AWjM35_1)dks,7`f-VJOsE;D:c)H=7FZ/VC,t'csDfF%/Fp*T?@ie*VKUWkGTsa<9Ud,l;kR>/7jjs-eH4^j=VF.l@Tl7a,ApLbj,?PmL*t37#R)TVNE>9'LjZl^+@ha;WR'X9FjOU*Ot?k+#YE:7G>nW+<AT'8p!TUpZ,+]V>rDPR(L9MJY>ap?'1 A\EZK$bliYn&5&oT<Yl>P!D!K%BS[U!j;b0pY2 L*gBClCjlt*&<1Ko`FXB\:*ZbD]9K#`-YKZ&+g5h)F/^=97iE!ApL^rdR?1".l(e)t!h<0lg^;6!4@#1jn\Q<^$LBt\;  8`9V<`g4LC(so`<% sAY*a.P'Y=M>q-C?;k!?knDk!pZ%%$5K`XW,b8H1k9,)sEbWjs4*AC;!&H6fafG:Al,0c,eWQ4>,lDnFSf.DK;*`F7`b$WmhO_ZdOa01Uo#A?,RVD=,@H-%;/\CBD/-Jb")HH!(0XgSnIhK[%b5-/h^?Wq0Q'n!d.NHig]\K`5c"X^b"h&t,Pg- W"[X(gqPQF4W/$GtB;%AJ6[#VaHTgV8HNNV2^rKR%R_"MU:Y+-Ms4nB,1#ArtADMSY=\dYXeQ])g\M!2cJg#SPCHqh711ObJk&HV"qQ^od<LfK@:FV'm;$t^k:qE>*Jh2f/+m9;\Q"@IG$0JE/Sis9XS_2T!;K [nL+VWJG!s0&:@klHsX@(f*4R/`sPYR'>8og.[LK-Bb cq+Zt6JFbdaM\n;o,ohqe<mOA$3@5dfO-)pI,e#[QOo.k"Wl2h[Q'jk0[:4p!LVWA.+l\,1cRTL.oogstQ#6:.1=.4)9q92c1]LcaJ-K'n=W!^^Mpg`5/<(6>1r 2p&'i)&bEGE.ftQfZIsRh\C4H=>3M]d5@c+3?F`]MNZeKh:/[(JWbXNa]q`?F4jl8OJEQFI\>#B-t1r?1m_[I= 5:BHcP@3$d+aG"8;Mg#TL4.lT2A"pmGo@a"&nbID9)DCW_SVJeZBCClsPG/03gddPG7D@!A\Y&j5s93d:6kT'LX$Yt7gEP_L?(p.#r=*b-'sc@SE6F[(>4nn(ZoC<8AJ*k@(Ua(mCNt,N@b>qm,o^LQ9W&V^9A5I%Qh;RJ\E+\BQ%IoG(!3GO>l>CAi(a%mmB*\4V9(lAI2J%?7dS^3/b0--0g25foi="!]`r3B`ist5eWDsqF'GNI9q%#TmbQf.L#ReEont*o+oebK/OH=B+;*tiAsbQsnUFeLIQ?j]kr1rjM2TWiEbkmP1]eKPmR9/A]t!Te=W>9A57.dQP^mn2Vob'5jY,5orT*p5*`'@'^GEG[C`A-saaa#cQUo^#>i+4H6tEkHi4@6(]#W.HQT0FQ0IL%=-(!r9^!k2MWXTN-dt^BU/'"0f4tZ>gQ^4/6>3:kb!8h gZ#`[kD7QBPK8AH9/loBF`d+&(.72#=JC!egf 95%>9#IF]0.T-&Y%IUD+tLR1:C\&R!rZ9Uf2>LjOMn%Xn; YMQ5C[f(UhZ3nAb,CO7LW7$^!o,bB5VRhSt"i4i::S=7J5X[ .Rp!-E5#FQN;+qI]7,R(:SX1%qCWK,m\9="cesMOMHp$pS1T0 \C^,?Jt;_Mm4]=i1XCD!spSN?1KInk`qiFiWF.]NS(HN]_bh:VgO7'\etNMBrm,/4>&o`W+tf4 -FUmm5\r3[ALm9[dUJ').^8);Y^`3P'A^iVSjaXGN/sQhOITrQaU"p&6?$4!q6CE)>Glm2pGe-)AX@4V,XDT $`)7npm8=e%*!>2FF^aXQYV_[2d5C7I_-[j]DE^\J#Q&AMW!$W]G3+N,.\?h>%o0s0o\gqVHL:%N]iL=]9,j(m/Ap5moYVK^T"Sc(\^qk1pe33N=`j(<*V:b,(#h;6rS8iq1A)RBW@!G7O&V]l9?B;Mm+8<-fWe]Zo5d%VXW\h9a4%4o`NKq0B/n]i1@%9GQ^2^Q5k*.$=LJQ8kXREg(8RK8c#.^FYVT@_$.N,j'sOiLfPX4ePXH;)c3jd-[9Te2f;dqhqs=S1Xcl&KmS%I(;Nrp,*7Z58NA/4OXlQ?[%3.2co(`#KCT;3SJejOR')!?]^^1^-UYY/.8 823gU]>h=#BjfAn=*&mDcSKpPsL(G4KgA.5%@acdimWp?ef:eiQ*@X)Z)MZ-pe72V)P]e l-A!=/Z<%80KA5*$0F@:Tt%qDNs4^e.Z]CFA^S"JhaB7r?A-n=otK*Vi#)<58lo/R4l).aDAeLSFsno`1Z#P3t2GC3FAal78/hoK,>'/'Z>h`:8[-`^7G-#Q7d.Vp.O^b-\#E:q86[UP@32gn-R4$-dN'48YiPh=Wj/H.K[^>0e],)7j6tnNq=G9(lHZd=*24"@WP!\.rC_R3V>W f0CF;SKZTE1ZgZc?$p&`.eE]:5^?<`]T")RtQJiXFI%U$Y]+cc[ 33SM^_RGC<;&B^XnoL>"4g)6RaHjX:)!P%EA_91FCViV7)"lR3HYXWpet\#r>+f`X&g[tAHI9iZ+RB*!4/jP:Wn?`*A5Y$b!eWe_[Z$M\<`@OQm4&(RWRNg4@k^D(KhZ.*?K#=On8L5sGd?::5C67$Aa[.t)9S\1"(id(R)-O5 GIcCO;05;l4;MQ4)K^-i;UHS ^Y2]!ac8r=K9#i0(YVENL_>WO`dk'?[m0AQOSqX_UDGWBkhS,.@W)J6s0aAdj3Tk>I' $ghFc!V[+,SS!:sAIg*lao;?1Ule(YLR*M5hgS0sRY-ULD%8"6"Y*CFA(V6hW%KE\=V2D%:,63r^g08WZV:OD'?-pdNq7Xs i$aSa^,'saNZ.?M+g!YO(Qs]>N?IUY?TSA)=5QmS!@%U6W!MQ#Q3rS[tnb._ab&BM,OnhAE$QlJXT*H3MH$jKa.1sV+aEY5p:[5LgFE[+n01)l/B6iA'4kB6NV!#.,^LAK]r9Yi?mG?VoM9RkW6j96cnWCLG`4EGS+b)'_!4tAfYJN)H,'[:^'7G02\eEZVFkL^b1C5VW5%-HC5 Rb8"E%5!fJ#@l51_4a+j>&\36@h;AW;GpNcg)QVBS:SJn.CE*(5p'FqT_fe$8=ILSaA]KqU-'S-51i*AQU5d\m<5'VZt_nJFYYPa$h1NWY^[2Pn8rm[^A$K5!86p8g@_m@i6oAIE4ScABg2^@1#5c&V$G%b6qXMEWFP=hZ1I4@2,Z9OE6AjkPDrgAWXS!Qk]M<*%H0ck/5Q\[B/%)R`\]%?/8K-\VM3NF$W1s@Dp=6+bk#H2KV`b989I@RUiQ2[\5LJkcA#MD/ah$-g4GFC2&/>F][OmO0nT'ATVfl+JtK?5OeOlmXOsmW_]2:a-*#!EDefH(RA&d3hBVH51b`JNNcZjFmZW8LhhCfRdsX_;[LPk0^Amr'Y]MaFM>&"Ah@5oag&U>0sgOh4mqCk96t-5CDAAIrtBjMt6!'K(j/!Y (h/'9m3N8:?B".D<&37kX3Vd?kdMId!r2N VO :#/M9pebF+)s8_`k-jZ KhD<2Qi; ]"&.X8Yh=`_iN84L^>.,okJOs#e\:V9)_As;W7&fsW\9M9A?bpeq4[BAJj)^GanF;dRBATt!MoskAbDbjmkS7)(,J#<3n-$hfAM lP\F0Go-'khS`KU^>%d>-ROR%t?Jst90nsR3`9OO+mE6X\japPR"54,(bhMjc$";$h-e_H5=tp,[YicH^1Y`<AXO_"0M`/Mda?f4A2.oYt0CKf]+2D$h@C<>#K5%o%)D>QD: scf`r2dgX">cHlTH:>O@ZHq=r1MS^$gGN'Q'_MHD5n%7m9At6WGIAXS'%V*C%I(Hc@=aKUe]sWo LZG9-?USAg,kG:bZNZ\Q2Z@-aM^l5CFCQKa%(M=APehR>Q;-8-0P/!-'q 3#apC":a*D'E*a9[*!Q^"l-Bf=@@Llb6AtdX@D]E)T@rUe^+CUqm:o'']Tc>hSVnI0*mTmJ@r5`k9@Fk`R)2 ?`!FIV[Km(<W:a`+GdRnS^/q]o<>Ps)aAdN?*,Qk!,[^72@"0Fc!?'pr2jVr;W,Sc6>C*Ttp33,+@[p,/0^N]>b")p*3^c:p1UULHW'`Be"Q]%:>>!lJb:/f`j-Gisba?UA#G)FA^tE[=KQFMt-s-NVI\03s>h;`@E-D6t_6L @ Hq(Yf[.O(@;"R2i)7l/>4_`_NaT19i26)Jr_+d_$s X:\&;O%@[( :%Z-,$!9Ee@r5MHL6G8&?^!Adb]e@oD+9ghjPrk8-A&1KfVNA+1Yf1;04dqhb-<>5[#LJU#;t1K/!e;]$c_eMG0s+F%Y'6$A/5GJ;U])jA/JK4Si03G$`^7A0J@g10a;Z*B3IjG4@@R$G&oYI0W=!m6CaZ96WZSC7"=QM=FKpoGA)m`Md7:.amAMa5BToXgk@PAYXElF[]A@U\>AAU]t>MALHRkqRZ<(*o8coNQks[i(rlXl1>/#Nn2`GSaAE=ab>6Rt_` +=p'e9f#9QVU[#UgLV7IM*&6lRf8(.'-DNK>ZTA;/hkV`1&k+A8n9!6JO(3fb_;O3.[ QX4+o^09RMK0-'bi']\J\g+#04UmYei)g]%=#-ZG&PYQbY34(8D$6Q!PKT$+U2CrpR"[K6,\XAL'El-h&TJ%VJ'-qsL=qVdGNJo`V0bn[)oeX7S"qqLl50T=h*(d]Yo@@C)+)(6QDJ_[O&I=[:(O6ABIPAg"jFg+gm0=kl,GMtT<#L@ !sjU%S85O.iG`1SptR!Bks[AQ':h,\FM_#p69ZCI:VR6M1M/?ASYkm \ng;kEZ"<+31"U@(`*ar^?jd&M5Aie`T.RNs2$H;0BZqep.33K $CsM-4)9Af16*)TE>rZ+5b0;-"' &edIKN(`N7A8)8qsrW>)_s%d4f3o)lsG9jMBG ;1nS^#QE#YkA?,R6R>JfK=%&j]0*(&6p3icNN$h.:P1_t=!00#0l!SXlAPP?>03)\99)GUBkPlAWf`6&?@!l.BZqq8D n6sCeXg%M:EK2`%m1C$_kF+PW%IS@.%9s/CF(Og_:hT5 MJR6W<-:S99' d!:PgHA=.RG6-bUAcd1.5eY7&g]Ca1,;U?XLD]J)\l\rkG=Q4ML#9;HD$> i:;On'i:k4G:%F_6i[FG'2V<>k?^b6.lF;leO!GN>`T]$\mH.J9*mdF^0kNC:24 !5(S@X[AJ7 Q2h[K:1^Ab*J"56tmB%7$Rln"q&[h&=,BYh_At:?asAr#-fM)n]lK@%lA)h=%.%-X+LM8b=K9`6&;$0D,5X$QHS`hNP3m9tZN=s#:5kd6!Tc=&LW7br/$?6YN@L0E4h/Y&:DeAB64,D!osg%\Ij0A W(0A:QVGh*ne^n$m%K0tPW969Gqf85jH[*=2;8V%gpHV3KH'bqZj#i]QImc!'!rKVP5AP6l1K9^T:&DmQla*='?X1SgmA>;@'>K!n7mL%]]L+L_)NE*c36S6pRk.&P,#AFhISXq1d:(E@)ltEIq2Ik&KN[.Ln(AH\qqX/[87\(P]rM3Q[F 8hE:![%M/*2V3U.Ncn$8eT20-@NA*RNt%p_-"W]/fsC(Nop\Am"f.VW[0,jQfLCPm#XBBE2U^sV] GasoT^9Q (HDl.MMKbU,fNR>.[N28U;d>QHeeg?RrMJ5diRlXW4OdOO'YSL[Tj0KE2k1A;g,+3da@N>X&iR*DVB$hgOrB.0q%iA[/LU!#f-s.1gh/nd,8cK<B0p-.p')jE[X`VR6-2V9*0":](e*6!p7sFhgmi0a*q-g(t]^eOQCrO"-[SH0#0o0Z^pJZXOO`Z9EaV`C?^m#Iog#sYVgm-hfNIBGUR3tebZtKE'aN#Mr<QcE@'<M_Qo6<1k,s(8#k-p4spe`o#\eUG?- .;tNl>H9tlP)mr3Z$!'o+jX95fDM[t2"1G?ADrG9j7EM0,;WB-FpEm$sE[&"::Pnqq3/@H(,bW,f/KJZimq(WYlJ"eRMO`TXOpSYM6-Ob&d6S+Sf&+!Yg]4+A=qH5S)3d7*\mdiP?Amt?[ANU>OW#L8teRfSZ[^67<[f: _tX'AEHnAE[W.oCg8a$Pt_g`'hUe9L]R)93.*,M<X0R&t@#q\qkOhcn23?on@ZHTU-;\qS@%<;P:?h>W!-2]Z`.hh(;BT)2V/2m(LY&)<[1I">#]<[nSVMi+"9Nf1>_(KKoG9mT&s&_k\g7%o,qZJDOtRAl[#@\AI&^*fm!No$e7*4r+i^E^T<k>s/=osO'Q.`OSr_Y,L0TdQO!Gt#A)+2t^X?Li6\p+PB-4A(eI4$GBrC47;&FdG2AB.#Mf-_fP#W@ro;\jcEr0/ct12[+N%="D"UF\qhD3nJCm ptMaZ!-bS2:;0P>&[T]k]a$b-3XT\-'P=KL]A%Xh70nX:Uaff`i#Pgf,edW'_GKg7)g5gYt_,9\L]>go,jr!tgjAOlRTI"3DnSX(mtXKlKgA9bD35!>>*1_6/"@)NkVS%mKFfHmqZ7`.LBR;,p=_Q^D63lt\Z("HjpNb\4^0<m%JoPS:ST9?D9YciCmG2iS5Zg<02U*Ai?nLJ76">-<L9\PU Pk?V7NZ'd]t-AZ'dlO+>U0cth)+ZG"<2g;Xc.n]L$btADVq.e"VWSL1rV>=4C=0;o8:9to5FBNO,nAm^Dh3fR1j,!M2*\*;0e(C_i,km\PAn/fJ_^5nfOMk8=>,d;!ZB(#TKmVTo>;U\Ckq5Y>[/b-JPf7L@tL#d6'&NBV)f],\5I-S:#ASCGF!XI3BH^=breg"m8lAAbV0k_BSC2BZQ:U5"C0Jo1GGd`1gTH&N,IhHff.UnfZTB_WfS2Zn.Gqlnj7sZS?L%R_S8m+P)f#BZ,.]jj9;Al#9I";l:4Z2-IMIZl\]4KFmiq=(t1N&BA8L[H0r[Wl; ++?AU3o.A6T)cjD()7_99M"mVd.S#"LIoicsog^EW&k?V*X_Y?j-)4AT?Jr^58IJ:!p2G/q;iNrQXTMOF=JOBfL:ZBlh"L0"PTK5Q`1p\sK0Ne9Jn[I@ P&/e<:,>J!0k0iVd( -oVhY$&PS(>6#6D0R?@"/G;cdJJZ'kpIYjE0^W;XF)@6)ebFR5 D$<WN,Fch3(1j? <0DW?a674XLcm/TTJkg(ScO[?2nlkA6iin !4D"iL!/W.>i_h?4'XgH)kK9].eX,I+d 5@IUTA#m/_>^LdkKsCGg:6%?`CO-*2AhY=cAfQE:jq/LUfKS%Oe_%Ac2571+OS^:q\+JMM#DTiK$?qs2qAD?fp6Q'!4H*<07)Q`Qq/1++o)VCNW ";j<S&+-[ois:kC)MW,Ba'35Yoh1hR#"JlLPpPTXZ@Mr:fW:PMcajPaiR,"+a_3$A%YA]j5SdVR**sM9K!(V/G!#>0_l/:*MEAiXIPP&bs6%ea@Z=[;l`TqM1!o+7mHg-YD?3m%1GS00r<P5t_Y3+jVHRR-*RLOCFA:="StiBqqsoI0fGl!CV]PeACc.%SA"gn%jmS/Fmiqq&3=X!NUBc]E%k!5nZaJ)VVX;9B+pI2fO7Fk!"Afkr05Bg&-_A;IIcQW1EAK83'=;% a.Q8sA.fk2.Qcdm`,g=$CbdABJ)[&F*n')mgl`Hst,f?QW"`rU(a9([[\2Ikeb&,_"i_"r!E5\rhS6>^EK@J'=L"Lk\"A,VSWrSAki;r<'_nj>'B4%O*TQo1D<"\8 A J;Db)5VXGp.JEDoU&cCGK8:DqAh'DJ-@Q@9QmL9"3Vb6-P!IVl_aXc_Y`6,d4W1#9P-[O^$-$XpP3a5TP9QapQA.3Y,>S\9VE-s%!'-:J3[>@E&RU!B^l`5[/]5NF#E)KN3iJDVli&(^APc=W;C\ts_-A DQI1G&DRaQ["gUk'[.-qf<_?7:DTEOcsA"WZVI!1DA?6jC*3"KF1dik<9ZsM!*!sIW9A]?1A3H`Ggn."5\R"m^cEO0nP`UXAT^:r@A=GtfQsYK QCrXn=HkrAMhY24e-qFNG/N(E?tFiAS>++fFKXh_MKkGI$_#BhA]fm7W7nL4b-3>dsLfceR=.-644QJa@%SREh[fB%lQ L2203F:Z[re0bL*j_M<nstP<:#;\VKQGLs'U:K]h&N[Vb4kQ&UYN,-D.[0S_cUkC4G1f70%nI%T&[rTG`WL'E`j:Tk.>qpjB.=$=)1F6rVgEehOOA?,8Q/AL@^'f.=D&;AFKtF1!qa38E_e4EY.Ul/.qMA-^'-L;nZ2+k_!s-*Z\f?P&D9e`+T?U;X%EpP)+m_e`WaKK*S:f%.L[9Fsng43neJVmSA5VhlEhYV<4Qk/0$?7?!OIH7/%T+k;h.d?e;,Hp,FMVjL*]ZBAjbHL8e<:)#m HZC<]:3D\!gsl P%%k+#`ep.P@V8@FE;89DnX/oW*/Qleh*]5O=#eQ,h)6^XMds1%Sc?s*DXTj/F" cJ=\WI%pj;dpFa2Dbs0!g-JcCql!(t61`Lgg s3U-4*:f)@SG&dS.P5i$9[T/^ATKIBllJS$Z9-_!Y7[/`<Ao\GJT>QWbd]X9K274$"[1K.<(j;7 h=::Sm_hEn>l;kaZAnVtEV/C*f^n&At1FDY4nqJ=f=( Jnro]cA&UqH`M+Id@9h7ABJ)2&6%@#bbRJG5reK9l3ndDB]KoBnB;)/t 7QPTpk@6g(?q,eF'"rBXXI_-LqfA/cYARq0Ot?ANt95D3*f>1e'#2o*D^->`HJ(@q5E ZE%&hM'okp0R\*\MAAMoAMje-0SAU)%$\&bJ]49!njTfPEA*?AS`%2ecd)A>j'@S(Sl8:@@?!]`;6o,$k#J,LI`T?.; DaUU9)#^nCkr,-I'/*g>QJ:Ol% [<1KRqcj"TD\'O&Y2<%X0(Am=7o#VXg[h9Y"@1tV5&#@--Sr.(QU.0nf]P,4MRAl7\_H7-f0 \M/l.UUg\t/jI:'Zs!r'a%^o[k8*/hA0g&Ht6L(^A6Z*l2HK$1*PAZCN5fM(G^nT\V^O";oobZb>;#1WeTQdB;9%t%E9PtXBsN'QkjAi_CK<1*do1HS$lVpatOaAWH4`.*)7mP%gFIAo:A37TFF?Deh)B-PF)QP<'8p>A-D)\GLG+o_>+O*YepW=P[b]n++Sbn)0J?@ehKoD?VSmHiK++E\;$,#?,j#Ks2a!c3_R=K-DJ7.N,8aJ(gIfsX3c2)r]W)=@e:!-CDW`AEM-UBa7/MCc\GVGa"C+pN=B6Tc)b-jcR)?`?ljG1'4XU/7j#qFqg8>@MmXD;,%mni&W6U-9%.#A#J1)j6S:qe:7HNrN9f00@"=@g+o'=bA(LB(#M2Q0#(15*,#hI=0ei7nsbYW?rl0Jh2_'m9.CLpb2f^DLI4'h;kDoen2D%[njMd*]Brq',GS%4Ti'&lri]L[^1,llHKBI#LA_]"5F,^ .G&,@/ATTj67<&QA;A\[C5bKT>p$*d"-I?X+RFd=Pcm8WOk-O(+j[0inG64`nWU)>UX2K+8r9]8s)NXL'5L)Tkn/i>P\UKVb H-#/$Rk`J%Sma#PO/=H+gBY"1PWQ]-$?O/Xn"k09lk-i+t$&aEV!:tgY?5>k?Q"f9#HmnZK!Tt$5Yck7V3c?ngJ7sn4L8'kW[U7CVAjhCb`F/Q<RU*3?kSQO83c!G]=76=C6OENoL"J>q/6rP6-eIQ[RNfOihrr%[ta3RXVhh2Nj4A2Wd&<;sYQZXpo+4Qgaocf]b 34B;59\?%Zp_8TBbO/`4g2lAm'H/2%9/;eP-0.U`[,SOYJ:SVE][itH,RW"PbZ!MgHV4%[&-9LQS^O\C?B_YL%W r1/\2l`r5r-eTKc7:jRFI[3k(Bdbk5$3E'NGeg#!Y),<%'`Q+$Zh>N! ?K0:2:H`P`H1mq9kG+',b]^`-TJ6!VDE kXq7ODPC'db<HTc8Y \?'3?CLLWB<58:Aa3G$!YP9>FaE6>YRi08]PTC*GQgeXpnS9djJ\/8B6\i^40"ZC=e[O:-^5'F#3B^MlD(j,SCA\OLt0@bK:_6]i^3/QrapY0OcsfO4F-h(n\FqE5JT[?s?qF._HG JiHBZ`;*b#m]=(2%96l#.!rYe4((6K>DN;40gp@=iV_4=@33s=!+%_Q"N.7W)Hb[_/Kfh_gAKBL*NtJ-_!U(ms5KnL`.37@`C"sO-R#rNf25)WKiB`CM'7FJ,!b9#&+:J-6pb52+F[XBQN4WZG1fJS!Z*s,JmA6[KV`g+q6pq4EAc*5!WA80f_Q[>0]2*[tA<G$Aci\tYO%Z?37[Xl-8)9(<'F7r'lO"^*"rf#h1Vi#6=TtDmi0@#5D3?=^Am`GiK"R:N7*]<"c4# ;gZsp:3<69dbiHc7CG=Gr1Kgr(rt$,e7;.(oA3C1AfXY`q6pO0%rB!M+a_AD4Pj46.O2mI@7n/Q<[@,n@t5C':,T?AN:^[P57m(nl+Ud4el*[,M2jn5!(?2'M\S*7n(EK$TqA?THdj*g"?.YM3F'\atVAkckL:E;CKEA0_!dMc3n)h\Or^A'YiLPW&I3=NL.Y+B@tATD6MJV]=j[F8N'W*nA'hWpm(^(,*p.[BYnF84Bk??ZfX7(/i3_Aj=fKl/N&#kIi8dIAM8Q5Z%.Q2A"KfX/or\San76C0)s&Dlc!MY_R+-f4A.H;'$H>os4rf+#>f;'9)t7KAqc4nj+cB9)%]UrV6P\pS abT$k>HB YaIYN]j3r[RM;I&#`T-ADV52bqOo->D'X,3R3:=f/$Le%Q#g7qb)2[]^mJ<7+%N%%!`#A'L!tQ-s?Ri??bX:etWR_)R:."<%g2VUQEe(&'H%/4k0eD,Q%g9+ %O9\0Jam:+d5.aE+):XrnrDCZ)J1MO&=)5G@`bQS[Hn#E)N_Y$j'^N[&!^N.KL!^YXKH6=JRr?)Qk$_c+N(38A=_BrTSJLh;s].,D^-)U]H!*80l@_XA]<'iCPF$#ZGM'2,JWo=MP'&Y?HlMKd;Q7L<1#U(3f%8"iSNFfh.iFXTSAJQFgYp6\B)[TI)]N\ZNti]8+$OKoF=eI"AhS.VcC?E+7I1IoFV+R`]dJqfrF#@?01]/QVYk!n2aiq3,RWOJ.d!VR&h.RRm5"C1-#hSAI1NdXhq'b.MAP#YF"Zs`R+Uq8tV[KQs!bOlAG35odc0aHh=3qirWAd"?Z6I^.4lb^XHM"'X4E=[YDbS%I9pR[.J"kY6H,)2^Gk-K9SiUN"o/S-;0_sgoNSsh+kp.GAX=J5,E>\l'$. LGU$=Q$Q..^_Y%gf5ft@6)hX;6SSVD(2ES,cA,i9;&9p;U`sirQZ[_n_QP/,lBIKpaEs9=#l+*n=cJ&3bto9DC9UN%ZWiW?l>TE26L`D%lcqQ:U_Cf*5d+3%Il0k9>Y7D[r`#pPm[8,.]EiKIIVY:jI*@tNioeS-plYcaZ3YKc^3rUr8kS$a1:Ulll&Kbcs8a)cCXO.n_/?DKneYMB_AlA"giW'AkkjhA$5#Fqo%4khT_2ABAA^QI 0JT>b/E`r!bNVVXXNG!.*]i!PVfh]MT q@rt@:%d3mG8*qq b<17hcTcU+Rk ]d#.Aj0:Sgh)R^:MN6o[R&2i,+GdVdj-0-QIngWG;N`$DBX]l)K0%n;3C)A6$N:Uqp^=2(XBb!]&AS;Y1-;)IAY(o*3,"JEAmOX O/R`(q>=0P(3`rSP?:`mR3N-#En].K6e/h>Qf6[>WT"*pK0=6cMAUgL/hR=e(%Gg"nED KptIn1S_8P(ab9M?RY#^]G\3s(^qcq-6E_K.]hRDiM"sEU\ UWV\4Q7h;[2V9Z+dj!(E+W/Fl//UFb\`QLN%>YdO90@4O96K;_:M/4)W*Kj2e,QZXo!Xq(l@6<'+L=c_?,B3VA2AS?AfU R`X js9,kLt3$GCS%21rQ9seO!e&@;3AVdl)&3s@HCfAj:H8l,UUE^*b!0Q-AL8l\:^#2+ $KLAh&@C[(Sit(tV27A*6rlR=>7>6dM5hHA8AXh](F(==jB"mT&mA],Z#nU(50e\=8lQj[Y3d\N/XQFsHs<bNM/_:Yd+-iY2O_$QG=EBqmg,[LGP[d0cAhd_aXZ]0+TYT4&`tY'*H)m!ZR[$T?^Vdp,RI;oJVfKp::cpH:\POOh>7Ye^I1aW_BoEl'B@cj'pk]]3EcShAoPXg7jqHI6!KlVl(kb1"]6W?7c>Gg!,;m4<]'.XQ[DcUA.9/UnWfWBf`-%DTS&g*O#NsfW9P#Ags_HW'$%0RpUZG&kK45VaCW@;7TSA4,[Zt,,-@b18*@BY< ,1.Z_nlhV;:SXo&TpqJGWb99j^lX^,qY>%dSGtf)M'FgMW,*c27@0]ACL4fH4HH4rejDXr_T@0IA+LW K2nA^0ZTG:[B.s5J`0 ih'!10=[:OtA*W>8Qin#'1K,OrS-,1GT!,5,+2EM("!k9RAD=M`+p";q!S76o79;Ii7g"WD^DOT$k4X7E&-mZj&GfkZa sl:G;(05#jSq1Fm"Ym9q 5K!U.G%_@Eh]=,M(c5G[+:l-/)U,)Sl*%A\$3rW$X;AOXhAX'sf*7DBTi>9skJ%GQiYSk');4L"tMK<\(HVF%E&,coajVoUP^V_T5?-!MIkCnGC-m(2`mBGWj7(5T?(9AQ )0tYgAo?&:U=Bm"7ia[?PC>0)_qWWUU>/jP(q)+OWn6LTW \gfa>^kXsO^qQlD33@qAUseAl> "FdoEpAY7jtf1mJNj0=!/sSpBU[Ghs\q4j0abhL,A"f,4U:]21a*5!N$p$&9 ]0A;EOf67e\04b.-+3d].\mAkfdhC=@.ZUgng!9dqF$7R;l7)&lE&mjN$/"E,MAsGAQY<4&AF'[s:lG JT&lO=[ck6$$TQl*B@ViB#gPRaNF:oKs?GHXm$91<\D+J#AScG\fPC_!D:5iHm0QoU3aUL? 3WB>`C]7QB]pQE,B#!]CGCK66p%EG6[8AW@"*Dm<8H2#(:Fgtae4#!&CAV*?!A,>/5j()QJid19Wap'025k,sB(-1NVt\KAlm;/6lnQ'=$EoDl(A!I^6?0JVOO@t5Xj6a]glpg`Kb$pAVC`$Z`%*t4Sr^+3%CT?H'Q8:_C9q$qeDB2G@&NAN?3"2ct2!R`J`_Rdk<[2?#'4I-&eWNbEcH5O^A<,45kbAJTng5cjY3a$@#"7D>DgbL_oY[>2N<37$)A1o52B\fR mdT>'igh2Ij)VtGBU\6;<?g$APIHf EQd)f%VgQ0 &cdkjm\W@4KrXW09na.=?s?6\fF8f#<A5dDVV:peYQf+2i`FH2l+5VNKe+JM2i>d6C"t`L5eqC[KAaP4XPLQKYB?Dhmo?,Ul3(f]AdVF6E,#4?N;@+d[fAH`GcpAl j %m>5q\/=_HrDnj(S=l)gqNXXt5i3tOl$/3P!5&dINtg7XbOR)ngTV^`f1!#/[-;Jp%Jf$@9VtfOQbhA%%AbJ-$@/Tgf#p9ndpjVhjT:L0e`lJABr5<-&Mo/+m9:.)>SZ*%LXfiJLOT2g)HM,+D[U=7hAO:oLej8=eg7#`TK/@FFm8/l M"oXQAgoEK(]IfTt16t]=Cc9t1RKc+1B9ZHU9B+Xi:j^Mdh;3QkL42'MUp$ke?IdFVP@'>-W[PqLNLQ>P[P8Y-,ZtJ.2rlLo:pb1AXoKt^Ql]OTo/5DMrp_DDiAi#Aj0];_#:9LB]2%Fd4ni(*BrD=7D*MfeX"aF*0o]Tb<4mN;!J"N#g.Z'8p>8AAqrY0< d*PTA_9JA6<^^cW(E2g_,.O]B8XRHc9 g_1A)f(*o^=.TQqIGp1>6[Hhbk"I"rJ'D3Gs2*IA*['9aiT%<#+UB@_Y!IL/`k: GSk7YW[">kK=YP[aj8^X<`&?;*189@+ 5A!';)=k!n@&>K 99BErIqF^-HYH(tsdRoAD,-B>2K]@SkUBhFWd7/7L>ABL-6[Ai_!!X9khq_IRcMM<_$/Y]rBa@t+ab/`maX2JBXqApHG[0>sq@o]A-"EY7f&\VPn)A(%H65WEo.?d>CJBMnB/sEDOU&6_OtY,.)QE?j-`;qF[MQN?[%l(8M6)6(50.^^!8!GPGer__c-dA:TU]Jd)K\ oC+,0tIjPR9:Y&jMEk+E'p Z?-S?>Mb6eb3(j[+8^-Il=2<#/OH2hT0k>Z0[[ssS% jc&jJDqIj05q 2H)_4:tIeX,9O#k<@3j_kI(\mG`MJRJ&lq6Rlbn(Z(iXCLs3W=D`7O=%qE/a3L@rF,2 LHMlOd/+O85Kf%FH:Z5th-l%DNoKcPk6qHA0 SR`ng%p*^tf^hl;pQaHdRsaNiPIa%H$Fj['!_2IARV6nks2EqA$2Fg)]/dGf?,7HMD)#;=[es(W=gOOrQc%Afp+'Mh<1#3mV71a0a`R(b0BEm%H1H-j-YNWd338:"\d khVYX$npa2m\'p,$/C/,iPijo\,'$+)$VA>fX(BI=5L$Aq9U3j6gQ#&A1,V]="AX["74tC$$h:@12L8BIYH#2`h>#p)8,PeYJR%Ji?f,8aH!N6oQ)I%_d[+0aE$a--fXo"o?P-J/5T4&& Q]@ZH<1hindE]&N?!fBjUs Nt6>.(*Il"`3bH2M;,X[_-tGAY-or<3jPBii^BRB6e\_]%/='Qm?YO=BmQ;\o>6CXb _jV-p9Gi32@">$<__8(mV-2onU;SI4D1 @+7H%d3Na;"0MRd( Ip'GR;Y9-U+%tN;VZVe!C ;DKo"FH69j$OM:8![&VrKWlmb`m )W_hT7m1Ki"lERR )P 7Roe/E5T+Yr6 aF/*4\VFg?),8H'0<19moRd.P:>;:37Eq)PLcE(m+c2_i`L9Et+a[%QA#dhT20^;fq4Pi.b+dYh.fnaQ`K&_s$;7+2DK=G2sBY=Q]D05AOSgkW;gMpJk]/^e_8Y'HTa@hQ_4 F4k[Q.X.gH9,Z]MBh:@O,%m1<&&%q87meWipq8,BTSRh1jn2Tg]tJPjU4(J]$PGCb!jCYjt(=e51DQ:%4ce_e#61K!brrMtO0K^)Uc+qA:"bj:P0d-9HL2oj%72HJGJ^@Q)m7A(eMC"AM3CHg-@6plUUiJ-$M]0V!>^E?\M`Apcf&@YKq33(Xm]O`:ARIe@QAfsF!.QnrZ1"11A;ioWci%j3rETcn.?8[-b!^Am39b''D _kt,;D&^\moFpEbaFQk.iL0gsh!7`g=!=Z2mIS/Xi%A,sJQnE^o"642#0$%?"&5of9d<..7 $![*BQ#DhFerH@#oL*K2[oPr=8.pr>,Y%l=Aqar\;_UVZ]YBDO[IjF*M^YB;>ecZ@OO`!t#!jV7C%;bAtf%:gnfgDhkb"B=_pYmF6%WE@_2gV9-+<$cCNL]oAaM&5)m.GrSno/+>Q:^f&POh#KblmSf`3WtZo8.\TS[.6GLB+a6"%m3m38>n@KU\K90Aqn5j+,`"\F9Ya%\@qpK=Sa<T!33fYi=[2jmA,/$ r0a.C".=aZK@q$$ Ecg_kl.5^Q'Se;=/UT.age >g3km P9- 2,^RpC[q?9r[:m GcQJ/.M$OO&b.r! /X b.[_\moe/C-kSpon'7eK.g\Apt]612!=B7BS+)h*MY.9Y5Nq'5l\?%6[Np&!o\7!B)6]O#nDP,MJ-/F4PKCL46[EXg->I`nje*+1EJQ4_Z!W?98AD0t">@J1S4" 6DnV-?T*r"MH`!$Ec6VU)2gH##7P !/.Z';K8R1Ns/$0A10KQ9RTd/nel7AndJRfEAf24+#[C/c,WeEn4/Ws ALN+QJ!Q5;ib-Ucl5>O\%0//.fFi\S,c)%,K!,Y_6n0^nD5k\;nmbSLf_l <Yf.cs"o#gAZhK'SBW1-'&q:@-p65!GQ_&Uo!mN:kRl\=8_8HQLX1TaOANa/?(8NtU#i<^T!&ABOS9:^:PULc"ghLa6<9ms-QL'E0UWUbYIQ<.hIbP]JA8qgb17+l)shX(Lt8D.8?d+tq$Ym3bGk9Ng(Jq nOlf=C#O9+Q:k^cE=,]+c^T2UY$GmPqRK:1qdH&eH\b%N#0d#%P=%5Y@pUa(m3J=^.OU97naP_H^Q6=X5VgnEB\Rc\R]_rPPF +CjPJNLVfJ(^M9:L>C:RaAblU+[7UAfQHWP+q.`rT,PLWD)<8PB LH@<*lanqM=l/.\OkXJEFFV0tA#2'o,Bt7#PZ:bb3q0To=)S%N&rL30f.Id4o,3Ie1Vt= '^'3'^i9psXE\M"MS\,?S-Z nG8[C&V5TMabH4XVi9Gb.GMCP"D*ma7(#;nIn(WfG*hp;_2HsUF#GUd#=&7XL`[sVMi%j2)/-:->AUAHiQE"GXQfp5Z^@TKQ)YJ3E,)!AFb\IW#ETD$NZ(<;)L4D#Lofa=)(G7QR MNZ'[)?*"K f3teIhHA&A+Z;gN(2Db^A,M9Ak7 92o5EOtEhe%H4AC">Bob^kO_ o2)`2'1Y81je?]k_Pn]cY&sg\pb?c]"_ERiNa(5Ih$?aj`>or.b 9ef3`lX+^WpEDP"sAK7E`R?t*R]""hf\a.5ch9@FNE/k`-d$lO4,S"PLKkFo6pmpNX?-!.fN,?rMeIA5;^:m5AKA3h=<m6>XqIRgrkS!XW/W]RtKDUVtY?/Hg% ^A_#tU`%HI7`O;:=fi;CO]t&+=cWkkO= qW<&>Gn4DbX%WG^@LMiOA:DM?F_noP0[ti4p=eb=jUlQr-%?=tI_*h;j,FGg6n'[1+/YL2e%XQ%5Za?H1 FijKT=bQnh)Y,L5jJ'i(CiWe@k V3I(3\..UG^D,1c$8'^E"d1&OPb3+b;9'"4XIGCYW"3rc@7dn!lHr2NVI#-@GlePX,B^-/%GM_?AWi>=UO42JZtbN[=hB:__5lCt+\W_,4ABdQ,*aU V]ZJ8>7g\=L>KWe>'!C?6+Z)-0jRE&CA-Rps5K(70Sl1roE&LBrla.XhSmI\UtL1mcQ8be+cl4S+-aTsWbdr#fJIVl37Ap$.$"jJ;B'nQGQWIXlTh:(\9L1\kq'h3B9nm5h?D0F6"mHe:8WfR,:FZ`?B:Ls;/A *\FIk_&W!4'B[q=eqCG O74/*A)T;>1s$\fnot$3M/YYiY]U*S2808n3Qfk!F=@lZ=D(\N6ZeFj+6"g!$.Q,J*0,IO@Xc0m+/P )6J-K_8@A,(]XdT]DQ5NdUq)2]a ARkg"jCl.Chf?;X+#Pf4UtXtT_%I$L7&;t.4dr3A^eWFCM(l0]BHnG"r<_ ]3+&RcIbb4/sFEg=Jlo ZO+@;_]qG09Pf/iN+o*njqQ*]V6NkkH=o).iL/N(eaS[;Fm37b]/hhD9e)Akf;iWg:Y@#=RI`ke$N(M8/Vh[ih9YeB/kE/]6ISo:h>t4PVNP#d/I0jN]q0-]U0)5RK/B8E\ D6.O$J"^tm">HrScj`3pl/G<h+mG%\Ki2JHQ[&VaN/R2qUiXES^'\*L5AIV9;I/Kj>@m[_tl7LZ"K_V*9_:toSt`Jb&HKZ59Jd)M.U=2L*MK#RK]D+k_1O \rN$SjGgbPH6c4q&940efHh`_6pfr<`;mZ!+'%QF #Z"NL;b2tObIKb,oX_<]5?L:4H@.:^?Yr1N0XKrflHFe08O8iAoC&%_]5 rGLQ:;+];W-d5Xd\m@cMfo]n$$nbFR$D=!*sFI9g=t:UA9pGhX;Z_"G-j[XieTA@N8=8)$VV R#seSQ/-OO1g@ho:05*ZgY?=F$L$8FZ7isK[`M[P"#r9.8ij22-VnZmCmT;Zkg]fT_D= kCt`_MU#4HfD)7#QWf8 nfIKPKFK$lS=$n!\5YB)*/2<)1iAU2"8;OGU*M*j%A `i?USbJHUGmrenT3\=<k-J23`n `r\71d3Z3qp<;*oA2Vh,rd2A5/0%BM18]8j_!QkDN#6oTX?E9E?bcPpA$A*VO!nd3?Apg60\[o"++YAJEYigSs'(p9adY[0>#]A3NM$AnIAo J9E];p^10fG?g./pNe&$.o>&o>1eI/e &n^0m'Jc8eYdG*AX4lLWg9eAJ/d5;Kh-T'O%I\0)\("66bIG"5+2D@,C*tf#)_]ElQom_j%%ndqP2i]esMMcetM<`?5+P>K\?9?A=$*OQ#UA]\b[o+diY#>"0g8S]475sOa,-^)"nRcF+)ALo_FpEA,+/j/5!/4pR l<^g,NCj)eD]OW,-T93p+T<*e++H.#Y=/HAmhBtKs!7jc`pf6kV1aEA( 5B]9KBeVop.NV(:%GT.b.Fe`RcrX$-]aYZn$m@4t`7n[GVNm=i`0sP_$[;,2q=_4QW @bTWV`dCb8<^hcrBaqNB59ERMDEP[ps"4lRM0R<50k>osK$U0s's3A_n`1]6igsA1W1PiqsF3X'ccZ/9AO,YBP%m]q7N&+Vbcbr8_b7X8&n<3mbD/."]38%>p=Y!s1PhSV5ld+qO2oK/t"D2mgS)r="TmFF0^5 49)qG-GBn/k X`[J,nI/.>Wf,Cm'mI7B9\PX=.J]00CBkj)IoSG%isn6.K`cS4.rX-c#`.IPfP:I2Zo3'F5Ybo7Q4.24%+:1Z#CiiK(Mf9,>VBh'qphp%]56afof\X;UXnqL5&qT*f?%g2RT5AL R $j!.baUTI57,H7"[m:A0g;KjN,g9X%4bZl,f=nQ6.r;$'2=('\pb5&1hAfB"A1!F2!Ig>M5`Si;dk' Larm2<:[GRk%D6WCL_%K*to=+]RhCCqb(\EZE#.XU\geYpA]Q-S\Z24Pf(.FI9NopAptQ_94Fm#:kFBj;DW'K$a3tAnF3#oY<%EEiskpRq-"q_sPeHPIZ]O7E5E40TMV q3kU MNVRlRYRWI?tLlsb!A&-ZQ2Q0:j'AnA^NC*_N#Knf%+RO6EWS5b&s+hp9n7Jjt`NBHoTa5>*$C=q5=Zt[*jhRQRYX^#NaPfE;WB>NYk'PELnsn5.a N(8QWAa@VpQYUMO."U_U'j7XFVr]T ?Pk[HDbi6$Y8)8Jm8ahPI^3]$lLeRte_fA7VA.._H-GcAtMsC%$k&Er5QY>] $eLqENb)rRA&]"L^!0p dUK!l1NUh9N\@1rS1MiGSN4r&B\Y59U38)E+C:[(=bi)ieLR?jTRY;6,f%A#^(qC%j&2:[bDN:o*thZI,HHk7`?o'WbA=$TfEnGj3&^@<MrOK8LZsF/ie %+87>agOQJcpQ-[)W?IgsXO4Yl0h;fnKaDU5oI&FdiOeC$S2=p\SPR2C.pdn M[.65Y:b",dsJQ;acF=pP P)Q=OZ3N3@kMp\GdI4a7DUF-\r=^^jJcK.V26Ul#2>=A260Y8P&,g&aYR^fIh(rV5dRt;IcInk8E\Va:++%D<+1ETI>_:#"mjF/k(SYr0 +-@.+mWLM\=p)%XBFN/#Ao5MX7>$BFYkq`<7O9[;nXPLO)Fm$h!)[O6V(/hraN_=1m4o1q6benTM+U-FWJSEtI$&UKQ69cA;Cf5qOaE\A$B$0W'ns/F1lJ3]sl"q`T#b)o6@CGfs3N+i#R@*dsA;bicGN3I`ABl0pN1[UA0HKOa(RKdS,>o`R>?r-D'hWG]iTIAA&GJ_T)!`0I$Qe9MH[]3Ar33D4nd5(g><^5 H8-U_0 5c')PJdA73oOW?I],hh3C1.m3Z?:AcWU=p&7P!<^>Es_NeEiN-!$S1=r6/4WA@`LamN!o7>Am%Z@"\fn*O8IqFGp3fr6SGN*6BC/`R?> bt\R3+3K`2"C&AbU?>pk4]+MjSTrHs(F-Y.S4[9[ZL\@$IIB[W, 5.AWBXqJ9`,9 /k2)G PXeir$/jEdp^rdN&A JfUa(;<6\4/`_^OkN91CJ*dc#bjc^31p*Idd@hkSj3)Ft^P"oI*Rf%OlZI8n):UC`R9M%Yd$>"]25-_,o9"[bNAm7!@4HeP/9@O>rR]HGHhJmqr$Wnh@:Uc6\9.bB7/-QN,3le@Zk.T"#O#;g8[lU&3J>U^G;emN)b7gHi*^i,h(^I6riL0q>V6%ON$[5 VU#k#O&KGXUBAoi":>TKBbOld8Cp7Z*QedV!)qEp;GeRmL#0L1t)Bg*SEp9ZFWDZ!pof[[tfifAtE'[_M2ODcYe8G-QP\%`JimAQM'2=bQhXtt.=]a\17:QZ]>^[KgnAgU=HPk0\Jl2\L7=c`E.=*?kij%`@&C6fFG73qHg$%KAP6r4CFOi;7G^Y`3i[2Y>Ub&rLr7mp1>Y,F"]_0G!b*/(rC$Lk5F%`'BHD%AU-s%oSq[Ti-#[&^0Hr^j4b^+d@1)J'onFnf"KL5;Ar=Eo>,"#>TGm_(Z\/M>JXZn!-i,;&[Tg\`TqnFRTTAR[7%@_C^kA_nfNXs's!f*G;-ZW=,/%mfR?p70-Q-iA`"Z4:qM0SX?tB?ao1,O%ZS4aTe4[_(P6*g&7,DPj%DKp]oDtlZn9sgcK&jaFE`TjQ[B]05&\E^n4@e*hA]ZnnhoEA.sX\MJ%aNJ]NQB3WH]`[6d!$[m X ?XZmc41Hj3A`gd\,XKf#X)oCp7pgFt*OtSUEe>SdPD`.X;b)JaNA\^n$Hqq^Mh3_r?+eHn,8$5)cDH)M-!eWgOZ(]mlh`AJ^,tDp/$$J&;pH\%^\Y[API^i+AHK/i,3?26(PW55Hd0RC0VVPF?@Af?AViM.k brkN5LA3M?g_dD+(b8.tq,2S"F* Xtj.VbXlpKtTmP,mHh`)HLeXP#tpcBeZg-K)tlqbaXl'!E9%Ejo9P?0<=T;,ANC"5Bn#^H]?-d9!Se'+mp&o6YR(m25k2Rf@`CFUD[kdAQtj'I%NmQ/`W,BFdMG;;P%XaZN@D_.TTS5KfG3W]br<.]YjY'k.V+O#[0l1O &#g6C5AM(#_I.*\F.No3^C#s6][S8\MYs[iG2I2dPPG]W5JAVklQg_EG25j7`I'(jKo'IQ?0D]L#X,pf6=-RSB9j),A@6.+@#EM(_esBY)5>PX^L]&F"fgaFS]2TBfVJ*BEc9@>K%D#:>Hk9R#n8Hj;n8F]:;Et8UD)ArC:15Q0+1snt3Dj&\P.<q6r-@S%abjA)K6qe*+\#tIlsb=DQjS=.[[OD;&k;T70#&X$'A,>W/bPTOr&dUS..Z1GQK*KA(X%%$k/md0ZmN+E21iLMiJK'GFdS'@5L5!$j!JD#hJ>9s#UsqU':$(#)!NoWq*k$=hsXj=n`,AA6AAP"]Ak*5_P>0.VRZcP.A?0]$^P.94Xps^Me753/ONH_i*`*7oG)l!g8CGG%=1-fH^BIU_t\#?Fs);Gf('Xbae<<=:l)j#h\e;rY.ZU#F!N-:o.1-<$Qk. /M!rbGAc&r%=Vj&_,i-+M-"G]fX@1Aj#j7J+$/5hfbHUOA>bmb(7]@+jYCNCg>B>9M;0#rCq5oZ]r9@hb$e$R:P"+2D,'J '"ps:gb'TGEc@'t;"4DJ^k6aM-)(E*pScW4dAq%?Yr^,[!`.FW3q?^6aF40AYUWn,GM$Q3ZN.a2Oi).1P$>s008oRAV$XmF(!X:HeF:EJ`E$tnj,RSAR(`(Z_2"=A,)WE(j65.=r-3t&6b4[>/EQ5Iii1OBA:o;''k6q3W$N"+DnJgNKN^2%:[Zk="Xpn[f@7#GLKdFi<[>ZO"Y@ 7R#Vn5DNP]kl.6?QX<]JJ>"U(G>6;TV,'>X`N/>^<6e]Y=rEG/maO*SWSH5cMYhpfT:%TC3TAgm[aO&f2R"WSX39mtB)ED:`;-;W*7?*Oa6_I0YY[HPeFAsQ'A"5s_f'H^%BUN]1f\] ?p9LX+lWWreE"PZ].Ef7Qe2P?s6-^$t&'T&[0,EaBKthk\9*AlDW$s)CS[Qlib6-r[q@UshcoJBUc7ndrtbQPM2K#CBm6SI,i&A5:]>C +4_ZC#R%:mKOq0$FmMCUeP!Hg^Jr8P:% ?e%Jq19AG.\OAbFGV*\B9Y.?j98=S=bJQVrOjV&hHGTf+kj6@%%l$El[B-U85[bg""pjC6;r4Ya[dN`#[N/$1\YfI*l:DiL%?#N`9AHh6A2rLr(Vhc$[Z*C^U?SM1I86hto\\Tb6@UsglAIo%L\"lbh>h]G8/s+4)a *4olRYgfXB,!]:BDb=DA)ICp#)6c!BZ\])'K>PAX$,'0]5^E-ZI>MGac F)Jp9mi=rhr"%n[W*BMPIHkU"_:]Y?P*\N]AfdGkR?HEoOn&Ge9)BkUjH ENcm,MV:EP?QB>0B!SCDoBWb%I[A"8A7Ii5A2A)>e;ViJ#bC1XQ.g9jqLAO$nQe'g@ISjnFkg\t\Q^EVg:e(XaU-AT2,Xe.%D-g`W$PFDP7c_C1ln8Ui]pp@U*/2)'lc3Q>J$_5Nl%.a.=1<<46LR:WBdA2ETem5-^'p[6G_n;\gN=)N@E0DP>kfn!_46eMq`2Di4(K;+1G,X*!KZ'&(Gs6IdK_c<4n)p'gP.K!hp%g2+'pAHPdX.kq4.H10aO($ns)&JtK:2?^X=L$T!nd`:oHb$,O/$PM1 hGkFY5mi"^ZHKFN<0*\0rkWB[()Fg.1'^8pd#G`sA!X'r,o0[eiF^CM%G0pmYKKHg%gIWJ I1']6cLlFKg5nW:&:ofb+Ejk&naPs3iQBTG7H`.UDg;n'<38XtqH6-NX!5rG*h`n>r@'`.c9&F"eG+A?3G![`;O%*LiB;koOJt3a,\aG9L??iGc?RF,Y9)FH 19=WQT0W_bU -:J/!3Q(R5f! gD9&5HK,$B=d)1i-#,bT9Me9+PEY4*#Lo#bK6(ADp+_8MLO0!R/esc`#W/,ksGpTGJd1k0Zl8dk"LrEPI;`VfF"&]`bl<$9A`NPBAqEV91:IH4-mH-b$?W7oHKX.07\hlj]G`&QBi 4R@+l16$ T&P7KhnF_LKNG;DtSR&ch&;j$&828OT==(BMt,/WGBil%iW*j,HZ=HRO.TSV7m`>kbWTo9P$;l#2;spkK\j>E3?h-ZpNH!:&50TC]\&0-%hiHeZf4j<39n1e_Bl^+JhkBJA? DAatMI%1rZ(YF C_c!2D+_`t+kAFF=9@S)fjBPD8L]Oj6%J"5A S`4(OidbFqk",r-O N^g9j$C7Io9^!]KZk"s:m#90bM]D5E)js"Qa9+lk'Xb+ONY=,(-1 4aA6OgC(qdOV^"N] $AhU-9&2Kd;^UM9K`7$6.W3F1Fc\sp]/%]rG-Fk-(jj1qNr,5 5QqnA]@A[Nt/&0U1?eA?A[r6&Bk3,DjS17B@g4o[6Z3lAT>PXK"MG1fl`U27L-7IRk-//*\ k+6OJC1M;X:XY?s9-VjH*AOQ%QGK#o]bm$,`hQN&$0QF_.-(2`$"cbE0jQrH7pWZ99Z#%]*s&i/ctQ?r\9K%gjYMg!ZB48"q/q+n.fW6'*`0D3]gGFQj-B2X`&e&*Md%lgf-2:>lk1AH7h5>6pL3p"PSO)^)!=/?7(S:5%fpb<.]"!frm;o5/.qtpr4G,=Et+A"-_VS:Q2Ph&A#?p*FVUi9OPj)sYJK/d#Pj6ZU =gXMCK?h$WTY:#JjN=AA]K.dZY,B;AGO56C(c'g]$P-(\/DF*X"/jl96JA+gJn>l;]RdWp6jH#pNdt'1U7^4qgNl7K#O;PA&\;1a/s*,PmG$BZj6L,5+dO^Hq($;\je4;`5`D<"Y0-[o1_6\r.AF.emOM71,=T])=4RlPMa5g6.)mheX*t6)M7cVKQ8LV!BEd$R<. h2GqHFC0Ns+s?JYeXAt"C=H(apc;]J0pAnML& $Ma55qhEp&k=:9n7mPTOA7P8rS_E%an7;M^(:aY,D`U?3YH*^Zh)^na=bkW@JOo&f?E\qNC+Z(ck7%Z/r8F]c]M/si't?:2I@;o2?FT8O1,iGhM9Lc/^EB5lUKa-Ilj_f'b?KH6U)A&A:YnG.k8;.gc#iYhU/5PKO*2CkC)A=Wm9hAF[I?7rA=J;Mjb'9n-nQ7c?_Q/$L[VOe^_q;%%t)@\A;G&r3E1-Ce6hG(sYt9)qtJhs!gjpPa5H=Y^sj`7M:3l')69]7h/>Oo !E]7oAFhAf]O h<=)V+74ipr4'OWir3bB(rp](X@B9(j>O)&UV29,=r`\E\pgD6aLVO@4]p=QrA^d"48KtpS=JAXLU'U)FVN4mQ2helEl]%kf L/aPr4R57HoT+(JOA?Of>:BQ_fEV==N#Y=D-!jeEcm"U,a7HE!AI#Ap=c=p!?jq8rl("H/m*:3iN*+YI"cm?&!;ESGIao< +`8Uj!FAiL+r+lD(oh(\G\U<-mb>Zso$QRskn#&=QLl+)M\&D,mmcP(G.V@Q&\l6]%WSNUaJ1\EV+-Mo,H)f0c<Z$>@?=/-?hU\8n T8 9o4M.!^]X%i5VV7kL[l$UT4?D!aJH!:Lp`MgXJE_2LYVSA0s%P-a0[p596d%s %V!@0t5O#e(+ `E@" X[B >tQ>ai%n/D=:Oi&@%,Va'npZ so4N$!)k,_h4mpg ClW+6jrf^rt@\7:L0AUVG6j30g+Dmda`I*AcG[r-J^]S5ER:L ([\ 'Oj^$!PT^/K%qWl&^VLV@'Zq`WcbF+tL`M E#RJfj27.I$rC_hh.W==$s>Wo^8U<`3p'\)>6#:Kmt[IS;/FA1c3MOO;15qR\k%b74fT`^j8NQ]kbs%N.5k2))oGJ]GVe\gY">Cj+cc^:RgbqaGOG7*aPjU=4I1h8%Ym&)O/^UdMO]s_i4aCp&:Z8C2`R2BDAj['ZE(bY 423me^/KaMH04tC(Q>3 V fiIpUX>EKdp_.bCc2AWW\Tk>?KA-Z&jX$iQ/*iZO#HFd1:SrVX#E[ZkG.3hbt@*r44i4&XC/K]9%?Hs3caUV+&fIqI21*h4nnW4tVD&tVK44p];U,Y;LsLM8&>4l3r.:'YiW>)q2=K^!3h9O29F_m40jW7Bi##fM1^DnJ5oWrN_O:d;&SX=e=Erqo;JHn\o9CD00qVpT4IjMA`r1')8JY,(p8d5FAb1ERtAsArdH+)1!>c/As.1Af4q,Ads//k1^V%4q1htP*"KAAU$:8Tl#Xp' SY7!a0h)GrV2.g'JmbYRLO)LRA<4b>"`LY([l!QIeWG; gd,hdog "Y`#g+M:b_O0"\.f9E"1'O*o'eML4nD@:ARo5/G>7[rpTP\i:7 tU!rb#sBA4EEN)o)Ni[ ;2/-_A>F%U)GMj c[_s18UoP6k-A-t@"aN/KX9cA'Bp'hAc3Zp'i.O(iH=o4b5JRt6&`C\RE8D<.*KA_2fRf-IR?<aDo#7oeI+ @cbq@6QnaPeG+q@RXQSS,A2]J:ce.[VMq-8H$dJ2?YPGfr,$a6gXYkkZKCoEYMCe*HFbQCgYn$GfFr6ELPGH=QF7g%p;aj)dPeUmISchF\"]6P'FAH0f7iDjao-n'[qXI"PT4la?DUfc9k?'m.-N\i_:dC6/'UfH8BSZ!rAAd/+58iD,\I;#"kZ-NoUr$*li&@'0d W'RnmA%&+R^lS]WQABo2P3P^#>;>N;G2K-fTeXB%;%8fn;A,Q%%ns?><8o *QJF]rt7:1#[loX+;0\@"RL&[*9+.d^2Oa+2cc<d?\&kY;#g&CC`ik)@6F&mP/(#7>$(O>kMPCp3&$1aAV&(-aL^I$QM6?5UnJ"@]_Vs dBbJl_681=,g7pNAcVD@6MFFR+p=Na^QKhb5" m)1P&9d](6!0QB;@ZNN"[^RIGq?dteA/H&Wg?!NmJj)n9j?;Xrn)A.G000"[?bIi982-n6rAf`gnb]Li9_pD_00p\O!VJD#RJ:SM7,.OBk$a+/%ehlgR/`-a,3Dl[6U437I(g-dFm?3a,"0WAS`MSdckj;^91A,DS_jlfSnr'NBPn9An^:<>2,tT%e2IF?MH:%T:om3@b-H's/A8hT+",Ho@<0.:MHts;XK](7P9ro#NaFHsR6n#Sgd#56*RM+t95gWAo6;/RK5Z\\kSam[(9@)/;_!H]eXco]q3+hUF Op8eZt4 `OKe+LDOF]qTMDnY9!M@Fo_i2LFLsTlnM@cqcl(t*a/Sd$Vl@8Jj;a*@diN/...8;bboWLH ";eFtsQ3!S/U;]UA_n@+n2://?H"OZg!t/8BY18p7HCLq,]h/O$M^XNV[]B$!2mKZ&Dp#0dPk1lc\9`"OC!j^ KqIoc#/s\GAfsW18)-XA8fkOT7W;_BJGar%p`pQGl->3%W;3kb`NBh;jlPKtiT?opK"Z)m#(?2jYIt;c_Gi=m)noCh3nM,MURUo'"-A@Q$E!/YanjTG)F'>lV I!6D:6iX]8;[">h:$aQZt[I8J5b5ha'':)oK';Ah",Zk)mj)$IJ]53kP\9%bPcf2q1>J q;4c/b7U 3]5<Ji*PH&"e!2&i%s,PV&:+mM&gT^osaiZ BA6 jIsjqOJs[*'2pJWZ2?!MPBB[No_QWpD*8=41&0ikriorRAi3[QaID5ki5@SIKL-P7`a h9FWc./jQndQ3gC&mb&>EHe(m;rHk*JWSC `[`6o'U#MGFW+=#%]>gYQda..\Uai?714@2"n`26b5N]AKfOa"@himgc:Cf-?$K3*Na%'2P$R)OmJ48%&[i6c?+#f4@t?A!jBGktEl?gF^"=rbPBle;s0WfFpiWKpOO;#/5`\Qnghr'\0&QMbrZYB2nrrB"E?n9@F;/:;!H:/a5`YB4"L%+ Vs)6n^F'R\fA(C^n3f:AM"`+!#Pr*!k='5ZS'<lt8a0qpkHDcUiL')5+0S6>Ka-B!S]7\]W5DnaQZLXfeT0+l:PR6l[ZhB<6p2m#$XUl4K=-00dVAat_b371"\eYVPe+kK'?gFA9T;PAG5SFqN%;Jl.&FP&G?KG?`X,hdZQr"3)D#.ZrP&"eFHP4\>,>A9e_M@,51:Oc6,Z*`m?k]Ej@9B/l1e[/NSA#/PDK`+R^Z0:[$_9=1R,$!PhSOY_#c0\<;"J$tt:>s.0Vn\L.V07Han]b4!Ti"d,M%5)AC(8JohVLR5qJkkhB 1 4h:t()$A0d4>=k`nS$<^*T`,?-#4Lb/A/HC7Jfnt$Ys;@p6%%ofb1eg1d*[Ob%,S?DP#"[2Vt3,D[A'')R>XQief!P!GT>PaSE4cD&5d2D B=1b-*9`kAinr6pYq7QA']!%JA\b;QE&-B%76m*3T 1d[lW@nf(o(264V s];P]5A=;Ad#a2BsM1>oF^A+ 0fTQg]\ofTp`<&_e[A>YYFAo7b%#?\QUVS]l^AQ7@a2>WDBm&T)[CkA)H>h7q(m4)-Ilf6Ah%*rZ&Od!"no"AFLQFg\]ODV+j+_/Y#%c7fLZHD*USnfmKn=W+J%Y>\$H]]a&eIRgLgm36@KthJp)6^6r:AcJjicCR+dJZ)8AmNFH^MkSoG9G72Wq"oRn8bM+4Sj0Drg&)b<9s>+SJ:H!+B:.R$rCl%@r*8VGd7lmX[/Bp(\nhtU9No7OG%Z.n%!t40&=RA);(h&2re#QVjaI">Ie+&DpW"%44A@l$_?P*S.q#Kp;-?\1<n0S,C+^h;RfAG;@KdcrCfFcYOl3+DW!+89kD$>`((G9c\?G(O%^A6I1(%j"6_;(h-oS05i*]PVsl!B1bGr+,#F9B"Trdq2\#rXiV>&q8BTf8)ZPl`P[0dd&chG=?GiW-LC80L`6GP8/sf:S\/7CJ_,`sU!VeToliSQ4)oN,E2CjEt96D'A'$Jf_GHlPW05caah,O.?AjL3EcW0 U7,qU-E!pKce(2/0`8"77bgBQ*"q2Gh.+[@.E"tn=X0[h%CU1g?Bk&,>2d7nS5qtU!%?b:3<7O[!Ym;Ws&F.bq$$8V/-@D38X*<\46*T VX7rg$cCG?#W9 =CEi(:AYk38OAHBbo@6gPSM\)FF29a!l6U9A9iFq..l=45o23O-Y"ql1KW?!;O=7TFBdokoT5s(XkbBoRGs7pZ[s]k;;'`i*2olK%K6=]eapN&*G/A30`..,U+_n+;Qai_1\t[4%iXHT''ABsqHAWO4c7(!sY7@DAt>rS^`LJKmC)62:KCh!L>1>M0Zplodd..Kd9 U^c=h)_c0->jP=W+9Ip=c3q]Vo93^ZMQOG:!#ikFbN[dV0*+sK]A"q^V?e2?YbA;()aF5od-c;Uj:(.d/$C=\o-lHB)4+0KiAr`>Y%A$A47US3H9Ml!/i1I=&!Gsn4T6qY/N1Qio+m$p9'F:VhR q&B>XDo6'$>e6pdh*WYB7[5`k^"HtY)0?V]2_>BWto!K599ds]mUt,1KOt=3B!lcQ'E,>I"A?O`@9qMec$5$U-5\3pE:TQ7F9+]!"p`K=ek@>,dC#O/$8BpkYbVL\*6Wi8f2o,;VLS@RHr(]NkRQnk?8IL0oKLj'*N\Vrq:AN)aZ!"i;e(D(`*F:_.$f',ZEg]NdGT*S.:A6PkGf0?/@dmLP^A) Jh3rjQ0-kZ@OA^T41[DLG)O0Jtg'A#G+c2^X>l8g]1A\lB*)c&bnG8imS[ocBS.AXL%K^ .*L2`,CUAE.'DkbK4LZ_@)4MZS:Wlk('RHFUO&WsM;tK5fL5dm<-G_tmh><M48CSG#aDd =eP*OC;Sr6-64e74'>aA/"Rn>e-@cKaUr#`D"A%Bp2)>#0 Y-=s-jr:ita j_jD`jN+i(GL@)Cm%o@Afc`c$66HAt[k5gOGJt-=tA9q;%*^5$1[C24!O=7p0LB8c6EQ:bpii++fSJsNl3$mN#K[2eL#%d>c<39pV55VfO? t5a5 >+g-X9Yc=es5sI-ts)A9R5TqE?/<M.C8Zl ^n"s`BDQp*W@oVW;]I'.h/b1:4!=.W%/01LcYF7=Um1(.GNWiH:Kp?Ch12Bg[5M`,TTE5TN\pba^I;oM2Z*KqR@#RqN\;Cb99`H0d5^K*=fJ<]%Sd>i1hpA>313bbb#MCtA</sM^aXko^.Z7+VJ+(EYJgJ;j*\%5@13(Wd^;PcjC44A  I$8,VM>Eg2T*ancMc.8]W(7%'g.#VpQC!2AZ(0oW12mIhnJ-G]D;Q6OF(eon*,UL_H'UE 4Y? 1?_,2ia$K^X?R hhS3!R5BC,T>@#rs1 gF*lPf8,*cCi:nAaE%*,qP_ofK]hZ@>cQ?A;,EH7fU]GR2p25#UA$.oE5/ETshg=9Vk_;RC#<^nK?)PKL(YCWdtBChB*T>[%;/@Rq[Alea)>Ib^QrKHG2KcbE0mD&/'eS*tX&\8+U,Q#Zm_`8?%In$FLme]D% ()6TEs4q.E.\S$= 7iO_5W?K\UA2:WSgk?-p@=SQU#E/1!4.@--8IW]kLr"j;$TCUr,R,s7OlD-(o#dlEef9VK?'53Xq]/3-s!3B?ZOk&d'a*X1TRs$(?O`DTmX3mPX,>=,![AO/gEO^,W^00>Aq\)M=a3:U`AVleR6-Y[4qdj1Nl,gEDi']t&><6n0#)'Z0Ci.pZY$d1A4E?FrX9Blka%LHWMd ilA@#'i'db3# ]+Mf4VRQn6'nXg#E)I(8<5I&(lT5Y$1s.5[0tYd]IbLkgGlt%?^MHq!k!h'FP18>%"oqn+V?WXAK,6JP\KYb5jIJZAG 7F"0a'"A"g<61lB:'^;idCr*82Z>MEOCeHqH^Se6;OgKSWR]"Kji7'1:VI)AC"nA7mhWM*okf"4,G7hm:c6B&$3CM.8fIbb[kPX',j^&K6"IoHXPQgY>@E=HE0-$10tpQ mXol_g,-rmo11C4F3b8t;@JINZ.t#TT7eG.+CjQ&NN)IqI3hE6EF'h)!f6spqV,fm4`Hirb'7+pr8Y,NqR^eF_23mt@C3@MGAHm0d;3rY&+tsK(BK30:V]"gTpI=$ms8j*+qddro#A(Y64/i!F2PA3<9/WQX?l6QV^V&)m!C]F$@ 468?JD8p``2c.;]3mkp)Bl'X2PpYSi+[t<UF\X)=EGfr K?A/;Dgq)qD4.4c)7Y&PKg>Es^%2h ,)YbjfMA5:dYE'1)rb]]/j1?:Iq37N8f.>+UQ "f5qFFYloKPQ`I#0ZFLrgQ1WQ\:)L-6\$Q1UDgI!d,_#),YE90K^EY0*0saQnl48<1`(@3L%LshoA?:5Gd0,6/b0!pIibT2UW9c()EH0.+>aoE%`]e[:.A!9^rMan?\peDIlNkjaJiX-=gYcFoXXbTYD8+Sp8US^t0cBf3@I?<7&f 2%n9!]t9rF_flN_U)74!ghb.I!'D4n5dim##5j:?GPH_3Q;gB$j'qNk[H,%n6dc0aBl&>PN-X3J.[pNK 2S'oEm_dsA1&+b`$3h32%m)"QNiJIWX9%*49_)I&ARkIm:gM(Vh!$bI1iSC/;/efNr_`sWbT'>T;fNIJ<%NW0%A)]npAdI>\KaA[.G-8An8&VN6)A$o4,@31\];&k4*=*?pasKksN1=1l-ISJEY/_`=U]j[Td-9;(OFh(IHp70H!2kN/9to//b/_ar&/Xe9CmaqX:`X,S\^A+AQes./s'F:2ZMY :m H+3XS)l35Y]AicKV"G?4XERT;gD?+)S.0?,8X=414C$hD`@?3"Sc/s>A[bFPR^]CnN8ml`[pD$q%M,aSCC$b$#D!JN=;^9VLl>P$8s).J7tC!^LQ,c4dPAoU,M7NmQk=90>$=:&_J;s?Y$/#I^h_`%2K$[^S[7f=Oa21sm+aM=G89g8RD:KQ)pRKLf'/>$ciA'Lr7+X'%1D+6hDh@8G#+B:/_"EaEc)VPU$kLC32rR-?HCm_QlA2Qlf[@n^K'OC7CDEFI]`;C5.EQ$V0,V.<E#;<.J8PiYa`M$FYCP[8$3Dif8K'RSc@r@MF XRPUqE?nmRhVE4D<^[%5D(^.>V.t4OQ_mqq37`53H)8rAGPldR>'1DEec?"2IGY,ane;V7C:K/__[:&<dboAG@@WqJZ:3<^.ffSXTgT(X./0T_"B06!]fejtX+?"dGC#nSP\JUSFU'mS22bI#WAp\83A2T(Mah,S`@56_B\r2.1Q9=f(-6K6YZ#Gf\;o,  7.cIAMP_(5X2O("&7fr`;lO2!5=W,8`9`s/6N!+6+A!PJfWK\A< XSr6gdpo=eE!e1jqMR"ptea0A+i[Qf<Y ,)YtQ4qA7e+#E6pcFs\c^_-Q(Y3DN39tKGiOML4ZJ/]jY*6K("f?j]d5Q`"(!a6^EnhMXs-4(YR2'J@A!hV_VYI.'P,/ct:aiY%I5X*@<Xt!%`[GkeOtZa[( XBpK2#?$1UiL2i!?t8SDQ]UBEW@5SN:$qlSg'CJ>p4G44h[U)U*4s.C'ieWRf:.VF]R(Q.iRPRAi0HUFmR8GAtnR1D&03T):Hpn+RlJa>:[U<*83'R8Fr%W$]?l)KANM[Ttj gKAfib:.oo,D?jMTW<3DIFMR\io*NBBA$.9'8A6g#(FsamZsV[>Ml`Y&<W"Tq)i8'ROHA9<4@#a56nIM,ME'>LJ18>52+]9pLqoAIWG##HMS2`^SX$'N0dP/)7*DVh;<llE__mo^GAHFXh+,nhg[,\S`oWd!dH+iUA)Cg@qlT jQ?8()W2`0RA9_i Y;!EBdA$_[IX'ERYmL[MkeMnHN0 R"8Nhn7>%)Hh\ e7F@VP61nAQm%^$@;fs\@mrNC5=Or32)c[O6G3#OrFN>k;m0oPe/]0!.i=5Qp+Is@bJ<-cLh_.Ia91f6M+7l;+\mH7V$Ai"4mAp-#Y(jDKCL:4Vr!h#k8R"*n88`WB?N)/o9KG\8A]PmSnj,=q=h!%(X+*%Z_/ApSK0`.L;*%@G22NlmG='pP%,JBl$WZ:AS)rlaK/^(J+B^6fW*E C37[ae^A]L@g$;/Ho)o)1:W6q>GbC42!!oDY5#cMQmK3-<)(m#=s%&K37[:CU-hm->V"/AM\ 2BfkNtlILl`fPWRG^+d_9rcNQFckrMM.!3jP2V<b(:QZiAo6XdK KD5-f95M&=Y$'1hV=]F?b6E"^W.I2<7kgnUQlj;YQ'W8NFe?Pc%[Z^BEnel*gUJ:gp`7lGRfg5_YboSY$].O r)#c8_"RFR#WEt(dQCYF8h;ngfPe^Ero9^bWGha"p"J]+f.<>A`G s^Xs9s%I&aF3k(BC@WZ"J9-425-K3884cC_#0Z2 >%o&UIrn.]!F8I#*Th=17cHo>^;_8dB:>NMm'XX<sZM8$3UsY(sJ-An`L0_.!/GhED.&$37=>@beT#@YdX3DFir7"Q'tVgC2$3="Ke9<0Z/i"]":tD-/nfkbdT_X/f)ka]=.l!c?IXTW,9!34IK/'*,/.8OA`8aoXCBI)SGDZdi3b?a`%bI;nNAAfg5KXSC8NdCa(!E:T*fIo2V)8Q;j q<42ACAa.4[Y@<OX&G&JJ[bW[3;Akj&&e!.;;=)abrA2*`5TQlbpi!?P,f_eV#Tt G!rd bi-Rf'-p%U@V7Q\/I?J+mR0m/p6VW4g26;7BUGfQscTe-Af]R9Z!B&f@3T2^G+NfGDgHPP!J,Qi5oCC\$B@I3Eg/6D3&MOfs$K9V),ESse*!h_BL_h-mA_19@P&s3i_0iHT+8#"? A)te`srfDN:Qjr =9Q5@m&S8U*eG`k+UC@Op]SVZp7bRqca5TaQ@_g,K"O>Mk8Tkh6K%[TeG=k1P'^k4`43Kp'N+A3+'>e M>-a!M@QEPf>BY.M^D#@!8RAn&" lZp*=gJD#>l.44)c8kJ0EjKn@q4]@Y"mKH\t@=Q!ISeN@[A=q`kl;K32M1r$LV+mb_ni\;IE,6>d$t)B ABH]7&-OK7"('Usf4U>;ZrgSANg+q7P8tFk0)r%3<-aN*%`ZUL-142$\*VD79cs,gWm0n+DS7bcA,c14[CZQn]kb/-$nM,K;F";E%4X[R#GGdpX"!h`j=A9_%pt4mZ]LJoOMh#$*nX57JktJ5HI?#ne/qIMd:?F9:q*_UG%ILCdH>fQ\f#>Y7OP(+"C'HD9a&F`'6ir+QkiB`,/EAT'IaBH$'gIAGL>;RtSL"1gO>XeX.L 1SZ+A]31S4W9T>4EJSpPk<4#("#CaOV>>iGftc7?5[?(T^qc:kl2I'#.t^6,`H4W!DfMI9oGt$p0>5f.Z>JO`^Be%q=/\eg]7MaOY:2_,]-,b!A;;_OR A5P.n%Z7YLIe^)1_$N$?&>oA6$59qS8"@VbD8bV:ON"!]`jC@4n:6eDT)3E=(orMJr+U/U-E%h*J> ]QinJS"Z`-9QP2rBF?g#8m PlBDJg^)p'Y4bRk OZ\`0<"p0#`FqLDRa_Md",AR>_7tqgAI6q>F\ rUP2h6P5Lf!WmaGeslT$$:km:"^b98>B@[58%Vk8o[4,3`i-j`:lG Jp3Z@RD+o"K;Oo`cgPBOm:XS[SO/hl\%V"K%rXTaOdA?!`KL0[jil< IE9'PaXf@/tA#eT'SBZ]es'ljk^/f?i^b`k`CeqsgEah1N^_qKFOQ:V,nH;?rWTWAh8@J)AJ-fdM.Ub'>9`Ht>[4A\. HEF2YA9)_X3L^H[B`)dO UYDPi]b&C`-AD`ettad@A#nG>L4c\Wcp"a%d1Bt4"atAn_#%3>VCJq$l$>O^!?$WB17E,NMQI9hqOM,Kl#0QC)5_M%B2E"K7Dt9XK[s@_HW( Xp8-1+,k\hs [i?3?4XCQ9R@I1c,D4?]8FU17BbSEg^J]H'(3&Hist50)n$_k1ZX=$.[:O6R_rL`V#&"GPi(Zk4\Tk?UAZ@,gt)S#c&n/KSYnFGZjs^cACm;+eP6F^)MAGhoqV4`@1%UMmfNba+"& 0sY!5$N>XYCnoO9^FI6'Y >U,i^S$3>sW3#itq3RnU@rgE1^8\UTrjTcUHbl$CFC%)UY[P:8'M'a6^1O4Y!kgi@n8:%j^P-cslBH*r,-Q"Psn4bKbHHAUVLl%F_fB\P<sD$^O&VU,5Xf';b#cibEC64s c(Wl+T+UE&N,[r6Z`Nk>h*jme`BI1EhITO9_gA%]A"i<37)\jY=sD8sYN^9XFA/Ml<+seGea<.6D^$UC[=X-4`tk@fIXG]%M_h:kVC\&C#1j,`E;2[CP_;_,SHb+MHJ][=@?Z\J[!ciZMSC=8T_P^+7+4 #0aMJB#M7+J9Y(TrprMRVhqp%6n6ph[#A1N=8i>Md4<b+GoT'>mPMB$b#AdB5bdamqKn6.so 1O2dscP,`V1#sAjYn-$).Ao3moshGH`Y^-a>1T?/^VeV aR(MfbU*_)lDiE%8OlO?pr$ZfBJj5#^-GX'h(lCVdm<9)q".PI$+*5j!p_'3#>\Il_VpFG6Zjia`Dtp+IWhr@EH#]l0o\`js?_);^=90%PE(m]hA-Vm/r)\W9ENd*Edn+NM,G^,U/n;tA^+RQIGfiB9s5o6`RjM[ALmTXqNm@Z:O<6NTbU`)NOr.a:gm^b_XYn-Va0`;P? RCFlYsq/5Pr%$G?r^AZAE&/d*X7AYM\AC,Mes7G -Hb0B\BfX6kcUaJ_5[W1+lp6<;T$WU=C&\hg6A^NeR%bIWE6ZjlN\:k&Kb+<V9boOA3We'Pp+PkF'h5^NrL(PC&SIg%Y$%fDpJA1Ol[+q!_>B7A6N4>?q&C-pLlqE@c)j/Ml\i'J'\/N4((UnMeLVG-?rc?_4]>TAn6!eU_:tUA?OYrAJ[:n>nrn>tOl]L,L3tb%q1"TKD_Ggo :+r<+/L<-QrHM<=)i1La%Yj*#]#`akcXI$cXUbL:=!nNd4$]flE;,Y4(i51saE!5.n97EkgA`IQUb$1s_<[*SpA1j/,IYK=$^.'*J;^U1Aa:r\*[5'BfPm5i\R:Y5N7XT*fJ;m"f<-*_ ePoqPlR7d4nX0[ZP'7CSd8!faj)#/6e[R+!^]L[R:N:TNV!(Kr]OV]a`% 'I-L hGX.orUtGE^39%Nio,O9MZ;+bHD?BJDBPVAk'SV%5rFKf"?[RX`W\t+Dp$)0NZ_IgY*9I"+GSj3NL[k%HI-fm9A]*9\;\>CTdiC02j0G04t_2C)XN&a6!NCi&_[W*E+K*."oe6R:Oj2/4rU6PtGm9X]s>ho)^1<44a0AT%ELqE/-UKgS#AB$kVBmie4$1Y`0JHGlRa#Xc:]60EN9KE:of(H;ElD[-b]C6hOqKdd#&8/Ct2<^WG->k1N._J]6)TUC2mWRXrPD"Y8'_,rqThCrN+A_oEMMkM5-rY2:3Xl1 @J)D=WVEo)paNT7\MYaD^:\WF6(/m:-oEQ98:]mn#U2rTqm7W07fcC6V&pFWgZ!A^-Ri>AAY?!!sY[:h8OB'o6t?3_]rM4^IfRmA$'mPB<X2,@j62V_BkPrr/6H*4NiF23S%(,EO!Q %$RLjP5X& dHpAUB h>9RjB34sA:CJ(R;lN6,kj1<ao`E3p[LNKFk4a!+V_Rh;;O>&;)P/*^g?AAiJ`@*k?1A%p<4%9L2R:C!fReCA[f#T1C6sYjI_D/H`IV@*N6LX'`m>\qeb %'3.)%;s#s!6/B#8dd`5di,iDPHo7MQ$AV=J+V0:(\<8fZa%E@Z7)"ZlWG4;b.0*S,<"K9#CihF83rBU(&mA&5EDV,'WJ=3NXeAW3@.j2/:!+an"I%3q(9(kqZgY9h]q,VK&![P9;J=D07JI_\6+/:21[RBq#4%?Fci'2V,<%6krSb@]jEo:YMGB7P87$W;76_U"nHlgO2 o>'[KdHeIl+n@'5[+Bd.^:\Jt&\Ap\RO2Fn5C&`omaZk:sGJj&_SIO0P-Cd;G3#j(I.Z=NCqc 2%(:[0hN1FV89i'a+ed49r,f\kNa@_KE*@ZZP\GFNRNQ;"+ghd]$LgM%3U05!U-$#I2.6 GM.Cq7P&WDYj$qd`V_755b9$K7,9(Sf=6>@J9pbr+RAf>A74AV_E>Fg]^+-0UtQi_m3+rkfFFEr'<%iHE/4B7N'sRWoRIc*U_qfZ(pFqp,^'0-ja;tcTHL5:+gJPb_qrZl.X(/0TeXTVZ"4AR/'lPAsqA<$@Ej%/0XV$:][.2mhWZ]lgQ?eD8q:t>_himc#`.>6[$mMSG)7CZBZ\e!QI7U=HDoP,3)B5C7Ulm`8l&?97]9bV$) c*11'-:+% f_[-8hncgs>Na[J (jUgspZ80?Ia_'AV;n/VQ0I`\QC$>`:PG6t >1!Z%s\a(FNgB;;HbsFWlOV93M8[Ut%f/AT2]4a@fo=&HiQ$Kkle-FYl a@C8F)*S;lU"VkdR9\LfU/TT!@.L'+ZhI,!?G3A!#@-h)^!B?)c>:O8cA4gUgeE#kH'\>E:`Rn#i!@2,*)H+HVeRB,cATD8U;RsNOXr*M;O+NTMJGe6$J,BI9'cg'=ei>U`gN41oN#SSV`o[8aOLPjsb0pL^G#MnmAgsb=(`-0T)4mP2A43]F!Uh\hA*V6 9#@Za_'IE2Ai;qk$JQY5>o;L)\]:h7Z)^G7#b'r-KqtTi'dWAC^g,"^i)abIli*HV@7rW#;[H.^HAVDU0)J:8sn2XK+LR._$[Vr,4Eb/7LT^MBL3gcWI7E?sZRn0YPA.\N%UqZT"H:5"Ha +4&mLinhZ%SHpLCjG@EpaTt]I+&VgLL6s%+epH56Rq<iMh6LE_Js\!*V6EAJ4"tQerAf'c/]icOeFc]>qJahlBP61.6Zn1e:I5 r78,#,F /3<;SFor=OJLpMlGrc$]/91SAq6(c[(Fle]DE#!/r\CdaCl)$0R$4B-4bm4dX ]0#T,5#9#(`J,Aj?&_%EcpA7_aQJCpFA*F[0r;.q*f0>3$$!_'tRVnR?Q$Q"0XT9?Tq+c_9!_^8eph%AR25K>)6T%F01e/>&b2f]l+nAgmQg8kHb psX3`)5MpE1O.Q!"DT'`;7A-tWqW@P20f$$T/a>PebHtn1!qZT'&JHqr[&'* =52"&7dpe?g.$o%-kKF7q,O0.i?lc698?&86,"NdI3_=M]nkAfAt(7"*tEfQ=-K#II_0q:N.0:K]80%4=JdT[F0n":o%VE& 7;;]E)'rAS_Nc-$P\NppVegCjTY>\lcF!%a:rq;9ndd'A:RY&IhG`p5>>Hj^/Wpn)7-f6$8A)=>0+* 7$4o63)&!i-YA,0;t\MkD(AgZah_<[k0o"0]af<(rDd%XfeBU#W/^QS!LTO[PV+8,jY_N*bApB[$!`-QWWA#H->hAJRlr$UQN(hAmmN\m!Y3R?nY'"`Rr4e))Ys@rQ6(FW9+m(8<6%1roR(^ERjQ>Aoab3a1MR=_]O/h4Irsl=W5+T3ZFSn`X0+r#O*iHD?bGj?I7m8IpjrFoa5J\97IJE66Ob[-4N_o,d-KP#PmqB;G=fXB8#]1AL7.HQoXm-[$A\\CQb)f*TfEH1Q()dJ?f&qZlmRo;a%-LnqtW3e&5PgT5d;Has=F2_VI@'FrHm,WN?2 *"=U `K'P$PchrWcdt L92Kj4;kTH=#?H"cf<@iiXjA_QN^rj4qLV";XPD9j:bV01]`34N1\%DX/Ff@#XBI/Lo#c QCoJ\IZ$g(1KG2#(:XDi8A.P"d,A_68DjmdT!hT<G[=Z0H@%j]'jQbkp"q)+)g_:[AYDW,K'LPY:rM4t>.V&m?$9OAM3$5kn+,%0o>W\pIXT`^5!6<K>k%@p]Ybdg-7nI"A9V]]2SWb!JA!k)D#W8R2B'ALHClX$++inHhl,8AXH!U j.7%W"Z6tNSf7STULk#,b=c2Y`\M8=j>!LA\i$qn8!`$El*4qXlSbfb3!aDY?2R%[1R5Ah"'$$j?8pp1qtA'Jl$%CW/KX#QcL%9a)['lmKB/(.BG]:TpH6$]M$P3\E,H=El.).V_g'G(SKG/>Z +7Sg  PKXjE]t+.WS^o8?G+9(9o@9@1c?LgS<$&?)tbb^'g(er+C2@fq_->mnAkE5cCn*<>AI/KAoGo>9TcH+h`Wd? FbbjTld6Hm+oYiT&XBq+Tb/Yf9BTIB^Ch`AZldmX'?0WT. @VSl&XcW:#(FW^.IAG(a&UF98DfaUc5>!o9$?$41o7OMdQN 'CCF=3n9,H-GV1:C2fre*/DfeAAgS<E.bQ^&4b7:#ChiO0/(Hq\S%DaH#T+7lYsIUS\"[Q60MRkTZpC29Uam&%?)2LniR"^$@&4Hta5=hQXj*M_EC.4DGJ0,V:>Cp#^OM0Us`WMg\KO4)#5VeCjJY-3Nn8Z+dM8HLr;&bU#`l<.J:+WdI9TALi7"Z.An&t-&SVX`XOY)D:7Cd+Ddfr!Y-0&jr9ie)OCg-)sqid!Q,>ghj*.<4]]ft=rY!g>i%M`] kX-bg;:*`c :*FpCB="6Cp?Ksn1E-$6*nP"]JM1==QSeI5@A"1AJ/Z_F%\AC')E3ZqSM3L2.IfClYbSGOb?aeeqJU!UH_2PI2IVoJ6q7pYVa71dJ%G/foptEZbhC#'i^4tPXI0= KDT Y-TRaHabpCCf="Bi`+t-V#dP>j"+FJN/KL',;Gpj3Q5Vfn6i?8El?H4p'?A"h)A'K%Sm^r%a7-\YgE9pLcSV!=?p%(7TIdC,UJ?]b+L0LJ3PEHeXZTr].8CR?b;,t4!C'>Z&UEGNT$PlIQW6DSsF;WeM2&o=mUA>cAhf-i$qW*KB I)9.1Ae%^ICbAe2h7.Z]$UQ!@G,pCLD1J>:A#U>hg/fathk5@GnFm"/:HW)V\+\*c)m2Jk8DoKPOBc7]fSih46G/\rq0&rm#,G3J;E-*rDh sS= *C%f.NATZooQ.modqS#(%dHm;?a4d&b!XWgOmKTf"q9I -2%%q,8R4,J#$5gBfZTYMm,tq2SA+ifSo/r[#P]T^7eX0(.?F6`%@`NXKL=PX\?XR7=GQRsCYK 0Q\S/ZOS`W`[9W)X7V_(iTHfR:`>AF:g>b LA3A@>8dj3,0ned.C9%JHBg&lDPd9#)n\@9&p)jY]=s!9 :qp)mJ3#7,;-Nm`e9lY@:m]"The#>be)i8Ahq]g 7#C_o&cdPH13j;Sp$)0sqL`Z.WA8[L%sSPF@E-(\S\9Y(fRCOm4p#A+/.-O(a11A$tQm_(R)NjCW(2f_' ofHL0$??.r'tB.`X]ZTY-740RoY&iN5STW5I Y>I!rPHtYX"Y/ ]m]QInX!&K`NQRU)A>OG5&En."WC4<;4;\=BB.gia@?>Y0'ASF+mY*2#Lb[9B#JZ%RhJ<>fc!Ae*daYAO6gYGjGl-!/h69M)#jlf86;rhHb)i)DV\@*_9T:__^KQ^l @<85s9 M6]?eA!#Cps.,Y$ e-f$32>G2bhqZA!B1LIA6@arX(5L&:e!eg0X=_bWcP-%",09!bEk^C&Y!irAW36XKqV6/MbI)Ak![%,TPZ/AKX0]*\WPq";OP*pa)Ki!,)$\1N-X$@M$b!8<;O`$8OZh_`N0mh_cs1/7&k3=["]tI-OGV.oYk Y2+.riBdRQ7k\d8GFpG/PVm.]tlq>RU!J_h'fVdeSAbW[^.iXN!f#;cO[m]U9NstB?Y`+Ab(IDE;'P.!Z\N@8!HZ>d>(@m"p(lS4/XIEKNZ5h:\YL>SWGK#]2OP.q;][.s$84/9FJeN')"(&q42g3SKpVUbifkn,mpIT- @XaW8j?_3AJT:Voh==X>+ ?1)iFM(aWV4]1_hI,\Slc#pWkThsicBRV[AhADB9KKPUJ`KL$eSSPC/['K8(hb?AE3^sJ7;;oEH6A8j$#1`AQXq]ps9,Ap08AYc/MO]IfN[.]7tD;U%6lh8;XH`s+'p4diRJ%oF_4b)cOH8 /J=sS"0kOl)4^H.]mP3:cCoJ8V1hl+)+2d7W Dt$0'FNfB&5PlW9$M]DJE_D:(;N(?$o&d,qGsnX ;1dOdm0c.Rl^Ct/GiDTs&^SYV.PW$"J@8 b,>I-<Gm&@`:[p6h-V:)e7A-96;h8:[364n4pA5C8I3WTj%5k)'[,&4>:#.aEXL8niGh;KrT F$=M/DjA'3s5/9@r1hqn@+HYf""RWe9Afnlh*\tg\T$X6dE9C#q[\0\:dFf4!-]NS4`VIJhs6-=6e2lT5cCT"24i5G$]2n^Bb$3$,R6:ZKjn@n.A;.MEscbH4 DdA?j8O`!mM#7p (Mb(4\qBrt!VG>>(BIRK#@Z:0AcaHk=6AL-/"R+&S!c-BagoA8,om0\!GWbeO<.R":,J>2aU0%PFdYd004$69J5;\tLU!5Ym$k)$!cm%OR%btd4g`bla;Q&(f`X3:4DeNTAmo=m*:p1]Al3O5H8,'4G6c-h3;7n>Fq/)Q'@lk!K[k0:eKGq8'^Hbjj*^%?XnWb)/soo."AmJq]dI[KZDV&75oA*F:"*VWY1d`DAUtYXFESlLQ:A9c_qNT^NYs.-:rZkgJ".PD:)-#CMDPjY3^/mi\s+r67s[c@V=;W6e*^PJO9`@2fPXRojZ9Z%1+:OLf?fGi)YF]!H %Bcbh!X*+F!)/)#Eg+Z;c*f^&2;tm2;slJSP2a+& \W;9)_LH`"+S$tAU MQ+dCr^ $1(AY!.b-2ce%n.dInA;#Vipko"dmU?'\qoV[ngS)K[\IhNC`)f:On)g3&qdb!?cQ&r,.UoSd%9KA8O!L([*H.!:j;cE7V65ae>>K)=('.65D3G;+]qYa4Nd;5l+PW ACE1@pAZ!9fj`ksP&cNdARrG dHjaQ5oVOYpEt>,V3SV /T)`t (A(e3UG*B:$*U%1qF'.Y&@4m;$i R!&GXLANqSP^N1$/D5SG9AP@nCAr=gHZ8G\FWrDbm\'IM:n4b!oXSa#UmqGQ(=UD*99GH#2FAcmitH0)]lAfKB;T<fbN'_q=TPt.AbP]s=6gRTsAZ#aJ&+`[3'.,nkmM(M)>S5Q$tR],lh]mC$AP;D@ULc0jXAAT>pBH_EDkoO7H2_oUJ!P@01V94VqMXTS"fUAS.Vq8W7*8jMn9>mJBQE0?C@1KW>E7_AGr\BQ+q/kpCe2B@)'1.3pE0P9NbKC$`5X^'*+[69n.gQDdk!6N`c(r5CV8O[#$Yh Ur$&Z?,6iif)l0lTtGi%Iq;+L3_U>Y#*78dKr,BH6An2gR5bcap^l)Y3!c&>n<VT:7o<)r>.ee4 aE5AcSdA>MPOSQK\#=r&1"0_S^@0*e--@bKC&1Nc"P;&2Z:GGifAL6]:t%t"Y$9O#GW]?-?>OCNKs A@-ekH0m`@*!+J>,/WJ9]kt5tQC6j+V'VG<.77h*g&)+G9nKA#5TAW\ti)&M3$k/7W?A%\=P*&&L]kY&rKk!kjTUl,N6R7-cPUHak5odkeHZH9A3V/]e/;fYF-<pP^Vka]?L%Wt!> 'JSsn/16VA/c,(-q T)"`=2JkBj^:aT8sTp_+2o%N:b%QTZ\gnq"t4D_1B<2AXOUM;O4*Ak@I\ENSP'eanE/Y^fL4TOAcV4an>(*-1fPMHG=)$j4j8tKb`59DFSA+QR?.;n<(j:3sr33Q-o]b5;j^l<-Ua&+5%1?7smY;jbUM/7"Zf70BdK@GnRNi%\2A+%S1J/`?(NH8JFjLeJ Z9$Mq986!Pn6H8E=Eg=k)e]>^Ad=?#rpK+J^5QQsb)oT1ch=rtJrj.c+XK;Mk_e_dc ^YG[aWPCZd!n,D+1F=_O\K:LU3"G'rFViOQO`B+PP`%XRnoQg9V:YCrJjl'rh5"HeFCLg:B.Ic7r:&F($UKC>8#C"lGT*p!A\3'_A*'.InVC1n8Z@F<O&B45YQ%bA*n<&r7.WlfF@>O;Iq7_7tWk:q")I#=4mK(56h45X,q,9s.lG#mPRAAfs2l/8MBX_na39RX1B$7LKc'&?bV/'g' k_D5I67WP!W/a'l%;ZWeAH"f7AQ;OA"^*oPXQ%;8;iU46BOD>lJO;8k,[Z1W`N'Bk^0Q_7P<#K%b*cpHlEFaJMNaHL>>J(p@9OVAOb8]Djdf+69iccX jG1Q9kqd*.,"lmC3"mYNY35[,2A=oIg#`S8OJ#be %49a81hN,bj1J-ZB9MYg,p*,1gKDe=>lr'+(fb:U#_eKBV(:H8\eY-Zs4bW5CLo:PZ]&V ]tV5`';2A@r:h;k(62p]F.ga5.r%EH)=f=AlBO-d;9*;n-=Ztn1@/-,7Nm%3t"^-?+sTCNYq)pZ[R#%BRe&5EM98USIRnH]R,Ij[aJ5#GcDL1P2'U%1U4B-0pLMZ:],^f*a)tYI6->6F]]rp*Fi! h2_=EaBn5D)(F?1amaLA4)UZ)\;;4B8F8PAa#XA\=$>RK>aPcH's.cHKk9o9Yc*7CO;(m<DreX]hQ>1f5^ZpkRf`5#?(],]V@j"JEi_U&+ec^F9L+o6S`$P;g':4%8ZIGG_$22bNQ589\KG%;CdqrRWd"f"GcNj&-$QNs2'2=j6AojYZakT>_KbC4HIT4.^o=ES8*5JZ1<(!\Fs8!r;!:!@U[/oA*I:AeFUE.UE$^[dbN6./B(o+&Khj";/-h7U]"6pb4W:3Gd^'+82&iV6L$oar/'MR?Wo,W"@YY&)#&_<%eETG(I??e'7cRH$>%H&b/BCF"pt+97)2YnSV3Mc#`m#smn^Y9jpKoO=e9j+fnJ+/V]Fq?:kpU(tq8hX\Zl2#ppK'X.Xa2UdC95c)8D?q!AQmHL.qh+?a.PN;ZHUmo&jm]dEnA] fin@9St "5i+L-4s,$sW Kt^;[K.q2QQO`?!m\?:*]-j;5\Te*TYd[R*#XE?R%JJRX*gELE/ZOMoP'"i-U[8We5H5qOj30C-lI1\#MAo36hPt.caONtgNM,:8aFnFomY<fHcg[Hl8P AV!IbYROa,4^dDX__$F5)S)b2e+73K [4#q_+mrX?'YC]N2RB0U(S&QQ hOgA,AZ0`qb3V'n35LNK?FZT]%o7_G4B)+dH!WFj;?`(OA0p<tr_D)-h+-XQ:Q9,UH[4R3M Xc7#T:Fe&#h<:H23V*WWo046t0IM*G9$@%ALWR2C?ADqS3e>4(g]IO/H0$Sc3nH@nd0n)lG;+$%`nilmb*S[gZE0_`Rm/T>RR%">8C$4 be`Y$@Bj$^Sdf4OY_N+C;K8]fi!4g3cF<58F-dat-XT:DkVSopo4.^ZhsjV/eX7AEPS2FVgB$'&Xh=VSM$Ik07PPW6ZO':)3Uf7)dOK8jh_f3?H(Jr=J.LgWnT1_eA=M1e,6f!4%<&&A2&DON;?=N_kWlt\Kag$9 26W#;7 crF(` K+M`V"PfX,K%Ul_d@0i!KWfX*OGp4i=EUbSAqBrLALs%[A.^,l0Al?QEaj(amk)]FBXCiYK--?0U(pfC?q!+_=@mSLkXrK'J*gge)^B-a6n'9Hs)75QM5+cQ_[B^[je,\&h0,L2:n3+V:eA6RKlQnAh^: #7oU(C74=K*?8a@iMN 6)?Y2imWkj)jL3t=2lo%-A%Gmm6AGXq_4!Ebb6`hLDF-N:dPU-j=o@5]'ibipCDlZg8,*CGk`A71c00>eW@`lpcN++U?e,n3\;Y#a($_>;^HrjD$XkV&[F,SB1n7gSqmnJZ[Id1g^sl*\E]lIB^ROG<^fcY4L[M^]n*O[R3GnNg9P/XAAM=16F,A^VM3/HLLO3#gZ!31(_R8kt:X2EhY\#6)+[`Q$B#C"A7-qpb/JiZ$eMFkn^MD ,TL4B?tXT&-c,/po271,` L:QjqT/q!K'EqA 6n#[#UY9n`TOWqC)=[A!8`QY#;#:fLP\"n+9hd&@S8&98>gA1=@,sIE$B1.F\m[c2-092XJD<`_R109#40(RH4j$j'(^%l%LaG[tiNdNZd*L1\p&tAXEZ$g?Z02SLek*3eor_IN&2ML+)kQAg3r8Y'\^UIW-h=C1`3]Rm:6]k..&0H*fa8l.nU@9a"kZS0BW6]KU9Y(_gF#p kT*6NY\(LoI+>=7e":1nOl4V"$!IZZY,B8hj6fhZ7>HA^rt'%q(_IeAAN#$#"8MFmA2qMckc cP)2Nn9;YF3LqeBr;(\kgkAfI0eR*@.h`&A+`ESKeNB"7q;S,6E/B'U'\'1FYW[5,sBM+KgV1A\l(q.oU7(!F0!T:g&.X(<$bD-DS]3Cr[2U?^/0_g%5=6=#cQt:]hj1O7-*[drWco:"b>R!sa"'8k_dU;QMV?:lSAcFDAaK\bO':MoAp_lAh`-" EqBL/@I)1Q -:'/=tR0A#;9N?(II?^7"Wr8-.@_*/KdAbk=Kb?6/5k /l5J:::)1cNJBbV/bC%Gf<"1r>kprV$Fat17n#07s,X$5"q5'M'%q%f6Y%r'\tr>+\UpOrS;&:N*0&?rVlQp*q:9LhNVteW"%&_0nP]CVWeWYb[mIOkkDfKdF9END]C>(/EUcC3'KtX3)- l^9"AmN>%a7htW0sKW>ko+-1p0A2NPU8ZpPV[sI'QOYe4+[F%aIY!jA `E?h[:=BrTgJ4p^1d7sAitnEHsfm)?\MJ1WA/Zim*4V-B3o'kMrct@h.>*OB-/7YG=)EW.tj!CpSYMa>CdEqFI@`1G#apQ/J4LV_VFO/PS]ZRV;s84(hSM.n8(`6LX.,jiGkF5,*UkI$H> /@ArY_7EOm)/2;6=EjTI&*#\e'#*2*>k.3T'0C*o0^#OHh[&"W6Eo2A]5GB6S,?"m$ER:Pi?aY4pH?Z; A,m!K+sF/-oB >-Xh?WQ'TI)L'mBJWWF>%mY!F&X8ZZ0)q2UfsSqZ[X:d0[4EWb!S7I(,FN3F)LdFX^3:`EhCO=U9>5.6\R;PF;)`^3M4EI/A b]Re\,*TD!C[T"iYIj^+l.tUG<0&ID.JdLFEF,lrZogh-JT-;a?2`HS7"eQ+Ng&icHUr[3kn'?nNUVD /b@7[cRe(U6BA?jmq>ToSn @6G03!ngRd&*ZKo'Ue,Ll)_2'- h1 98UTlo@LX@i7hgRUb\trHlfc\epd$Dd'=6=tm#:U]S;d(`ABONL L6q,6lVID;;TVbZb3oT?#!cjhA#S9'J =Iie<3KV%eXg9ST cf%hT!aZIG74l-^bP>18WA:NRE,1VQ>8n_d`II+&4Ume@SeS Q`+>dmTNhhU+8=+gc/Unj=\LBal9)>-cT7]Nh_,!'&2Oa;O_!p:NEnWnKsUke-I@`1=nB)N>[)qs_)>E2r3B@c%N0R7PVUEf['eeAnFZtesX'+o>$5Y<"i?6&_Fj*iY\Rr]5)>7/E\e?mp^dUAn]C3?#T'`oEe&3R5g7t[U21bj#^2t?>HAVAb)D]gf2B,esZ"shAWS=WN)5P.p+TZGN3\KAkAmHN2DbS[V@R1fS`Ti50@R0>UdFAK1)Zi*-J0D7j"/FE0RKgkB;0iln2Vh\<@,l5r]`W?D2+"Bt/6X 0L>3\066f+6tYoOA`?=e&r+4_C(F?pZZ_h]2V0&2bBhp(=3Q,]EGTePc&Co;lFKHts'mB>=OgZJ5rFRoEQ6$W?]j$BT@RHgO*82+a[@NRqTPYs:Ks+^NG+2"2jF(5!\ kq?M9_GhBC&']rj'Qj)AhgNs#OnOQBXPO!o0&=nZ!i%DX?:cOY,2Y8#2IALK1>:R^N+o6hfqpU f[O%m6lQ%_I0=>bgAG'%\7(4Tm+LtH]Q(f[KYjRnf`W0-B'*LL- s90UE*\Ks5< =BWFKc485lcUBk(R%gULHnT^KAPiWSR6 ?35O?dmV- ]mH45?&LV=EsoB]%)!*$'edIP"HG+V/A::SkJdA1k+@K%D:IB_ENml)0&r$NS`[IdK@Tg>Jq5]_0*/Q-KIb IWTFA!SDl%\-:M7ni6Aj9j[^!L?`ZS^T47j`e`*lc!hK=rb;UG! #CL$5c(3iTti:(pCpR34`];*shFF]-d>MAn59AF1a_E2>SbWX_0to6Q'":44aKk4,_OWN'WE+p9GES&eVmA!ZAWe;*qsL/ l"?l1kg2d9<5jgb5\#OmVf3WH4:$$ad*b>=G)U/n7dEeC([U<@`qL2iOVk(Dib2-K:K?Y*r+^A^,72qI)JQ>.VE SfW`"Qrg1`cJ!oAKC>O @CpG-A0t@M*]8=":inR=\NnGXpC1+]3lQO]i?5P-WsB0t^VOrZ8kQAhM+-/3'N7[h^&Rg#A%K\^9XV4Rl gZWEKgPEG;$^iRChYtWGPlp<8#\6OVm7h`lDL-V11E[4QN:,kH"\o(<)7`=*@tKW]66kb^#jiLt*/%]!)A1(Vt]%e;K0FREkVrC,XQJA'Foj:?I&Zb>^Z+4D4"A9)%`=J nAEL+q\'\F$kAP627_qJekh$gb:_FDj/*fM#1<(;qNmOX/:T&7B?EMGQ@QAs.O*o2ld' jcoHpC:/'!;`CX*#, 0M[`0HB[A5#]4&jDdoo' tf6e",o(9HXr,bVrfLCL0Aa.bjVFXVF5P>b%R(lpHU*'3XDQQWq-8MECG"t"'dj!OM[_N,FfE40OCHd6Z!'M&6f!PZ0t+@\2#)&%Pk45Vf#O#be?9I.6DkcS%rV/\^Te((c*l7+cDmMaFCFhGD$Lh\ID5;V0a7iRqdV)<],d-e>q<E[ (Zg7.D!\4EJ4[U(b@(AhmE`_OS9G&&pdj" q3PHR$me3_LRA`G[9poS)*7?L"2_qe3HXV^[%rTArKEAa:S-aOS](?hsJW_/7R\[+%;pe*kZC<@(q`<8!`&7#4.OoJfbpo3ig@50+m*eR53JRhqrU=H3GH@^KM2%<`pA;<7dUD]9FE$tYmlj:4&)lWpjoXje\L;nHsWBi%7Z8@%W2M>]WatN3e&Ya$P?d1_j+a6i$FGQe [Ho%f;j#Qt=QGoBobQN?lP1[f>fL:)H^SC9A[ ;\(Q=WAm6cp29%SZhY@(8TsDkq=l3_I,h(g?%q73K`h6-55Nigo3:!<3c4d]&(M/RC4(eIiBKW,oI1d4!(<;B >+HZ0)e.bs' II6_7LN#)q0a(AMn+>q59C$8oU0La]iI)[H9,gNXL4&:BUAfcT@[h'dlY4tBR90i9=:_bb?\QZ673eo0Ea?JZDAFnHn/UH6]C0 /t-;)e78-B$@6G%OBSL1a.\&FQb-+OUZWrW&1ecmcSTKW#ZdeT1+ApR'5DMSQ, 9Am& )+ e<2W.Wa?CO"X_l"lQ/Q<*[.hDltZ^6JjC[PiL2814O$?j/QC&AnOGmtW_ b]KA( 9LO*7FOICC/7dr)pPH!B?r[;`^d[\V2,^08jK/C[M3k,V78XZ@LoJf\HmZAko6>rTepb]iPgEQ!;4.c$ClmhP9 1T=6&0GBA*(Un49P<=BR:p2#p&bO!H74&n`98`_,VkA6]t dGYqeN"grDXBFk;-"dNOARN[5-%).(_NSa/RE::QKJnZG%f"PP=6#l'D'I48qT\;))GTV2K1E51o"_6-RH;:$cTB5"48AR<+U*>A7N?5J+iEFl=h2p+f6]h.fH!E0CtSO7t;SK_/h/-^ndjRX4$rfi7Onn#B$CE="L=nLG[]3HB=/ph65]@7dB7P#"MTBSV[P-60h'#NLG=klt'MR8q=d)fN])[O_`Ia-7BMX%eFAkcF6JT8MYV!)/cL3[cj3VnH$ &O"iJ_g2HosF.@ To@V7OK2"LsYYcAs5>M+d:Z1XW*e%Gm*K>tcI$W6Q:;KCW8U@LOlgU_)VE bAQRh6)apl,gr3^#@NbAij\=Sg_"teo$a WNJ s\q8+r@pKXeJ*sh/T'M=L+QaNK!gdrAe+n+FWDCZ"d73O&/!Sn/0.[9[> *,%SA'G#Dns-Q(RBA`aO7ehjH)t4Y>ad%^:]&QOX[M[-RS5W3846J>)6])AO>s&GdJcAMo[mJfU<>YkGoI%14nSCT:feac2KYL[-! Hm.Y7Q=:(&B9'$OVjb=d*e?S5Zdm'Ar!qIRLG soR`^Z:ee +eAt.Y.FKE>i*h$BGo)I4L)L;A(P!-]ofO(X1\m,kn4&;6HQO>TAD--L"8+>W$6m'Yod9bg_4 (a%XKa;;A)@t<"XXDf7j(g6/+W`o$%[@-c;ZRqq,9bkhLBa&X@(>sY^DS2fB`Aq]pm'8iB!RsL`MeG$atMf'^$hk"i[r`s^LS>(WP-?,oPj_BMIs_1gA$qsn?'oA1Z4Jf0BFg8n.[sf@=gm]33!6m8_IK6',"ZM[M>)ejl/M5S`7NlJr(^!dDiF[.n U%6S]nseSC8=_2>bcCgcoW!sAbgRfL!kgj%81")9\EUQiobP%Cd`[S%t/WV[A`T+_WFrsRlPS]gK0G?)-l)i*_X"4J,[Vl8mQb= 9Y(a^=%lViQp(feU]A`:-MU`^2tA#_mKUjSE*h,pKKl^n\bg5LBF6AiUAt tY,8kJ; B:*CQk]!fn4<&*&JQh^]rJ`k'j?PUQbR*dHaYWN`IqI5d'*L%2HmA?=HK>g73Ih#/Xke3&c^@O\rHG&A1&F!VPW^2'H.[9WD[;=#!Wk267l\ggd@B3(CnV"@!^C*Cm!@8dg6pIAiaVY`omHsisq:(]e_iW)(,.3 '_Y;bm&qQXO[_c2L*>=U)U@@V6QWjlsCA_(^TWdoAjC-6.^kp/8PVmW2pMq]*<[rB(-bHH34$OB\;86lq!,hgU*m&"",6e6`dNO<;S',0jLdrW/-I\P1IJV##$>:TEl=B"$WHA0]k*cVFE+#j,%ZID]KSV=&2S=<XD\h!tWF-.maP>L(qS-;P%%"9'*IqA5:E(-H-^IJo4-*9o]ogIIqd^G[U"P(ngM;AYL)a\+on0"$+A,iYLYIb]Ok8_fBRloV?h^>i?A;VM,5F5!O;mI)Dp(7"H4E+C8$M,K=ZHM3iaT?t;s*\4tZ*f-!dB\9UqF>siVD8lFn_eNf,5In:nD#h.;fF#M\P=*J,DKKM\,pq1^`=90Q!e=,@LU-4PFS(IJm/J$0mrDUEDlDZ/<>SUO"MSWAb 3ER:/YH*ab4%E-KC g>8dCgZT2$7/5Q?8)&MqjOj34>%m-^a8GG*P_fF?dA5rhNmWU`@XTe,O;S)EF%,0Aj@T#8(1A%1:!?bI?U_mGggnQe\\1 1cTr:Wbbg\b 4RGo#7Tm]\@0EaI]:G>4:2CR+IQdHmOsFBgo2;1g6@jt1pC'GAaa>/HM16?i(+/9=h'-[]OL4Q0&eTGc8GP:A'>O:1-$#.AdI0Bh9aALq^#XbS:^>me<*kQ*H&g\+oAO*#U;L=M;?#!"b[^K*?iL+1seV,e4]M?p3A(=L3ee/?D#p#)2ffq\lXn;"b N]1#GMBaGDTEk:[r(4ZF$j50M\K5W6NIMrpMI;E5X@I:nZH/sA8 3)#,l,1J`/8f/gJKP[h%Z5\"ir_WiH; Gi.-dF4UA+#(`EgB$!\CiV2nfHi8bde#CNHNg20q>KZh[O)2T2+'cUU'#L>iBnDJG]`*"i>:Ua<\bJcA,b&*i3Ct02M))Q$$3LAH90I7TA-$1SWpR3JmHQ<)ki([726n)#$LJV,] k[ZnXs")+P1EUfF--*kAWRgp(e%h^Asmq_EWK[CS,AN5U 'bgNLlUYn]A/FkZ]F9KU6OtVFV$>M*1!/q2pKO]8#:Q4'9BA@6#N/UWi@^,Bsq!R32;%Za_A-;;q+5&R4?8endVAd#"[O-?b$`E**Fk "Pl@d?3>T!taRl5"Q=GW"IE2?;81%s_b-n7jH!"VH[-Y8`^?[#8kBfN)oKgJ8?k8lA#0V]i'[dc'tcNEbaV9XT_85*(<5S_W!m^l;h`Z$`U;\rVKW:V8RA-ctGH7O9roE6;F0D*$C-(n&Do^tXcL3=$%@K3&An&/?/iFaHn6&7'X0!G0o5ng*#fHsl*_BQT`N$fgYGUC.Le]JG@NV!fAS0"WEGApT!R/^)#D]m`H'O*kPd?&kkAPrR\(3?X2lX1D'"*Q+,A!:&N_W,l!H_'PZIDVD:X%1j40E[>c#3l,j,.JdXlY&NsLrL!Xff8R;6#%K2R(p%O$rB")9tr3-FJd7EYgTS A(\!dgX4Vq_'_<0FJ%8V_0U>)jDSpRJU0K79LT2(C2*?NnnAIF9a\&AI['B$EkH,Tt8:JRd7bJ1BW6 imLcO27=Y)o%j4C/6;%[gAZ$k#`cWCil0[:sbU)Z9`f46@>X/\>MO)3kLnmtL^/4Q=^9a@N/n^D4sZi)R\]0\4Q9YE4VG,@d:V?\ jrTm)Ra).W^YAq]-=@8(kKhc7O_^CUdZ$3ZlC-ZAP0"s=^\Q7':=+X^r%*," OZQ M, l%oH2X7Z-1;/p,f%i!'Qg90ll9cE.]6)=J-71ClLUS*D?Phg.t,`^g6c`q#O/NtWP1dHAWYFIJL/;ZbrMd6Nl=UDrs:\9D?#YHFK\ BUhIJD#A`faf6"1X3g:bkS?4a 5dY`"A6Z]+jeU1QMhcQ6]@,e"3)oU<Ql59VhPq IO$3[=&)j] 6e!fY+9$Z;C)%p+csgdnAl;Ote]k !n9/`Wc`,9QV4F&Yq ?[pE_lG*nmem<mTPP'.2a2Q+6.BY0dmi-U$%.Jrt37@07jAjF/'6$!#taa;Z_f0[)2l"8L8Z(-+5*2s!PB9Z4K+dUcX@PA olt(IN]T3[r*q2O( gV,8 \5 pQAUq`ln#KObIiH$)Cm=\BaQ-[+WAEL@:j@A$niZoQp*\fOtI0/peWG0>OL?Z`B?s@i_?J9<$23sGI OA.(ZQ6hotT-KjOi4ai.T*27jrJ!jg$3WWE87=8\kBD`%53Pibf[jBAnKP)\XD*6Md-nrH Lk'o-Bmk6SO-l=d(Wj"Amp!VC ,iOF8IgAb7_0*XW3o`/eXiVN3q2k@p=+sSiPVs7$1hR4b@MA-'Oo_9\hcJV7AA#it^L&S$GV(m1FWq38)d\CY-Bq)\ZaHDdA%"5-IJ\=S(-)^BHEJm>Nt'fdfi-`6%+o(qa2o;j$$AN\K=I$'FEap4D6p8,#L-8%-oUFbgAWiG[nD.g5p<%0FM:ef*AtRh5jJE=N2'fciPam'd#\@*R>?2Kr3Yn'RA)($i%$,/eo_p!8^#<[%1Q\7p!i5eR9dr9jkE#NfPej$kW,&Ar3N;4ab-a-7a,qtrcArL^+7<6@aO_ph;C`j$TeL^UhfA-BjjQD>Xk]nEKF.?:ASU8\$A!@r+XLUlr?[a,@dfC_fN810! D!KYBtmVs5+#U"I0q_F^A2nfF0RE>t&P,`0V7._ajj^<>Q?tl^!#$O:tRlmHd!BejK]aqUCaJm0[Vjh/*iQ>D,-;S]XY$Pn2@3lh1(:AnX,,`4?'Z0 J)_` -Wr5?\r2PV_bA:h2HL'/?A1($g0?SG!"=:N+,8"hqI9VYfN4Y3?bS<;[p\3/qK:D80G$EUb]tgDU['[O)7Ht$c.7WT,dep*%&Ta_R,XT=n4G4M!/A.04d/>Y8'Z=Cm=,A'a!=bhRADYk9?sqics9TMQL_1?7:O6E:/^de,TXZ3A?enI)&@ir5U*9;HYV/nn$F"oJ#@a'%*,m6sHScVQFj/Hff/Nr ZP<'V6FaDYH4<8&i7ZTs/+FDH>2F,BP&BAM`9`$NTRCi7j*,a\S!>O?4rCV4]N1_$p>]E2eg aJ&sA^,T;n38Rj>U9,`mY@_kIsY[fbd%XmmD@p7A6^01L1XcG`&t+ISC\L^,7GYI>)'Z +t2.DPsGO!hae9L0Bt*U6D4g.edlmm;g(;=:h5:@d3k?@^!mnT%cjRpQPE8r8BA-70K6PS,#8mFp!^_lDl@kYfL#XtMEG]fe;d%%5:(>Q dF`cZ/\eA)^l.`3dPAi6(4VAf7jWV#6jfVD3.-7,$aT\ICYnB#et H#1SLfA?KNg6lPl`.0bdRp?Y!rl(JUm_?X)l>$/_!5]r.]f?M/B+HiL7Mf8P;A@iV:]'NX=K8]_^$, <4< qPK[gag.V7WHF@&ZKq01-"8g3E?]VK2ZLpmLgehF%SfQ"YM]W?FRJ4.V/G:jGpe\bjt^io$r<30]HJ"2n7H8Q\"o.=BsfZ\=+o)@B>S5.f]]Q'K4^bP3Tj0(q&)eP>

    6LjYG/,CVt3*DgB`+_q'9lK'-Tb+s)T27FJ[YR$Ot^!(W$beC?m[DgRN548N&LZ:/?sXs!F4]gFV*DnRMB`g8_X+a7qa^QAVgj.q0!rb/]OCp01ToFb%]qAHj,YTY2:PrfsO@?ajC$P(KShC T<[^'gO?!f#B]].HBS`3X#p"':.l^7m^,J1843Mah@-qe*)t0ZG2l3FI*f]EU8CldM29$WUD<2m-&'B;kGU\$gsib7(8d2@&-r b=Q1Uo^rGFmaO5?iK+A,A7">b#Z6GpJk-"*^VNlaY> qTlfc5K:mCT4t!Jk&1Y<*CU$'d5qL">s#F4@%W&+,[e&G(s3%Bdil_&+d=m#oR/j%1CBn,`;\:Xr-` &9a#/A`5`^e%V-iR4X+N;Tl?fAKpYV%kWL2P)'<tB?j2QS-4Hol\:8@&N[^?aG>eB=4P0)#T+B,Ll@Gr'XZ!^g7iF liLoAG#MX*kLKX:'A#.EP-b$ZDpdgQhP5A61n:&B r_=$g-4AR(IsV*9CbiWH7Gs+mA+o^sQ?4(p"B @?:B!'*kpj@'^:73Y[[P.WoRKeOm%066gH'6B558DqDXp6tOQSsD"c?6;"h,msOpSBYjLq(QAJZD;=Dgg@Nbl/ d_$0:fM==X2\=m"j][d/Z7K1[3aGS$p 0.6ED74l;g"3;7*C'c*7U8NpCZTr$^9FZ7AWf.EA<X==C-+F<:$oMa=k `=-7fS!_qfOJciIZE18f_e64JQU/lCF9Q`"1^qX=6iE)Pk@s=OPT) X&<$!i7Z%]alK'D Dl#VCl,h_c"I:^IPNUWi$dGM8@sSr@&%B'XcqA_@1a6eMZ,)ABFo< $hp]9!R_@1daHGd@)*KXpgHq2b6FV7>O1&aYi/!mVUmC1Ya`` ].M=JYJAX#q9F'k-#:.YAn!foVE7lb9AbBTX$LlFRR&Qj"%UdbQ(2CIQ"6W$NF4P\-e,<OsZa<.P#_aH&SXJd^G+rpNtIl-4#AFM1&m,Ja$GNfoh=e>CRGR;G72S1&rFhlAOQH#85[.Q0<_FNk+F\iUYK'Kg+,cYkkO!Ad6S\<9`n`*AL:MH*-NMo %1AQIYZB"lPft9$q.4K7$fiQfW@05*2M0Q,gaBYj4]Al#1EPUWAs)pd3/fM&;3C*le=YZF'sQ!pS7Tk1+hGA2b`A'cs*&&!#V2;*;Jd\7a@S/R$8mgLpcdf](QGWYAAF;O":QIe()+[::3&Xms,6G#7s04PXnp8T-Dor6bAZQ.i2VIC!BCm&,D5j!LJ?/+M*i_8t+s6:!pb^;qM#f:)k4&!rfLUQ/-GcDq9%?$qtNFe#4:"*"IQPBZc]61@(fT!7/.T7 -Vn $2>%%,jjIb,M$`L-82!q1&?%W0qpDCFWg@U18f*%::H%sRL#n/t.r!gg/?VeM"DHH6AI;+%a)h(ilYcP4B(lrq?$s3RpED3%\:o!((N)]]FrJrRO)"A)2i)t&LQh-l]WbUX=iP>l[Tf6MOoM7"f(:hfim0*@?Jio3=If%"H96(<8;7(M;/Zr!t?,=K"[aD:+6ak;,?&:;;me?f'7PGmT(B\`YmFqTaK7 :]4\Ap7$R:^?Xh0qGB$qQnjGaNR1]"Y9T4Z% T@pte3Q/??@4*p\^73Kr=s*FGJ5e!#/m33Arrl1]/1g6)jSIG:ah@9/aRR]To-!toL!hb0%I"1mJqi[H7@fT8+N:)"gCDr2\<AW`3q!)#6klf']q)P WODh:JMo!-AMX &s9ZA%:raO$)=,Sa[sBp*\`U.^^?J5nj3Z5Z*O>\Z)r([G.%e.QJ(DTm(TR(F\V^WqMk,^c$P=0^/noT/AncjC,c4>r5OrQOU#M6,e2U0YcW;*1$P"ZM/1Cbl0?dQ^\A6@3:Z+-^nph]2 2tc#>6&Z@6[*B7]fGA[cU&)Sk0UgUe.FFA,'Xd`6epPmXfSsT )-iT>MAi:\a5+gl/.pP@DE%'St*+r;51hk6,/4TCUejW %7e$D4pQKGFW"r=h=a8^s.hp!?.6lI_:h]fD:i5=@m"3>^XHa\R9KU?;Vs@_%3-3>$H4L">8ljV"O:4Wje3#D<b2:2(,`RX*qj_Bm_%sOoN/dqZ?,,N3`Y2NOt2.dW8U\?OLiMXHe R/m3QtI%f)qNU@U;sfUb*HQBKJXl?p*)lf[K"UWl@BeAHi/q=[hF-*`:JtCM)I7XD:,3%tZD(LV`d_>e@@>"LTS]ShI:!WRml\NG#cMosHE@t<1Z]"@JENC&=M7gW5t=D7Z'.KtN#r?fF/a[r-B20%J-,A&5A6N#K?;9k5Yg!:b=)Q,4jXh@>h$@g$GX"sH8]Wk$\qB"0*&3q,dE/a9g>*d^V8Rbrs&J[??YH"c9<@QAkj..T/nnaaPdQ ]s.-#&m/+,U0FA/lA[$O7;lW].`r;](S62JFttJS_!I')O4fZ\4AlMm:7d1'f@2ZE-O*Xjfho)O)/:*.aQeFAA,hiAFjV0mLH@tK5 '\F%m;g?AM]]&p%A7S&^ab7^5^%P^t?GKiYJ`"aBmcX7Z\Q_KN\oYJ%F[G'>Xre>-"9R\O\_J*Yh&0([Aq0OZ%c&RYCWJW[,.KEo;8/oUC2PRM6-\sAqF?TXll'2^$TlX2OdR*W7PX0$CmK:J\MD#C*O:^b!*+rm6/ 6HUi^hB8%AmmS=cPT>9e;EMLUrFY6rAL`Ni]UQetHfeE-9bo`Z>!]C;$k\mtSE!ndgq@2pL@ i`m`fk#OGRcTeUgCB.'b^>sm s:Ib(j`%Q#. 5T\IldJfhF^kdIAZ,*,;8dnT7Abkag,]"-nL$nb]JCWR9L$n85 [f3'd(WTmHGr>$XeM4p&fd+1bTqE_jfn% kMPkXk- (Q7V,m*VYdCEZQrda(r1>$A>;@a\/)=joY+?"$%AQs?J_0p4Q<Ihck5UXW>:([Wdq#;/>MKeH4kI@m30otpY[5jAI*4g'\f0qiJ5f6V-OmQ`B^LL@AIK$or:nOHa.N`;KEh*cQSNYD.8h9H%HAn#`=[Wk(?H)?[>6=LYJIbm"QDW-4c+ES6WKS^P.?Y^>1\O6Y44l5WdA;.=;(ZB";qm%i`^;mS?$6Crjg;;qR(Af\1ID\QE;cT^Bl:> `_ij_8>cK[Ut,)DhKX$NVGXl0RG`GKH+I/H'Mn#r?Y"67Pm+'3M7&FL\DFWN#qGIhK$N1>X\23%N#@ c4i$s,^>tNSrY&Oq@#N?*R%D$.!:QU^6B>pA^.Xd[i/Je+e+AKb>-=H(8jMiD2BWi%(72F>()`Te^1;b@]nKGrX1c!PjC"@q0f^\Ra;9r-CVIT2.XLQ\GK`/oQQZ<'WnA?@>P#*3INmY$R0N3-pAO"lRsDlts!8i0NAmC?lS"A>rdil+R?%WAg?/jT@L@@? ,3)P.J(*Ps6FHQ^lM<)J`B-K%Cr=fPLptLA'c?r.\Ji36@Tnmfb*"@gh_j*mN2EhM[]55neP1'#J[4fb!!j6eA!/jA]C]7]>mii%m=o/Y>,q^LSS9GUn$l@jn?`t98@ns`IbS:>mI^smC%qm&)ms:S1c?Laq4U:YlM[>bH.t7!14F d?pH[HPBtA%9E%7m]AK4-?q'r+eL b\ZZW%j@#BpRI#UhR:FNFBY,0 MX)UD.@V&bcVAB!`\Eq %Q74!Eg7O%CDk'-fK9/49\5_ bP*M6qTENeA[A5e[MDmk7Ncj,l]a&\T>WVPZ,>WJiK'_pS(i@HR":0-T0nI\pY_5f7\9]I(!&otDqY-MRSX+th4gU)pG0KRJ)V!VGpTDiU!:9MilXlsO9K?O.#Vt("0Rcq%UaAoM'l;E!a[Lko%C3qUa2/fgC%Ako9!#8Cs!X"!fOk*(.s12S9tn`,SFBF9#n%UVYKTo=+FR#@C"r`%rH1U*o.?Ee^YH `WRM-kSJg-80T8+$ofi&gJ.0SQbUcAm=pY63?SmfL.ZL:/rA RH`-&OtN:T$-4Iq@O.r$++jHcbd^kKr33*?KYbt,'e9\GBAJ2;sq-+]r$@St)O ,H_EFUaBX1MbN*f/1W\hjrDLK"R#ia?P(-an& <7g/@11^/Jf9%]6Pj[1)6o$i.Fc#q"5+gm-3HPQ9gbLp7FOlY[j12JE)[>Zl!Eo!F#.nSdm!s(;$VL2#W`P:.^L$0"c)/'G,H"H=08o_%^Q7J`4>Z17cX q9dWhZL:IFn5H@U,.-1;q%U)%cqFXQf^=[h5p*3C6_>OVcsm<$t#-(/g4o9 >U/T>>Le@?7D(P`R`Z)?+N`S+**I#1X5AA3IJEUa";l$>_G^4 G`\5ID8L$31/]a0V[qg+grWO*^sPAga>D6[hG,jX^W^:"!D'2WRQH+XA-AS+jOhS2nR@3b3ghn[,MH@sZQHis+d%A)=7$>IRVg+.r9.TT*ZSkmfMTg!':t7QUgk`b=(HD8ON?gf nOjj2^SPXoCV=HF_[P]cjPs,bH`r4]:2)7M[L*st%2Hlf&eq@ih+Fsop I(EV&oU.%";\0`@(;)V>2Oq3WQoh$F3:E6ai-spi^T$kjc+`rD!cWK($?kGN%?T(*]h?eO+T_E=)8B5ioL6W7<9)-r1cgW.XVf2Y3R[>+0]KiC8Bh>,C!$HAmQ1_8>2UTo._a[[qchmRnN2A^`BcgckQW]r(._m\g_gGt0C`e$GJ.r-^B"?75&4q*)2CE^$F!f.;M.]>LN7P]_(^:2DLhTWH,:)A7c2sJTbDF*e%K*OL]<9"O:tWeV%]V=h)>r3!]l"pb3;\&!Zk*iUn;"A&'Wnl!=ghSC608;A@;mj8!GgAUm&W./c$F+AkA1J-P*ma>Qoqbn\;2<1Hbp;/,V^(G'c%J!8WF76%+/='$FK)!Dt>Eg""2/4m"ok<#`,Y5pdE'$&>-K#1FnB@76/(D#(pp))6aN#*;)ro'7Eea6qGsg"6qln-An'9;TgLrhd;:d9#["e@<#'AY6PeE6DnRL+jL)A7jA.qGMNN)s,_\.6EjDZ?.W*.#S,9Nq-_Y+57LNA;qZrB+4"aOr4lAbLcEA:Md5qQ.QrTlnsYJ\TH';5^F\EZD`<$8sKonrr$J&2DZ@I%Ad:FF0I)g`13t,rgm.Y8nA[.T!+k;kjd.#Ps<2JCCb$ksm0732;Bp*XjA5F"2G-e3$rrAbc0sG0HbS$N)>L-Up?fbkQSjG9mr$f.,nZCYJ.o[S&YER?3 AV4&1-6#LKt7+C") \\@`B^Y:#i5gT0`(\E*Y!(.H%c9h1HkNC(>sV3XPgi$%.@YApoiOIm/=!4@,]9Y?p-5fN-f4@i.AIYK^QVgA0gI`W&*rI?X=Y?^/98'gIYnqVg[CkH>c-XL-/h]JSU_Wl^#C5I9GII;?YteE`t4M?f6'!T k]rUol25g1I^2k0/q6UXhV16b15[cqs]P=n];5plS6BZpITMN,$I4bm0aF'b:Tpmc^JL0/eg=Il\&:T 0JndFH$n%CUH6dCAa/+$SSGl?t/2YqPIooLf^_&/UtoL[WN/\,qn`TD\/k/-b$(!+2 TI[O@*1@h;scTFUIXHrN(+);jLZ9&oe'lo7eWcX8/ '6SQ3W4@bGC/N01^_Xh8b#Xi3rt^X1Co5OS]JrGQC!&V[bR\?++e@B:Kj:<\"#tDm*&?8bIY%;V1K,#E??rQEmr29fO!a1,hgIU)]U_6/X`6n)5rok"AXA`6,g;'p30]t$l!@.8M'XYZgAV4H%N\a1eG$Sg W!Q`WD!ga(r/tXFa3WA9mm5LMT"Xid&T.q.Q+VOrj#.(@.!hEYB*Ncq-et0bK+D1W_T2_Z-'r;d+df+7dNfC!To#[$RL3J[]\:3Ns+>?4J:Z4-if`L86=TD=M4ot8!7Q"N\+%\@`a5[0`DjbRiT/G2IkOpKZ`?)T8]a[ELKqFogA2P1ZGJd`(hA&A*':c8HM#3eE.sRcb#F&,r[B3$Q7lZ&IW%T[h;>R;qV04CHjhKr8/O8IAn;h>M:5(((d1J5?qAS']+."p[kK<n)a6A:t-08^X:TejmZp1E+%;Lg%lnDsAMt;)cqgRs.^1_W\YG>A:QH+1@H;\otrctFi96"EQF_m6E@W)S(oUA`pKfM@Y*o]Q3K5iCR.gec%4XOTf8e)<J+7=\<2Uo#IR!m::-% @%$;A:eqS)t( @RDj=GbAYn]%$H*;Ubhkm8eh\1fbKl4('*`05i1m"3%KGUS_G*0 _k,kTJ6X=?A\Y4Wdl]iTonCL:t)L.ptEB?Ab+:F?dRY[H=37M.JrRl"YAjj_T$dLtbc0Tkk4hRXTaAlFt/HcQ7HINZn;Qo?\P92q`si7W]WQtlC^`EN :akD;RZHn1-+WTX,h'0Z_s+<#2+_.4["s"tac_C-WhgA*gA4RGnO,2L&E8$Mf[mRiOj^!_Ec#cq_\TEH(>QsBk^J+A0rPl2=Q%1L+4j+TdUJ6)B!0IcqMfR&o`]Gsi@AgLV,-Kr-5l,*I9(==KW0CW-?Q"-WrnqM6"[%]NcPfP]nOkckft\Rj.?A;FbTC^MfgBhD- #;&rM$( ^b#)Y@;HJ#@2g@0pBj6PiOlX%A6A7R2hZPZk(8HfP+b1GB38&F=FO+%L+j +d:J#l\rl`nAbDEtdT/8@#s>l>f,t!.$L-XjP&Nf6Tqc h4eIsWcAEd:'E;:#6Js6sVS]eB9s)q`L,-1iNKq$F0[XXIE [#[mlZ5Rc06dfB>A:% nb[n;8kKDBN[HnaPpI;=+F*5n`Ttsr0^_&@ YOA:$[^t[#A=_QQ;VfHT=4Ir8\&" f#?QW>OiSEhrk @shHirk>9/berZoY>3bH*PtUN>nTp`Xs7[2hAJO[H,bbROhY:RFqsVN+WtV^Ai*Z_8P_D_j?f!4[X0GJk<6O&A5'/SCO;:P+1DDH;n2O1O AADT8l,d3-=Ar*V>*IFR6.jc8CN+]s*bZMR)d,iH#P33Bq1ABaQWr<>R*;-@jT><98-^5CnO>p8]-G))41BD$7M,-hCAc'.Gs_DRC!gk>HSIHHER,+0afJ#(%9jJ`@QF%L1V;GfpAM:`;<1@Of(UC$P@(2TSLo-g)M05)F&*b7Y9o5A(OP5R%WL8rJd9Wbc0L.enUZ1F&[;ac7"!K,,NW*5]>>,X[>%@Ei37q,ro5LRs$#eLU1j&YVO\@A%b^MK._QBm;4Z2.3X$U6RZ*eOA7$bPkMd37aQEma`YiOa*QU;G6KR3X*q1G0K-Q=m1Ok#lE/gI5$A+-of5>a4\^%)$)=4-stY;Cr/]T3AHqY*,W\_K5-U/'.I6@C_A$M%G<8FD X0-s%l.>p5c7/)89RL>$-P>gtP]!YoWh?LMM!Eqtg?a,o0mMrYkjrf8?\\N)A]k#5&@8-%)RlN-3-!R;P70oq_KlO;CAAP<3JOr^sV:24rt=(q= $oQ(1+l%AK55\P9?t;BKMV>5dFHb,iG#<>#X_DMQoEZ+H;WXd;G=0+ Ze&@M\A5C=B:r=1ULSDD]tHq$b2sYXAc#':I5 D"YR0=LWXee[s"f4O &-l4@8t^qL7l4UWlQ:5Opq%*_'b]j4Ik^_kH+K5(@Of_fhWAs`_D^2o]]=':KsmcPn99VoGCtCKP\73;K?l>O3gF-Ns`_O^l*e3h(FY=Ddt#M?Rhg^@`o>-OSSO&(G0Xa :Zk')4ATV0/&##cWpG(AWj ?*kd5sqG/9.H]e%GKb*bi'Yg>K2bEcb6;fR'j=Pg1rnSL<!.=h.H2QJl\M_qD,J6g^6>fT)a?@3pMXLprO>^Uo4`ba_"i#tt'CAP*NP'Xt6tan_SpOq/Hs/N3V/PR9Y.>h(#njXVjDNmDSLEJtA$\V@C[>fcWN>3(Y9/(\,]Vf; 2p(b@$72V; )\$s*HdfHp@j>DLD%N@gf?:_8[RU/O"Q[1jALA"[='/OAA)-i=@'636!el8[YdW/V(-d3>T;S2Oc\PR3QZ+7YGG6#d$ mS`#CnW9iANsQEoRP3ZU2q(@/AGF$8MWB:bObcRSOR'/;6iOD@iWh_M=/Q;fQ@^ P*ipN=7GDGqTC],@t(@%+1_LjGq"%HbLc9/IJ@Zl8sBP`Mc8C0\m5:s4Mj"gZ&Y3LhKI7+`m#(@r-R59\/I\$0$X!e p7W>""D(/k8OIt#3s;/0*7bYoik[F]4"6@,2'" WP@c5?l' J?J[TFE*d-oOSOTVGq:a%giE%Flg.bE626m-2i1h06BnFJULW#!20?:C(7D^9E0%hrZE&H^Ve4#j-W68M\.!SdPG<,UA;M)Q -$[7gT;j,N\08e"\,;`6X4<^2AAbe0HZ`Jl]\8tN1P]-HI7pV:Q6DD7$k(pQZY7#OP-G %3co4:Bj.A`A5_iJrljh"J><-ZK^Gm.b3[QcPripbVm/EU0Fj:Dq$D`/*hJ\*8F8)'&O>YHQn6MSkmMdT^gd-NqPt m=$6iY6M7;l!l4CB>Rq2N=O;YSUi&bA8>)R9A&KJJ,A\sBCm< "'#!!I[*Vm;a4Nh2^f10r!.p:LjdF77_rg@V*XU%!t+`#/elU\2\lk.@Uf>0tR8$?qQJ_:kWKJpe['.iiP'G/,Z-L8pFOqo`KHFDsWdbG0n5aiC?><Ha\cmVls(RBdo[KpER8%FWZ)gJ(4GKPZ7;6h\daAa?j$AA>`bVT_&"A+H\hW2"p!4E6CrV$*#N9.LL:5tM.KT#i;\bJdqR]B94)i0;I9)/;_5_SR"G4T/Uq?_3WmY*Yq%6K^dt:d59p`jeK A7Z^U=OOjHR2FeG0OT>S=mT-A#'Yc7s s,@_p"Cb#T>.jI/9:8;cS5=jsSXE5H?(.VlG3CVaNG(*CBam!?S5B-Oen)\\p>"\/!i)ka$m0i,8S6no/o-glcW&PAcA![7-A3DVSAA9js5H_.%CH=XT83\Yq^+er tWe,P:FIFHiE=1K&;&5+@jj&N!]%i\Fq0sD;9cR ZO0P$4:?VT.;hFi_??dcI"pDeF4U.(BS>`oqn]VA:TksLA\OW18p^FJhqX,/F&MDPFm1GfAd_sUVC2P DUC rMl@APAG9J8+r*(JjR;!7Ddh:nN#'BH7"Apd,iKd(&LW^Q*A'W5$=/H)Mn\2a'h]OXO["oUSI"$;c]YhdsU82dWk'L.ic o"Wk+<:X"N)e_DdrW1_OL0#ap []DiN\JjPe"lRaZM8r4+ag'7=*4tNbea=?;2HK)6%?tD982!sdEd*VDh,gqGpD=$j;q\mq]c=r@ .\Zo+Gj"FWL(@/4[T%TQ@=!b*! )TK$!Ih8)i&iP1HbDk!G@s5A;RAKR+JPgi\Y1jK1l&5^50S?LMPUI]rfD&^6>LAf5[7MmdRNp?/!:!`3@ @m=/9C3*c'&=Jlb8^?o:`YhO-5GrBbqW0S_*:D6G'AcGjrds#LI!^7&RT9A>"[=bOJN`4oW7f^p`S^J[<(iA^7.$q0Ad9s=6-AcK4r?h`EXp9(`g59GJjHSm%LIU+)O` +05ZHsoZN=h`'"FOc:T;@_7CPD-TWFg/7UUAQl^&,_)IAt(7^3g?X"1']/&b>FMD5p%bgqDHd'+a`\*88*$BeHJt K jm.: VL)cF_=R<IK^\8Pa-)mPR,n3bNE["S8>^<&hV'B <.p0\F'E;Ze?3+C/g@2-^LPA%-Wt%Mn?%PoB[r:=U48X49Tl7jDQ-WC!LC:%#5l[3b]>e0TDkC/Kqs->A2$7HgDU\Ob=*= a(%j89@-bhMa9GMka%/')S`S0@2kgA9MS!rtX65JBEmS?h7WqqkJToGc@S^qK7S0Mi.@^WI'Lf1NZ(%hA^))K*%mlBs7VE9M tNi@9SNk4F1ah3?<`WWX!^:b("rKN1`qT&[))Pa%h#?\O?s<IT_`'M'^tB9+grJ3'/<]d&Z]O.n1A WUBlaE-n-2TDK1h+)ig8g[K <]]R4(#9fM)C<]\HCZ1YdaJjX?+K2#mGha3>2#YYOVBE#jcI7CHR__T9Qd?/Gm5[tRf8tW8U'id fS@_5?".$I9)1Ve?9J/?hL:rHa>f<>qAn`Ug?i^R=2IOYq> Q-WJa_S&]S*=VhPS`-%pWptKBhe.?IMc/G3B/#m9lI?p8e>FFpt]bT6hP,(b6o6=''.p&rYZ]niT?L(JV.1*I#qm$qGU+@1a@cLdC+IF"Af(l1J6PA(O?[RbhZIp0IFooE-%j...DOF&]^l 7J;6pC2CJ,dd[#W1cA'0Xl!nH:a24**!%kF6\S[cp!PhCgTLWWPsr9lV.r_:HUD"PWti<@6R_W)LCkM<kp0cnA> `fcTl.;1+rhbXX5^=(Ke@^b')g,WcdX]c'j)@KIc\Ng'-G1@[:J%MJ0E<*&"f3MT*$fVTQ4=:5l#pAIm+ns-,:R(0q,.ibo*21jq`5Mn5"UXX_n/J<cg6c7j82V\$H1!mlYnj7M0AA[8X#)=UG+;Qm5G=`5g4*;j6q#q/hiOATs`oLIBa.p7][34AJe_r/q,N(CUMO4Seg%:(9s:FqBnHLm;Sp^HNf%fAs6/DL@GS,=F2<lY+b+4r."IEdri4J3-e$?ZCl-W c`+sdl8-'."@;dIr>l0H53.1=>IWA?Ac3_th=HtF?p-i^VFsC]c)4E!>+AQN@@\?IH*tN:NBt$^Ab=?jj;lm;Cl[>DV.MJjpeXd19lD4k28tCO)^Zm7kZ'bOjG-Jnd"A">-m;hHB@g)p8ZW.j4k^0/k7DRD=Yn0=-PD#]%5kU@eK.\H;H59XF[(hm]qV"R@"iOA1M"]MQR5, 'c2=Ph.2sbD+HmOZAp?_c]5mOg]OM;1:$_QkaS$csUnd/)e2iN4>IN9UAJ(J 0Md^]/dB3N8"^q.j'bfCjOSs-!rCKYUj#;_o$54D,Lq3H0MB?ZCI*C6.%P>ng>EW#9h("sMP8(B4l;!oe4)'&&,Vbd;P-%VH8&q:=/e_(4#4/:nNho\*6BbMqG6)56F>gpEgZK!nEWS,T?r>,ApAKD9E lr/1E_Tk5o#XUdGYft`5194^WV[Q@;jA)Za1NOQ-a"5;LZ'YB!6RfA#sZVIf(\6B\irp/KYVa[N*8m8O(MK9+JD=m;iF4VF@`7?mhKA>bdE50AVVJ6Xt_#pgZ7,U"B#=]*?mrF3MAYRfA"- N7ZDanqj(hK3T``#mfi,0 0tGA(LbPL0k0DWJ8XS82,b+*YF;#;_&6-&Q]tFMafcfC/\r_QIdc kd0.o#^clX.E=3'B]78%oRLUbCd8Cdit^GnMsE#pR:=qV0% skgZGnOK:scEd30<*f'dem[/$!B!jSRZah// SC29rRbrk"!A.i%[!Zlg:&O6%iWnM9 8^e)K$` .G-."W,QN2rnGm(V'LEF*IUT1pmH=iC$@jp!D@&C!nDr>5FOj^N!5%Q<(jF@5<1N7^scFZ"ZpkQ=UKL`QqZH&"6Cp'(Q,H8ooqZc.\WEl1 a<GHjI%;4#!Of%KUc\T2o ,))^fP#[OhPE$(3N.hBU(Op0'?$1*B7"I)R^IA\8_G<*j6h>UR`><5 Y^l,ld/f28MJXjV&$I&T>$9g c[K"d\mc7OV#Z*Y$M?`Q(QY\,_\/@r5H \McYaaR#CV=JK(A*.LI_aRAArY?AjK+R= Pn%t'3dX&ZJ-YA9p(q')@2F:GVe9V+7j.]pdMrT QF1V:$*`@.?atU6Yi;0+;oNA_'Va0A38-sf6#YZn_J3WIfF Fsh(TE64S5-=Z/L)#J7S.Hg_oYN_e--jU2oaK=peMh`Q[$D)dI5q3tA7VDD+,?iG=f*bs])J/8;qOam0mcO$FXp4jQqN!iMM'KIE:l+He=U[8o/9/sLtd[c3oJ%:Z5hVVZ"dO1$;idosNDg,(A'F!NfeY^O!akMYg*SM??f73PL6.lfHY`r_I]-`V;.\A9j8h0*Y73ZUQkqo!Io%i*+hO.G@,/d_%'FO9dP@^D"l&Qe*-[$!^=X)tKAH$:TAK4KQ"MFTAk818%GnKgdSG]J4p\8K2ZN".1om'PN+i5)lI1lhK8ik#m3jVY'W(+!%_n*W@.KUQ+Tq0-JE -7G#gd:ARilZh9/>]0,_:kTKm!F_oHrV8Y<*]D4'tSieR&AOkf_?J'/o:qPdReU)LmpB j?;In4k?[tAOi+DZ_7&<2GMK76BM`qMUc#1#^Xi%(H1J^OkS;a/^ANh8e.=-"J.f0\P$,h"s/,sW"Oser6QcaCK[D<^:pbTZB_$q;0FT//eqJj-%KFO37,%`6kg6B%`]M?"8cte0V\*W#&WL9:5a+,-(h8`;;D*I@:ZoS%9(oJoYfGoSgUJN,N15"(I/G?G$G.t#nspAmaV4KoAIEQbi-\4R?t>Aq6kVE>3X"XFVNn;<:;]r%'p_N[pjjeJ]^W :(&NdMqg"(!'F*PoO^!\f2q!S]\Thf+s;9AI_3-SA@k>p/[Ah'WtN7=#f-+k(+p5]e\^jQB6-rDWMAb,+K0d=WmR.><:Xsg(fR\tMOkh!5'L5@BsTsGMd4A+[ZSZIp%/$aPAAc*A>I"h?d:^? G)snhb2eNC[(J8=I-e.nb2lLLQ#TVNLli@WnK`PXVI]M[ki^r0Se4?W_&9M%)\]r/0lcJD[Rl4rI2qG(_]^1,`_RJ#YA&Y3JI,eHKKG@p2##LQX.89hjBo!t_,MC;;I!TWAp>!sjf.^,+sZ=Hr%N2o+cSk.9lg1d!]4#MX6(]ReFA=!%"gqCc-MW,8#C;c=th*btBtJap]K\^+lV?\>[;Ap8<&RsH8cH`#VS^J]?gIJ5lo'9Z,GC@f,AT(>^dS2StQ+mNQm0e`6\_:)?/Wr?,_^'ea6XtD2fY3$hTp?eTdaG<+,!fsOW1-^B^4:8d++a'ra]JQkMO9V#V2@U_YWLW0L)OSU is?CXFt'5KA:p3ZY/Og!=ImOhfIR4@Ebg3AAXGh-Xkr>!!?CbmA;M$=]<'C[W.i=B+s4"RG.)DcBm(Q7PB#I2MiaYs?\VeitrGO4@U"ZWW+>5V8/C#.hP(`P.9,&S,8[6IO?BUO.oU[*OAmm("Z=4_) RX>'AjKETf+?Jt`28%7n%dnU3bRc0=>PnWVZ0_j+/a5&kI$G_=Nk"nAPVWhe0PV*tIZD&*-^]gpV0E1P4A]i,DH8j*@-@=W9'B2DTA\Q23k$K./AVc':YSZ?%dQ9[d!i58q!6$qP*J-.i5JAj1[1J_`lK\6pIhQ`;pA0'"XDL0#0oV;N[mZ)e$qTtNRZb4AGH$S(J9=ACXY)jG%^ggr@%IsTQkk:ThT`@^qJ8[]qPj8$.lmTp,H<71TW@ASeAY:q.[0mZ5N,sA;VkN=6?j$E`[SPR 3n*:ND1c1-L1KU'-WPH6QA+/E_bph'83j;eG**giUl6ASo[]7m2[^T8G6jUUd@prbCrAOVlgIU[9_chGe;^X@ T.a:+&tptA0%5-p#@#$>r5T27#jKEjFHtS15pplmSM\mO`"FsN)d2jm9KKme *OTa="`gABf'/O=2@,e19XR&<8p:1L&U,(@DBYcCGOIeD7ajB<-fbp'\V>q7n>o8fBkERO\?Q4ie#pFb eSs)QTR[pd1`-YS=Jk/9Y**^`p#YPQENmk6UU-"]E'ZP?^,L5SlthTnc2_lKd_>imUpXBVDmRbd5r2-O?G8;6=,.$CRMUdZ9RVs'oPB *U9T*&Hkf^]Rn#VHLZqlh/JJ&Y`At `hPB&TR"an*#.J0E26`+CW=[s;^?%gebsV+[^`EUZ'aFMS!NjmBc cAG=VO+]+M[1rgR-?5lOMiXm^@0X1"7j_=A& Je2mMh_>M'mat?$)l[S'YjOsH]l ek+Ls5l8 cP,=`MW@m UoEYnV^MD/A>4mN=4?S/Jf3*>f%V)B@(;A$Bf^IkcLAq-T(f]i`7i6Xf:%=0U>X[+'(ac:l7o#[Pp;;`&D+CLq:U"/k<";m/K[E/L"23TMi(bf2L6A0'D3*B1 U.-]Z3FHJ/#@9'V5A;Tah)q8)4]JBp+%7>nmhS?e79@Iq/C*J_5r@9_ZdsVc5Y/k`BkgialL8::XP*%V[cg^&Aoje_/c[ms_4\N3`Xt^(KCneo>^ogjDh,=^/RP'-=q(!%[B54UpT,ic%K+RcrXP9sKD(0/m%>ZA:s==@cAdm`aT]JIC63Q0209[%MM;9:d.`tnKqFhg,3(YO4]4 =@&[?%6VWTA+K=A%`S/[jRA/rCA3#BBhAdn D8p'l/W+tiilb;=^'\GRM(8b"I.[?*VF,+%1"_#J8mL7EYJ#1T%Y3G?K^57Xmk(TQ/&Ajl6^mhsR0CB12Q@$(tBiE0YB)Uk;A@'tJYCab76t1Q9Ta*0f!AdV!5!3%;K!b<,N&mO%TdK 4bOOfn;m`I_/:nHcOq]Uc:3ljjJQop8strF,cY'Z?ME[`ps[+adMHJ2A:?)ffMG@OHf6*,W(kDNM:P&#"f=)e3h%4^]f=0T]1+bapD=A60M&l'b^4HU\la-I-j<`A_"/V#h6r)_Ti8b)KG.K>6ECdLQL;d`VeFI`8=)`Qh0ejFQjJckrf,><6bBmIUJ+rZ MAs)AJ'*[qSIC_e=K*1P0G.nW_A]c%)H*HR.-.g-oO7C N+Ie%aZ]_fDW]:S.9TZcXq3*ih*a)U6k)iqoXs\"*dp#U&eM%A6mVd2[bp&`r$'^UEi&jSsWU,OjYX4r9$AG*r^Db71Ul1M9m8g6+s) CaaTI`9#b)U1AOY3ALhtA#q\_+]PE2TiW'6aZD\HdkD)/Up.d++A%I^#fGKAW]>CtGt@A.Qj%UKZZHNnXer;a(&?Bq,]W*ot]P9e%iZ@]lXcdPU(h#TA7HGT.E8R(h;EB9JT15I]q)XtH'h[0IjLYE=/RFFlcVS)&GK"[Ag`+GcdI?tTD,_XG..XfWAl)gT)7dOFFs3jC#ctjk"2lpNM!Ui0$5H@ja;XZXDT\FMh-m ^D%AIc;N5A.j%o%"a>#'h:kjq-Al`V\]Ih H>:F1hd,tSoPac]sc\'j:4\Zfo<-%foa.F%XN@]ZYm+SIFi3f2)prdB/c$U1)["WitMkFS5N?=b.\XXf4D@[A\\jpg8iNkRCch?pB@R3$:G!X'O%-B!HRanglMWA#5eaF2;a 2TCs_>cEXqFAo7-<l$ ?4krlJ/q]K\Y)j_$AdU"3'P`AblRql9t06f8(bRC&*:[#E5c6cnNWAQgS7aSnn1X7rNM<c-tV+Hpd`MN$R!AL": =LdPZ[D5mg=%sD"TdL)m;AaQ7P_-9A2s[.'TnY'6"C6aFL!a"G][8>&Z0U1iOHNSG BShrT+_I.=P0:S]oA[]6&,W.`4_+#j5G7Qk+67og`SA8X5RB1)K9WG\go0C_ao<m$^:m[JAA4RiVWn_V`c/am _]F#-;K^ HV\QBI4UD()0+e>N-2sI8bQ*>P_NM#%ie,fA31lW[sYn)Z-r#>4lA[C@Spt9bG0YQt_;1$V%O\-Srhr6H?jM\GX"KX!CpVK,)Z)Sa/YB6&^i4TpU\FNZUgPQ#`l5jnK]-.A*l<](I1T)M mQ[TM\;AdEF-n'*f[o&=$SD`oD#*7Kg#R?0'N=FomX:N"m$rM H*_2X1o,RRolm1@Pe05A)X[3Asq<ig!'gbhLPd`1t_,eA^O9R] jl+a=jlE$g+k<"$lm]FUTi`RPZ?3BUU8A.F0lelo#drgnH2oJ -dd6*>n$r0RHNDAfC`JoA!e*.E]NQWh.O8CAM_Yk%s0aaP22;=30;9p`,liM"tl\@(q9K\<%V!ifKFoh0>QWs)RDAA=Ra\o]GE"3"T[2iC$PL_ M, TFR<0G%iR[j=4EJLZ:iHnSsAGCQF;-gd"'f^PI3s!WP[gbp\p2Kg],fl(NBF,k;l[bE'27W%cKWL(J,8RH^PLqi5d[&W%Y5iU.IH5\6PfP"-2htG-L#W8b^"J%'XB6nV:Yk7'bE`sp[^i"l@kZ@\*T0jnA4(]_pf=R^SYRG+EFQe[V&iW3OMp!VRghd)Je+^<VM5=f^)qNs3.KDRBCM#6gJL?:(e1@M\U.&R2AJtbdNO&9 [\-T"p$+PLQ$Bco QOiA;o;N'HA`eAV+654S[o4[>]AjcN/g'VJHS9Ltn7b7*kF5\\`rkP@ChHLh"]W8!;V8C)&^%qLE?Mq88IHbJ-eA$;+qOaB@4kCGY;O=d8\.oRU%s[]O?\D\0JO98 L`imB\!#rHo0]i+02k9"4#)5:% A&9Q:,;sDZk0[o(GVlI*T-W[-G#J+-@r!,AF3NG6OhUcK-hXd(##J85GUGZp0Zi"9_Pj4^e])>UC3I8T+Hol=BE ([Y24p[<]CUcnR-,G=hO3WH`WDo]5;`=EGi3^d7aj#G.r2kEP6S];>ab[<d%03jh2X1\'!2D'sl/*+oZ8;&\"VXrI);dL\(c?1; Qp]/?g?:.b8%J!N`31"B>Or&U"dHHk-+.`=27f%IT+#r:$0SfoeZ%p7[4RG!3GTUmO/JVKYm=5aC$WQ!X^@"9li>0s2qj)2G,AZ6%F&N#lHlaA (B5r5U5*TX\LJGd1!hOV`]YpD)_>[i*T,(*_oi*"b6a-am,)Y"nK:-T#Eq"-l>R9TSU310G8h?gm$[7DgXt4B2i7fB+IEWi`Hi<^lRseL7U>f@*+N_hAsH)J>f?[B$(-,E*58/44`l%/9]6c,Kj)TfCDaNAROGXnlUaN=WIt_!Y9b5@@?@57K-68'\0[`cnBG.YRD@coGCTG*&ChORm*2%a"<'0s7TKC!hp_`.A2Vi,d*)Zd Iq6QK^KSO9[n`[soc&tHMWD`s=K]1h ?BbJ?pH.n>A%CIWKNsboRXU"/p%Ma"iVi`mA V'R)b^e^Ge!iqH`dqTs@a6\7EA(lWKVHW^,,2o5@moD^Q4\GN9YPjq7K4e`AadDQL-R]3/b89]MJ9jf7*2#m>=*RW&Dg1`A)dAjA`^&]^,OV.iYWHliSEStGtBgt71qQY86*KcG453U//XH5:'^R0<[=9h(IsMdA)$%L(R'mAW5BRHkMP\5dm.:"J?0]+b+=Eta#\XFb9VpAZU6;?1S^VLWq$\!V=./:2\+lnHEC=.oMSj/E72a7[kE1ZM$ h;m1=lfT#32?VZoCDnK?EAA*MJ%MGB_l\<&/P:3%Me(rQ3N&'@,b@>KGk`4D^h)Fl$DmI>L:J>^1"MYHK.o^!_]!qj(Z[=!'3S._MeE1GdPrI#i^#jGq4"h\DZ,?i?jdXMcI\MtsT1:(PG8#?DM?Zse)Gi1OC1W:d`69"akP7!>:PcQc64aGhpcnC/A+d/nn@fQsG3D@9+i"GP?G9[f.3W!RACAqVrdn!k/VWJSfoh;f5C!H:a,M@n\7_]oT *>nDGh*r@N?2;9"6cV0-.e4](:FDEas<%>X fle&l=!C,q;6dNIU`;?C#[p9*d+'LN_aX;a.e2PGRkcVPFIk3X*q qM`"jRY?>#E]"-`YLK[C:QTa/,8p=1J7_rZl7XX-\rlM0;$HGfZSt;_Pd/DPlGJ+E*aaO!X['htANedI)<'j+s!KKh@q #VO!HT3m\SF$Bt36o@0tc-ZYFs?VnN2)D,?Nf^['h4m#0;OLSfOA/dcHiX#L8b4dnDs-nV_btDU6gJ+[C%Q!&9kL^.Xh?JrO7jiCTc^3d@;\$,t,+JQOjjf^FUj+*m+*A4]??RgFBWlA]bs/CcX49ejPb08lN]h)>=g_C9`9sY'g+e3;A7At.1j@>4gM^Tk0S]E=;r1Q*p)8ira/O:I+9/_QiRc.\R<,PDD_lGKK4ff**n2A@HK=&?4IUAk2-S-[E E`JepsjP*B-$@`KaMlrHo]6i-PBP]%i]$/FKR=$>-Nj9,m.RmT8H&h.Y5o,Y4)8.MPWLmnRC$A.D0pd>3C_sB(-p%7orENVmP6Q2kd*SPg?M+GB-RBH0'JU%NVt-qg%>-A-Xk'!V2sEXF*"<2[:htt#e L*[AMYK3B$ .lH-Pk85-mqpcW.2o$jlf9>%UCd%E2(O6)#kR1,1K6OPDV1[2$&)bJeFc/R@(2Vr5Ko==WmK80+s(4>Il.0SE XX= )-[W"=@BNT//C4EGCWVSGo5/iZKJ@$A2:5Z:02L1eR-1Fdh[ljahX"+-XaD&c2`=eod1g"_l_mIK,kVP!.1^7J3\YR%G0Qjr9N/]hgAdC3@bE$hb`$[A:f+Bp1rYU6TH0!KcnRN4( r9 ][nqNnS[brTD(`CEkeoLoKAZ-Bn227d-k/%$i?aU2kD`I!Cjg& 'H-/o"E'7bdaY1gL6bpAefnAqJabJZfnQ"^G@%SV)S.4 t>>rrdNp7f5?Rb@EmA6_q@(%OCd^_]SDsbgf+C488AFd%Kn@dmQ9D\8P9dW\^/+g-;_?fDr) qb#AY+T"R^]JkF-n8IP7o:;Q7W=4s&A8?IKrn0U9URPPf0Mj7^q'AL^<(D0:UsbP>HO>&N6@J1`s,&^j/Gi@^#i+YjnEf>G&!)dohal(\&Y^d\Z0_+LC$c6OFV>iPn9WCd`?eM:-Ahk[#"daffELAi^sAqbgKAf9q-+=^V#4:WJa#fI5rFrU'BM:a?b-&_-j&[T;,0KH,!:poUkAORn6L-U9VsCX9r<25r9g\hltAV79W%b'k2WC"'E6H*:EA A!V1`PnSba\kVrr'AVShRN[''U60+%2)kll<+f8+MefEDtmsXgB^;_O5A6cG5j8GpWVs#bGp(;;[oNB9tD,/D3[pcJ.@+@=n\F*l!CHa%KW@(&@0>=(W%mOj+"?og>4b;3Yl]ocT0Nr'C_o< P':8(\3.Lcs9NB8*WPk,3.[_29,Wpt `+h%:0\]?>$5s56aeiS;7;tHIgZ`5j_WONE,e`gJPR^88K+b VMQ jWI%]mc)3]1tOt5\/?;TM`=$D# d"#pfLjUn"Ns=:RX?gObQa2a[i2g&<^(jG.ZQ]>rJcqWpPjlA#EYif^<&.pAl\3=H05lr.=K'@dWb@AWZD .""MQ7dsXcE^g0t9(:TYUlHjY>DB6DgGP>'9[$](VBh&a 0t&@Uf1B9Bq4ef$]sPI'S'"=ef&b\/j'HAM"s1tPkh-^'GV4j"f5sAl%WCp[Y)9HJWC]@VNTf:o+'5_L5 =R[Y50##nJhCEX 4(!G#<9A?oi$pq`Pl&`lPWVAMrBDYaVam"L70VbSbACEAi-;]WP )>Rp4ep.3Ap&QF2Q[C!LI6WM4a*f)62!>29VZ6NG]7F)M'%H@Mjoq#H^+.XZtnV'Fp4H#Cp?055[?AK3LIt#_if_"9msn[+Z V##)Vq\/_>kM%I.,h=WA4[f+Ds:SVRAoHdn!o:CS;ejT"?@k-Qj*2!#eXpm>9RN&JS$Vn6kq%iOQ-g%Cof=`\A']IGVV%0O O7"qqeBtJ)Ula4Mm*86#QQ\TmkR/!J2G'?6e`)6RVq5%*ItWq)P:5pC#X!:K^# 3 E-"eF@s5X9=$AZgJ>>YfZ.iq_C1t^JgZ.4D0]^88G[gsRo+=^/8d3e/(lr ?n4_4EL&%VX Sr$$S]@@d3SfX:\!>FphR;%P$R;TX>\$q=%mafk\@Z(C]/UZnI9R"P%@0U^_pf`opkp8.>?ZE/c&FVqlGBdYsj*S!Dq^8!K1?%mR:g:PCNqagL8hS"T(l[ ^<\J&9ZN%Q!AtVKS;DDkbboAKT'nkBqa!Q90#LJR;..-te=aabVt@40KFBr8h/T`Zr"A-P\1`84Xq\fCl:USe'(eR>dblk.#l^YIH,*rbK4(Ws,:?Gp@d#W0_+.,2aiK5trRDn`KO(+4kemO.lJ?g^bOsWG%D^P5NP*$nf7kFG@%0W]MlP*3.$TO^l 9;i'p#OMAKdl/rKO+jU3F!JBFdg!qXAl,&sR<'o]*p7V[A\k[YNQDr@"oct>!h8eIH.QU5'6L]Vpe*-0XUhJ,5aAkK:6]UlBLMtm5--at 3PA/YT@^D9!E;%cUR(ec5*-SHVfBA]86_b$]gT@ FOG!kf!mUmpI5A\lH,^sN- \%?.W&ReT]TN*jJ;3!Z7GWRW'[\]=Sf%A\GK$6,s#'Hr_ME8DKc,HiE*H@0f*_TC(8^'qCZrbh#.`50hC]9A!oK-Ie?]f^gZD)'sC\JEmKPK]1&6U:A<A=HOlI)9?$ErSj8$\)6.14Xla@eN,lj5+Y;g@A,=V\l7$h&BI];RMK6(__^n\[Z6rLKo`oO\q-p/$q%AqSEB-X"A=:AlDR1lKCHVl.Cgn`4?5C2iS>&g)d"GQDg4PJ,1.ADoP36IMsso$*m!@4"Geh>QM@e]Xd-I"C)D=`:$5An$4sle" +\s/k".M#dG 3T/,,LipcSZYU%c_T&O_/HrO+U,IA.$a+=U GBt4BgpPB`!Fj6< &#:5M<??Qr .T[`"[Ag"O^2!9 DWIQp_/7B.t6+aA/W9DZ($JcYDAf+Ne@iLs\;P`/>C'e0o,0](Clf:Dfg@-F"`ig:*Fr%>HIQ#V/?,t5H4B<Qs^A[l%88+d<$'aMa5Cm.fD9:A=LAHbpA3^M%5=rcnMAA$pCANJ0qYil1jG,8IPA/4.,b/JX#nhUbM%Ynn6S1]*=`pO^q_dlCh7ledKj1HfCU8$"sA=<\K=qKAfEX5+*?liR$rUBh"W`p8m(**5--fCj?,18QS"?h5^iaMZZI'V_qC#JPCr.`&0Q=n8LmNemp1Z32eBO;EACRQWaIaj0(]8dalOb@!NV2!tkfsC?+)\'f783/-1Yn4lV7c*A2Al9*8:;(^JSd#W69%p$jqQKJs8L,fAaCLsOPT5=;+2Sq%VmEA<1h#6J-KpU$0A-aA: $a'NV]oQkk^(f?eAnQV&tVO&a9p)A2Vf.ata,FqU]$KsTf']49JId2t'R"j7jO^$A;?9:0HiEii(OrTP'Wc_G#2W[Z^L2AieEf%=k&&-a0f..E8?2gh7=S^-JY'KkHm;ABpb1&)@lZ!eQ*!QXs0.qnTHkkO/Vi?pGje3%^0`EVcan>G`Xi XZ>kheR`oFNGZ'#pRA4:^2)Y).tsO%g\YYK#n/sA2gO*?MZLNpFXVcY@R;S:X3;9hHgF"N_JDmYCE,=lPY+"&qkIgr@t!!d?I5bMd^Jg2 IVIA=FRRat.b16dEc7l-V\7^Om3 LQd0I,tsa@fG\sOMF%P-K56+\82XDJ445em!")a.*49s@>W6`j)>]E$[5h+b`-ji*Q! gCZ01k%VIBlCt']*a&1 MUSJ4H+AH(BYE&B$7JT/TLbqtY9%K,r)Bt>XRsk[l]^9G?4p&N2.5J)4#k''Mq(1/FnAeCZrKqWASh/Te^'+p>)O\4rL[hY)F-Y+X,,@"#J2m:a@\Wp-]VbfRRl^$tA\!)('E-KC*[K27;KbY#$*l")_lb'NtU:GX%n=[BX`.$6RN5[["/$pA^,H5/*/;WF/H.D'As+N+/6.YYhfjX-a1Cq&?6I48OVR*"tDZ=#p\&cDnbnP6Qe\tN6C_Wt2f@ATsR8]9[0#s*IUI>gA^be#nKI`4fl-]%0qXQ_VM1Q=bY1hn*,3UIBIMOF 3@QLV' )F>H>lfHZs[P[B#bRK_f&d-5_d)Lj\*Z\Q+aI#U)]D9TN'&!pG=<8KScpJ'WjU?^5&-EaU$aU5AK)E5eCIO[TKt[&WPomg8`m=S5j9lUKB$`i GK5+qcW/>$FKQ:_rTG6K,#%PWP qM4f'E^ r;<_\Ja4/2Bo%a:f>)Z`X?)]0.V-<-=fkPIe$tRoPdI1M;;d0&1W5T$^dWVn!CX&]b8@:_AbB1c_V+,_:NtkthMM6m#Lh/PR?VEqb&lrCXFC`O!6+`Ce^5Z$s83MeK2`Ho_.jo\25P7ghe3XQb.3bfF&+?#sGeBp,?"*KNh\1XUqdn>j?V*Jm87r%U+ZCAgeF>\(9SPU@GI<<,C_j$QjT>J3k +9`RcbX bL!&*U5Il$PjL&^W>:$=FcVZ'qg-8VGg17-o1"B:B@iI$$'h:F$5#We1rS,^onIE?S/@%_gc2oC_ AG-MnMZ b[i ,-#BG_Z/jh0;ebCkqCQef8UO"$M1cW O"Li;97/9?Z1bH8MaXEi;3aAC4-2dLtfU@_=>R:[Plg8NkJF<4,dXk\WOq)tSP=T^)b#G+18Emjt.eHFst,G`]Xa(GBJ=5;"/>;/=&* +'/3`Ag kI-[i*Z/T2#ZK'>7PaVO,kW[20(nU+(BqGB@AaZ<4:YdG6jUAXB0CVteK!7Tn0Ai&rq_J4>O>siC:?#FqO6n,NY\_;SElXKtLD7WQ+*/J_Q19*]D"H(nP4,IA)p(M\X`or6MdT?RU5d-Mg8ZU)FIn4Jn4A-AF[mQ`f.a`;j[AgZL>3$<:jcnWk/!+Jajgf<F!&Ap:Hl \PE$KX,Jd,bnNr<$>:;p3reF6!Y!$f`&68$COR <["a*O2dkf]hWRNjKkl2K/Ts+m=@TjE2%^/R8ST4?+*cSY`M-+`dNhd+Yn3d9GV_lTP/3#^LKM!h-j#0A-QJ98d8(DL]Zjm?',U=+O5e_$8E)ikIY\Fbc[PLVco8:NYq/dIE`bYm)0@7Y+[DtHrlTd[B?.TYG02neN7s=fF#HrcdSe#B'R\a(X%hKTUN>-Gl]VnX-i)cVVI4'TRSP-X3Y<7,K[KAqoOIWbhWD18$\*^h P]LL4s7*KdbJcX5HSOLjEJ:DY&SA,nZ]\\b&^r41nPIoQ(83k<:K^]oW940AVfHYIb`GW2,C.G9X*tPI;G+RrZ^c65Ar0lp3Ah8Pc2CAgZr=9DBe8X8JmT;7*%Hkb9tWg;Za)Lj(VUX.>9/XbC>GrRHqtJMLA,,Sc7X:<,SPAVF]iC?=7CX3(;Vq es8I8Yjb[(mkYc%"+j!hTkP_c+_K9"KLjHo_2)$^;:;G;B@`!$Q6(W0G Ajb%tsAI'YWIFM;gE2;05=$db5GT#s4i9)bp//Q*GT?EknHAdeND;ABONA]*fV&3'-.@ae oWH0dCS[?5DK!gqA-b)I7!6-&ND<'@i ``I/YqMqY-6d$QCGOR-IiDk93Mbrcrl4K9/mK*5MP>AQZ/m6_EEti,m"A3X [fY0f"(g'ZQgE+@-OBg]=U CN"=?1m5\=&h0C2G3t-a.Zs5i-PaF1;QnAAZHeio-9sq9\UJ6Gj =W^(rnNgok]mS>Fl3Nb##)6#&DVWKP=+U3CWfV ;?<?<+cZSpd-+3V6o"!j]p53_b3KQUP0G;72`'5_ipWF59>/k\S*EjnOe,Ep=WhR9ABBiWS-%?F.6NQq>n#6k<*H`8U^B88+:-<(^=T,5qAp.OW%i5ncXA'[#2@72_tArB3s?'6=^faQ[ak/XQ*bqmJQ`C6SLM'E8i^Cl`bp!c^f,_5=t)o;\G*0(U/"m:)1qC+JUdt02caN)oS(WtK$=pB/A%qC6:Y`Y4E[UK5KTG47mePiqFRacGX9,ps\M1sK%@r@S,9fV((ond[)ZL8@.PR_o+2U"J[IADF 3!5sF9>UJIpQn830RX2VfpQ@Nomt_h]R0#pa?lXDjhQ/ZqWjnC2T-5bNF 0E'L#-.t+bNE!:U_W/4Vr?Up<\Kj&/K.p@Zh%PAtdXJNA@F Yp4D55m\p]-[/G2PUo5>haQq/^^Yhl*Tn?Fad=jp,=Xrd_eN&0?8G`n%8X_Eq98n8O$hY=\M,[@n$b32JEBA(9=-AcX'H3BX3\Xs0U'9m\EVs[(4)&$9AkXc:(]HX.dL"Kq_mb^2O"nJ_A/EbFNXT9"pqsZ!FCDZ5sg%jm2fIf2A:_A23WTjS^?P5ei0iq)a/#:jV8C7-r;SP>M\c_coqI`W3ripm6No[M0W+jtcAZsPS+)BdFVh>#lZ7De 'ora7XVAS@cAC?CCs35JjCXb9'!AJ-D#2U;MO](q] ?jhTskl#V9O-gZL6!ad&b95Qs-UG5hNWd%a%C5B;Sq;;"A'P^0mJ]F`SfkP2aQ_-@BpC@TBV#DdfO7asSY'!De! ]IT$lSo-c;qS"Vle^I:k(Oc+Y4DD jQrFXATEUlm-3&3Za]Fg<05T&^!YLcL%<))1A&>1N.YT/D+):#!go-,+31P"MC;k0Y'p.<;CoJGo+a@4("!pX=?Y"$0E1Y"%UAZo2_]&KiNjH@*PKmTY@7I$_a)$1cP;OVU>I/$tG3RJ02Hq`X^c\_EMCX8Z4#q,'HF/B&KiY"IQ&p+$@:i )1)3/D"*m=2MHX\CX;mQ+]((C]`%$A*c.L+37:A!@A\66Fih9VRW5dQD?1'"t;fq3.lrYB@R>7Mc>mpp>g_DZ$Y P@VE)Kr.WAjScRpf:d+af_S39#79BfE00ct?DraP:=\l3hNQ9H9>3_Aq!lD^-ta3GZ\W;Aa7l&s`q1?"F\JOpAR&XW!QR\(AB[ X(t34Rf;1X6_%d4-20)=!4!TO8I.&#nl/#.P\CAYeHJr'c$b5EJio^a:e%m4tqZ$3H?%5r)E$$5q98rtU2-QbqXsLmFA`q7AjqOIK&X19N#beR,]q1>^?(Y*8rMhthFT1qsjsTCGFJ6BPpJCVZlWC>hpKt ljt#+1DDZGV@eci,19LnK]j1sA!g>f9G>&rDQVA7m#Y8a6;1q8f:3Gk(VAc8gKXh"f.YXb0(H4mc%#?sCOh#jX!/Qa^c]5@*NsC0.;WIMJ2l W/h2FWr'Vq),Jqd:Zi$:!eDaC'k;qG$1>?Fiq_hSJd."BEJFU!QIQ4TMd%A"5rD-*WAmR_BF;866s-s&Ns'D)fQKWrp%9Vq27(fZrjKA;3"NWDl_]WD+_Ji?lY"D%LRZD*7m+:(0UqS`3WA:;AG=rKUii]qJH[$+Cm2c;?te5#YeIjm@V@(E$U0XQ^-Tq/*V*@hniBiK$M&"3T1]hV3""q@-^7d+D! Ai5D;=k_t]Coa&&4UesRq(3!S5XQB"j`0B`VIhBt&O9q+YUUn1f'1GdoKk"H$&[A:bst\+V%FX1,,]m>k%b!ZY!]mk6Aq0aKQfmbA?`-"@&_si2ig^KnJA2i4)5RR.m[1C?IlAj6X cQl5)OGp`SE>4&=%)ofQ;O9.0r=.pcm)HY*AMC86%"g`2_Ac2n\?AbA^p]!,HKj>g5scI[8cL<f/$?!+5iQVL'_^D6WMXg6fE\ImXTjY2pN.aH-Q0A=/SNO'$F6%#B/;AgcWY%cP?14a`l=2BoFZk<`2R# 9snT;^9-*N3BG"rq q#R;K<`"eb+`<"ie:@sA:89MVQ8N4>2 9\UKt':KMRV7!>j*Hs++aWcJOOSg5'QcFV%E7"_I`k^G:Rj"rH.42PQ1fF00L`f#pJsroLXFr._M2]-J] ]gPaAi#BA7M8iB1e5P-FSl4j!GTk'*U3PnPZ)lQrQ\Z:EUS:9i3G87PB. GMM?=jr]=D4BWeWWtd.Zp$1AbeSIAr-+-GJDZr)g: k4EOKl8g?EMYqAmK0U&N7ogmHC!A,]kGG<>!qThP`+3n7Htdn9$#*WKPDe"Z@7?MH$6AiiS[RMsq+$2f-3:U7N"X"(1I?\="i]1(-JmY%Z/4%)^AMdk/n%=`%Nom@Nd13#(YD`(k0FJrFiI:a.F4#N]U2WcD@rkT!G:^k3t4DC'Rm8C]L`ND$q]WYe[5$m[4H(%CBe7.;,t+ArTW!=lTKmjn!i=_4#BdX(ds1#1Gok3GC;DcO5WF:7@BT7[Cqgo> B04p'1LQYEYR50PSsAE@1hi(*fjocJ@L),e>[3AC:_ )0G))l6p?05M\n178XlA#h^lpG)>\]DS^_D&mULnqgJJ:2^$AVa_lIFh^dkAPo[gt?C'B+H>,1`_gboi-M* 5 30GeG$5B*s:l:O(ZBeUt!.o#'^86\%Vjdb!0tQj5Y,IJ"(qUD(Apj-s3[2I]fM41Wj/#c@?HrT+J=/WlpU\>GUj]so=jIqEV5BA13AD"d#8hl[#^2siAb'[&!F_(fRH&%h@NAm3,>XE4&O4>f6IP\6%nTrb De@EYF,/Wbs3%@p@E$YHQE&Y`Y_D)g2@'/$4]p/Q#N)$XnatM:<:HrPg6&F7doN,Nen+bHtE4lJN&QT9fl^P>W3j&Y&Q!kra_M9[192YW>R`!U^!AS^62KE;=[AVrPK:i^_9] A)mU%SMngF]GZ D-Y+5S@HbHp'X^@*/V@QcU*>iA1dgK e<""`R^YY^):rZ!#9#=ApYQo.EkJ4.*EXcjqmS*:kQD6gYdi$.HBnsCni^5rq+SY\0hC=:t:UH,Ns9+V&k,Wt$DpSF!3HfAM^fI+-A*"9!=G^+hL9R@4XRG3S21VGfZ5a c!(:r+c7iel3(ZAIbQR>L1BsVnn3L :/Blg))[-&h`&IR6YGFCXBKV&G0)@AGTW7QY'$XC0/U<(W&*1R'&Ynk*A8Gnl]3j20ReM1';6T_BK*9h@bB k83;"nq%n]FqqBQp'?QD4>6oSb[4dm.:+@YRTFMABYW3eI.@<D@,'o##hVAP?B*kMl@cY+AshCHMM4UClWn#O4tpgtU1a*"5 cJ_Zt8E9640;C9AkBabe.0nZ%VYBYF8;kl`9^^`aF7Hg''q#]bcXKV#_@pj:)Pla@+ +!6A*no]^?$V8($RlJc]jXWj6]=9M61r*f;btbBT*(N5Fl<[ON+'4#X'hsGeGWpML5&6XAIGWjsRs]B]8'IU#-m$7i-RQ2HA)MqNU?/b_KnsYSD7=8>[d.)*SQs^K/"+n1Qe2B`R/+oK/3Yb@C.1O,>kG9d%=D8A2'aG6Ln-P7nrtoBE_;t$aA#OSj/#dJc=[X9D#^-#i1:\rjR3A*5aZC"2"bQ$otgkEkES\MoU%*H'/i;T:`f(n8:\;"NGRgBQA<.Z@,7a3R=;gZA9MAV6!KOH:=tKWJn)fdoSC=ttJ*N,B5E'_L1?Wdl-M]bGpf@J6'[gRU,Y#edf=T[($O:22\4Mo(Zn1E85:6lg4+"%K3`PtR9*R$tlCJ7FJ,bcbd^T_N/nA!7*QO\0t7JPSrlf:-Tn=q`S7WXG1;7d!N7a5<_6Ul`M_eTE0eZbfb0%E2])7@P3hIDkf\S>#i$Z*[p5>s@ZV9\q=n_O/Y)G;*^S>?/NXM"t$M@t'am*M92] \VEX]^G_XTfDKL4\tA\Ls)J;%:1E%A@8d>&[Am,:Ke\'8kZ$=(+K[s)R]rj2X'!ID"#VO.>Zh?L"0o-=pY^!=BRMA5g#ZK8-/:ab3:mo/F6tL-jb-N)At;%VA["R. _o/Wb#;5C_(NbF1F"G4N(oh`^$18bA8aL`8[>38W#c6t/dcEkQUoZ0+S;LS;G]a\>"QKCsKT4pG6dTVg@kPTZ6F$&*/p[c+n,XeFd6YiaE 'a'n;C@t".Bt*Z?Tb8A`2sErW0CXD:rQ&B?]Ys)+`St-2ikC#DD5$!LORR*jHj^^eWiQV9GF*EYnr.:RT<+^oe^,DR XQbpF\JalQlP2%"%Q9U(?XX&ER:`cSLl9-%78O7Ol3BJ")P![X?J?))$2T+395?;[A5/<4kqm<(tKhPGf*D.O2$-J4t2p%5OFiQ8Y^1#b,5gNYWsb"e/t[`JqnF(*D+5aD2!_"bGEcQe1V+>BARj*J:t*MR3.\WiSNg8BP53,knAVNm3:pD)pAh.JmTnC$A1pZ_$9VOs^[n26PgFb5g2 WWr1^#5TJ)F,2=R%KSp2J!)?Q_b$s9/?lNTAr4kb:/Zq'/%o%K>Kt1$=L5Nroj9_[3;.;+ld=j/a0kq.LE!Nfn?[EN!1@:GsOElhN0=qVR=ik0I<"r/m^ZVk]3.Ee_3;aACWCV<;0thiq]hCj\^3/eC*8Y^$RKh7^lBMQR40A/7P8Ap>4P).gUKPe2XD,f7pAV:aL^d,Un`am8iJ"+o;p7<(VIN"&q#g's^eQ1lj<G?q597IW]g4! F=<7I5A[,H@5GlLT"4dslHt[^Bl=0fT\3sY Bs",^K.Tdcj1H#Mfb\@cb33pkjI<'\dAk(se592g-ja-6Qj^(PgBUL"iSGhm/-rs1eaG2meF%8i7K0besQKi_?L@54>k&LhTHR!F<92ZQDZg0"GKS&9^eE]$7-fad7aLC=2]h.4IT'`XR(_s&#NEptr_h5^>5[2Ff@O[gNZ?\Pe5k/AO?MlfOmHL&jk`ei$r9hArAXg."tEV1+1F^e6WeTS`MjTM4;/SpUt,0&O+V'41Mr%%ZI^t#gk]<]Q[Epr$VD^00[rP5lA'OdjbU;R1FO&*#)e _"N/8KCEOi)QAWFl;47_k<[$PA0RR c)HAB52JL<.+TLp,!2sJ;,UGVk&L#ii!4V\mibWR3Kr6hp5;e0>]d.XHrKMg2*#IWT@6#f$JR>W6U#BnqeJC.iTePg9A?TE>cfs1Ip_N#L$s`X9aJN\Y^,2CTllW%8#r@MdsB^@7&MEfCMpFW0Ze#2!:S0Xm< +S]6lCPk9L%AFM$<.l:V5hF+eXAt]i>%)C8:VA&QY]q]Wg[;@G21#mO*5"3ACRjDO24Iq6pf8e,L_JWU )8_'+&O[Li'IJ#<&(IUnHnhP=7q)kf`2lX4m;fFq0!>)p9k+]a2 c*:'^,>BWlUD^W-63A_O&[X]Zkp\da)r !WRk#[j2H)N^4Ss>k3lVpgiLM&iSe\L4Tt"oO>s=Np)UqfAY/>LPQ[r0L=?5lMWFS03H,XM2J, VN,%O5&2@msR\m<(%sDJDPAT,`BL%sk@a9.sq7*]A;n5iHY^?&ail;J?0**s.^'C].*sAKEn4[D\Qg.gSg>jXFfX!%6AhFBt@mM<^8jOr#Ni6#U:icok"'d!r>k(=E*5sQkX?^<^-4R)X:!a%RCGU83k"P*:eNCCBfLjtA],k&+;oKc D+`slC\c.m8?LVsKJ*2Jc@%FC9Ql1*o%>!2hFqnKD0cUh/Ap(_4a!AYA(gf6?;L0"H0R#AM(Lr6%q@A#qfDo8CaZppKbk:H,UJepP'L" V2pLY@eNG`;m!OQIE!^?RABSLA_pb.FbkNoA%m_'F+;^&AfA@m]<*J?*!$NPKr-=Ze%kRU\gkn^gDsB0_?mk`QFsHcpJt3n;A`.0.5)5Y8NttXQ;]LW G7 b_3,XhdYA0Ak1Go[1j0K!-rC7X+1o;;U<UF+c]GFkWifp/XqsRTQI5PeL_1`b2]?(gs4b2PIBj8H$Yf?mq1fBcB3W8^#d90a2jCkkW&].9Dpt*)&3`=L_`i0UsGc8JEBe[HKqWJ?da9A)*hm%Mg!ajr[tm_V\/PK"A)4?>*9iOWE,C*tkLVZ^U-olaeOWM?hkQ2mFLlOfV5Zqt16o&,C;<p\4sI.a3-1n%"O%;]?@&&Kkb'do] r,Who/hQU<`Jt ^N0?d)pHl2h+,,m3o7\4k/3]4f78Y(=N"JRm0V1U``6Y&rBfgfp?'FG!bIFZ"_GefA#O.b>(LlZbfmbX N0q/c[@WlhTsEsWG&2CO=@@EFWdL0sAsk99o## L;[f4-*IE>7;%X+:A@F(=-U6o>nQ<#./LV7FPb1q!6aROsa[[\@I_F:/<2(7^TAL&8@Zo0ZcR.YO<+'cniABAE'>O:"iq<j/-P-VV8+7JALk;f>^=5NB-'3375YdeL hRCPe7UQXLT*bcA[13a"@.TWjViKS^rVT.L.`-o iS$!Mq?+K,Q1Y %%94)m#8g*i QMdVkn5X*1=`$&8jNs?/isc=b,*SAmYT/^MWA]"@SM(*Je7G;7QtkMfCo416#Pl:.*NkfSc]T5J;)!ff0m&q]`7,nC`bMbpUn\)o7=LTfP-c%mTPhm:?*![U*"5((V?8,FC"$3JL]7n`.>D$AjCl?Y/E%%C,+s7\Ee&Ch]^ m-tmoYADoQX6Vj>df&lXVCc?cSBbdCXEVaI-2;72PVG b$RB*iBT]\O!)tOH&fTbp&LMY bAB$3,m$SO;@Y>&>"SqE=%gLQKq@9A<%'_f6r-9V]`eC,9`!"6cEn:@e*W%tI Oh?Y[j9Hj#"t@.#K5tC<rGR=lk;8)rk]BpIS(8MCRU1c<=oq%&ra-'kPVc(PdFK5,ES"@(_I*)8\"M7q^EeWflUAVCDN\M'MJsTZi+kXPX)43T$.aW)-s<:#o8*Hq0MD1=8B23Sj:>J]qVVVN #A0/A#CMrgb2'slW>-"Wr4Dog[$-j]eo"P=Q-cEVCE.4_/'QR8rT+8=8T2h,A@'N/\NL8[.2K0T\;OS A?(AS&o2:S_TK+b`G:bm:e$N)[G=# ,@;\KF:R$&`D];41=E9aA)c b[Ks+K9l,3r>lZ%LBs`(AciUpF;A*$"^Nt-i,F6d22+Qmrk9@s 37'LPk3-dHad;Efkq$nJnleeLA$YIASX_A2)bq15M'1l@W@=7Y&`bqfWO,.6p/pj2^8/=C._bId'"Td*Slpmo9JY\@Fj7L"(YN!jAON2CAtF`:rDtL9b3JQ7\ZmWZ1LnD9bi,liT0(e HY);_0Re%r1=X(>fl\9`[Pb_.O)3TeSDF`+h@nQfA#3SZa@__C#65Gc]$6J2R(sBFAj)A+VL/"LGY5Par[F^bo!m=sbTY-&aa^;LeRCD=*JNrF0H[p0U1*U@TL=2]O.?iK6,$T<`@/;Gme^Wd$\nN_/b8Ra]pZFeq#g,t?D-V]M5$II3(^b.17rU:(%_I!:.j3M1oooLBP2SW#(V 3I$9CVNU4mdl1JpP&oq>,`mJJiIf5e@\H8i@IcP@8hk3]O,\;43*k4?'q=12)$A6>0DB:7B_el#XZ!U.5C ;/?r:qM]QbO3I&gA%#.RncpfG@UGTU#M) /SH+"r;Z(mJ+M?i]*CcU#dkn"J<4510Z.$YcW=Gs#0N:7"?0X9(C$7,ZITf$-1<(YV)i/8it@m;42Hs1b1JZnMC[t!4YHU] @*!q^3l;bhQ<F&4^(,TTgn]IP:Oo9.=?>sQGolboCh0L3oO\a%,eHENt Qc&R24M$j0Q;C?b^=I5=A.ZA>_j^GY]Ds/D"E(jRf@p%dkE13&O8AY;^Or,!?IYUH%F5k_oCpY#A"FUWrD*R9Gb8iJOi'HAKZ/2:RYhToX!qIIp+`N\Y2K@ e,_3i;9f.LMmEO.Pg\6b$tjF5[sQkd,3XHK&HqVJJZ'tUcnK\gikacet-hQlH&pPAD5TM[ehBh;)LL1[#-O.e@-*DWq?7aeI2;LG%UF;_QL*osn[`TKs^EqZ8oaE'#:p23P7h>HBHd`#R;9&tS(& qKeFHh<$4'tG!TdG[L*-';>+RKU J$aNR2O=E3I'B__9B_\BFolMh"6O\4rPq$f[mXa5'3Tj4I!5t!D1L4dF'rbiUdtFj!(*fhh`L27$# PA-YsF*:&o+7%AoK!"T^<,Jrp"WIr8BAB\mEBeg,&GUT"$k!0(Etj:T=J8W%G"1YGqYD9]P&nkg2-887t@d^XhEJGPa3RAeiAi9,Pqobp+Xi<0)h)BgrOI&YW=R(J^;;_HiX_f]aY_=8@ZQ4-&AKh*RjZB`rL"'rMnZf';Lr+M/E='=$VCmB)O@o6T/I\!Ut]RVCEM>o99`ZHXp]81FIsqa_9ab:+Z5-MK2ob:"c16C [p.IfG",\GPUBAA1JROjW.c,UpK,Dn`'@co6AQfr*G?TN6kgCX^dI]>Tb/H!IUWA`nU@Neb05D0$HQS_I`'Y4!dTl-&:p,+CX^MMj\W@1TC05 icp/=Ce*YVqS+ZHb)Xr*U[2(oN.=CVI[H"!;diAT_Fi!M)L&G1p_lR0NFYj.aB@@_X`sB YX*J9.9'r-`6C%ijb `F]Z6nAL1X/nUas1A%b<C]75JGGe,q",DDncIIX/AM2=,rC6YCZ>M@Ah3Bj]d@ ;"8DcC%orqsAT7)h9\QA=i4A+Ka)6sG,SY6X6qh)h$&*kLL^#&;ei!;()!dVO;>19A\iZajHd;Ihk)I?$orOYU:scq3Tr@<+&$E53g#k@;5WISMGOicsOOq_6n1D_Op4F:7l#&EhbpQO(r6r8aJlJL' d**Nrr/\bfhpI`Q_>q/-3M)!8b<seDU $<4 []6";L]3Og $D5SeY[d/Fam*c1e9g]qA:Yd<>+ZZSF[Y?: d6ri::(sr%,.L,8L;9O'A5cq`KI!$9b0O7A"\:Nc@3LYA"eK3UgBJ/$\j%OI_/D9<;2m.DUr`q4#eleY"&UL!AI:=8'g__)"r#:VN3D1#Y82mEA+Ubb-\g,AaIN&>?POXk#(94`fIfA%eQG!(A(;Z2`mFGs]c\qmY:nXY6#k5"<7bO]>5A?(m?^3PQ^C<>Yd;WUFRs8@D\C9l+ GS9RC/+R2VWe!Q3*X5=_sj!3PDC=A-?"SM_`CG#^.j-E'R:7:MVMW(TL>lO?l=M*4rgI>:052*0b%m[dOD"f AI.3n.MjLTn8K:aDTH@mTqP'qQ.HaB=?6L?b!ma5:"A=3tY5C)VRF'GIdIEa3JCfKWnQQB&^e7BUcZ>Q7?WIP.2dP)Q#T^gd0&AS-0L<&@4\LB6pcW "VsjB@0LPLMr 7qm]ga1--#P3;Wf4FVM;l]I)[Vk_^:IiW+KG>(,SZr8_%Apa0>SUBhAW>VY^3\JA\$$3;RfIph*9P\MbY9llP22N1%o^Y3oU2D#k)*W DCN&1$Y"@TSp+`4c7 ]t0mh(IG"/AXZ,D?i?_-%l.I#g(^#Z3%g'RmB4Us-T`G]:Xo'rE5ZDGl5@,]3crC8_:^HQF6h>'d&!%3['k9O&gFO)r7SEe=_]=6Oe;DaK:XZ%VNm$o%'>;M>q5qH8@DFFXFU^t@O8DQP-J*'"Fj+N4Ur5[?7h6).#+C[:J6I39>Di2CF+] Po"7*"Ih";gA/nhPJ>EP_9"?e*m3*UUAT##9i7eS%T[/m$%Ab, S^!^X+DI!tf?cN9@!t*L[2NWOZPRfc=Ao E$AH=\("8?oe15>dT!B]T<ro+:pAF1`'aH;XMr*$U;)p%9P 'Hkj?04I]Sl;j&$(,S3IC8,\($%XND-+i IPY]DU7s`@PBo?d-bfZ")mOi#$b2J.A3A]Pk<c;`eYeeN7\kR4>RtQRo Fb6G4YJcKB2-i^Nn^t7)dTOdC:/WlkR1IoW)GF^*:=YFA>tV94KRfkYnFApkbb^qLqkc`7 K5m4"$[\RIIYJ-Ys&Qd;P&RmL;fs#2=V1LQtJ[K10n+DYg&ig eYsEbt4EjPP@FsaUjs+^[<i4)Kh$2fe(`b%GqZr_+lgQ>idEMS+7'V)&=nn_m1%=G6ZLP8XTP'rNo>%[Qb4/4seF[&XSB\EVi%!S^SrtiD:ARnB?3As,%L@_OFhm"@:'/=N*A*OMESS2@M1VpaXTd_ISUSkUO@ERQE`SaJm%V0BX$#WAd9Q>_#-]SV'[:N_,_W4/BeP(<,PA+A#lQc+RF![]Xs#_A1Y3Dl_A3,kXp@OXT(i'M>m: +#b9+IMkJ?!94+p`q0Gbrae#sVoTXtlbmSFt(^3P,?jpp#&H/f#9T8m]UJKYT"N?,36RDGgl(5i#j]% # XE>6l$5^?0&kKs&9h#P-G?$q1NMUXc"Y[Re1,K%2RI3D q8?7J6lbG(>jT??)E/F8%MmcChF3Ie1M*d21#"p0Kn0:Hp?8/XRF! $T%-<0f8c&+DV[ZCV#+;a\c'<+^"e`A8+9!<03(F">XTr0,hl-+pZlKA(9a\pCQt:QtMjYYman]4nI]-kD@`kOVZX3o_`Jp#@\q+hJ58LT_8El&d8%.%=o(,!f&"Kca$Q),D<F>BJ)_FNob(/BD5Jp36H;.R-.(fE(^HXHeUbJkN>X(Rb-<o!=P5l,68d'GSP.OGs3O$VL5?a)]XS.5"j!CX'=A2*O.K(3Oe^AU3Q?9Ft0Llm1Q;%"4HM; i,@h':b0Xo/icY,ZV1"W B .c2gXih(2%D(Lapp>V!k1Lth&XdW-Afg$@0'@[bcA52+=at?gA;4W#354d(Un]l`=+^_'P+$pA/4&STiO&>t5#`HJs4V%DTF@j/.6Z&U>'*[da%>TkjrnN3\L.PS>_g#)Gk&fXrqGUJBo+7"oS?U5UeE<n6NGTUJJ3`1O:JKBdYL+oC _`^>'@A;Jo`;r9Tc#)Lep\scM8$--A2C(K?SZlXU0E1M00AJY+?XnhSE7WU?L l!S98_XBA3$ddc"!rtUcTDOe9i;hk1R+`k(?a@K1lmZk5:eSAo*Q&n>Xq`<`I/sg*Lg"=Q_VO0=pgqX1+C^rO-.V& :>rMD^#Mc@-!f--t:KR+ 3mC%[4&nS5!sC`E_W,]A?,5CDSA]i)k0pj`_ne@Fi9GJt6q-d]jJ-jh4PhR(KbmDgL9p:KakJZ8C"?iso4%Ar\5[!Um,i)lgXB6Xl-*U8V.Nm<%7Esb_`?*7tTMqhjqTGh0.3[%6+@dC8W+h(WlR2;27:a6_O$5k3gQ_o(bh*IE0H#E).4b>9bm<%NEI?N#&GDtP6&N>cV3.C"_:O.=!23?!?3LHd5m> NRA)lO3c/d+\1A[QB`C\2U+57OpQEqSc&]@0AX!d,\l: H sm<"j5'(d"[gHX0Y"O#`$hU0mOkh01NWt90&rAen9)NA.io5lq#do>peBfp<>A1BeiI])fe!\R)]1\"OC?0Fc0k 409tn!#qQe&N@*E[FLpPR3HoY,PS,%8A9_iD@Znc! Kp*gIhA*nI"`>;Tsr;g[R`1cmt6"Fj/Pd#gLr!=8XR\:Amg \")eFXG <]JL +Jg@`MOD7a9Xe)C0oZPBE4ikP.QT;AD=3#d^t3sn1il3qM)!2>\c$\12;!jkUftXecD"IYgtr#2tR*Apj$rRT:*-nUY5]T6o*fFNMq#I :.G\ah3sq#`7mT[;2tW;U(Ps(ohs8?SStj13fULZHM2&-[9#/q V\fifI8dq+Bj:NCjEpYa\g<1ef3>cBJ\%8aklFb4V<-A3CW/+L#C(9r+XoaMar ,C:t>6r[KYT3XC#5Sr1oVW=q'/@58a@qD!/X)AA_LrB?Z^V?j=WD)1%eD7=o9)Wti:`O3"]r+>KjIK/K+3+ki11&ciJ4+p>`lA#]p[int1`QTg1/K"d:CmhYG,h&@F3#>h2dZ$kYPIT#Bmq6m4f,seO5R)Xf1Fiq$Dk[kHP74lN>^mapAnWrCiSb4HsUYAYr++\**e-%UVjtfP1S7$K)Y6 0 &;OPXKY]L6Npc>SRHd`?n#A4O3[:tCR4*!;&DQ5c0`lL!])^HsDUJ #&ZO1bXbe1$:q;/Cf:bH57oUE]H%iJ6H8^em60DEeAX6WjXhV0_MiJ]tdAaH<oh,]j+P"R^e0]sJ$AWa?XnK]hGCsYgk,ht]_7])nX2*,+?3eSeA0L^.OUq6&F^[IdF%I#ofm;/J^W#N6N,7(>o-k8\6FSN(a K(6?T($;dRT0Po5\MJOXqg^pVOI[.W<8\3Nb(s9g_-P](("A_3$Ra;b_tSYLb W3RKP!_JV9],P.q!O9>?Z0d^53"Fi+J=bf/0RFnPa]'f"iY-g\QK+ir!K?H&MK6K'Tm:[>+j7P?/>mZ[s9(/$=sU,q787+2bY U#h8<,qnUc6tt3nJ[d372 (WA&*936B1%+9m_]j8m2-Z4OOHppbR-GXQq!s?HhI:JB/4,AO1+b+CtmAAS.In[)=AkLOMbmcD ZP%sqqHrj]F*BeAaso=.5F#BQm7[`h'3l\3Y6&!S2j+pX"]Ma8M; X``jhK(5<%Xm_(DbU^I@1m6qGk0`2hXH5T4Yaa/#m`+cI4UiGc#^Sdf .">A+&!A:gW_MVb-TC/S"c^r;9bbHc6TEtWemNqNn8bbDs9=pGi7A(SoT2d&=Fmo6W!o'haZL>GG`9+DebsocV9q_T_g03?Kl-&'WqE%>sn`4>cA?_@-`p64Z.rVFfH>t:)d#Pe7B>oK&Z1]D^A"A%2`kh#>_[&o/HXjhH2LOC$fW$I1(.?r@VIH2sgDa4o4XM(1VTm4^!Ra6`AD6T;U9d@$;tNR:]4k^ 5l359gf'b"AA&9)^.r!>hA?)]]bW5F>U&Si$ss'7_3,6[`]Acck9AC8Ca\OL3bb@fdQ=VS(G=ieci2BBb_jFq)9L8>o0J)DAL4<]VG'E\a!lI1aEaG-$(3`N 2VrDrQm+!>t_O-X`Ze2 $mI9WQ2T+U;\1P;aAgAHl^Jn.;-@TX2C.T2J\R9A*--2kjc_X&sk8r;^'$AoDON5=bbk6?1,0rpa#+R&?pGAl8f@_])G@lF#N=_ 7cLY[8JYO'k%d[XS$ LdF@lE4Sk%A_AZbP^7lZb62k3p0?XR$q74j`Pgc\Bkdt!3CODA5Et&8@!:A&Z7B4d3q2'ZH.EhAGt;rWYYo_e">WQ#417ATk%'Ro,pS5;`5'&E'\XK>2o&B??IHl,4Uf>95a)qR5F9;Z _AS e-cWA!;?Qc,UiT?iHdY)5rQgD*:"-:* /l./Q%&^b)_`h@37IGR*P)V0Wj0.RIS+t _UMJW)d^S[snLfAocTL(GIB6ts4tr3%Sr6^S&P8:npYaAlVC>n*D``6F)`7-pdG+L:e_e7MnrfSJntJ GQISBRm996%%X?c<l?G1T'A@'Ih!1hp9U*[Rm,Y<@l.:'.i#`S0,nW6hKGn'\):IB#Na@$,5JA,VP5DnErnN_\>tKSm0);?L&`D0E`[;\Rc-9c\ihT/;*9\j'(V"-T@#>lgS$0]^Aj04nKC$<9/D(2K\od'XbO(J5F9PR6=BGFp#3l[p"n30&NEQUe(OkEiJ8%)BAPiK]L"6eM7Q)VO)FE\bYk;*,R %,K$,^#O2eX7#dEKk>]5(Z_p\B_Al`f1HMokqnGU)L8&AWEbl"?495+.`>IO;o0$d32g=b%W=n[>9Bn$iaB=Lr[gP3ZU6;htm_J^EpNtWp;;9cXO56Rro-'13)&C?tq_CX[g'QtQ8fHeQiarjm3ha^q>L@Fd`A'Vc$i!FiSXKDh=*Z4(d6,`.+K>Kq`Np%`.4TZ*d-BAI#/q[Ns+(g(]0s:X,A08)o7ALtHHCOOL&@NqhmikX 8,>=;]!MCea7RC'0sHWnW'L,7E7'+o$A%t2Ff$$a(pZoc5_76#cs76&,b$n,XO;@M"5VRUld*"q7D+s6.kBY]VbTIQAB3PePkO9gIKTSVnZB&0m,AA^?_QRkk*\;:;UiS'6`N:;2.H85:h2ptSR`V24@ H g&F)&@T]A!Z3EdA\L$rnd &D9TN"hCrMls<r^MSD"7SKAN0D#NPe1n<<;e/%fhZHOrV"gLe$1j8Cckl=Ei0\#tpYJ?*pIXc7W,j7r-25<+K`7qh$,Q?DGdpNA7A+PhUiJ'Y9Lnad?8r^;^;t6Did,l4\5%jH[;fPN(0.ReEQfRcidVVY^lX]F:71LYqL;A`m$M*t5(]c5d'A8%"7%!r'mtFDUj.+g&S].*+?7^DXAL[s+/;f-'#&sk&Z*"b\pcchVBdi*7k-Xf\+"-#A-AlbL,NfbcUf6">]^*PmcEOGU4SKjp,1&(]?/.rqk%Jr:UQl3H!X iHpMOr4)0ZB"-0jMqA!>21F/h@%_X$&)Ze_R?_AE$YP6o`,\6&L@tnB#Ja$n,YOF1;e2AZ6;>r9+&IWK5N<3Y'5 GrJcp)ZK>r`TXr%8QWs_m80GnWE[L%geqW7P_6XIq!-'(imGMnKg,ZOUf='#d0[b#&LF%'kK@`;/edX)=pGqsjOnGG:467Vl&r4] SJ%sI%/VQX#K363QfJ,*YGK(1hHf@G4'lTTTL9>>[T%'I3>rAG-:r=GnFE41HgIo=&PT[^BWH]M-!;W=)Ad!.MUs@p#[:>lmd9&^8 ,T_iP9"Tj1ItmHC;-Ib'[r,l?RRV2$V-j[#;h:HK*P8?l+h,$#=t$D,%-Xo)t2#)RZr:>T[i(jlBc)E+>iPIP+6h<Xe\\5FDAX`8@]aGHjX[Uq2k`tb<DZQl3Za%Q39bpPI'RT?O[M(/UAdRsOEqF6A=6#&_G?aeNHYItHQ"Sat2R+jpA`,RB#H9'WVA(45m#,FAR9&*7TK-I$+UgGmA+R9 PC%^hcZpYmO4f%aQe^"a)DC 3@cb"p,>k74KWWML4*3Lq/#6[bn&_GsnLPMI-+cl>[mNdb"nl-$W']\'KaLPNA ml]t^WNOt\W3aS\7]"D5./8lS'5g+Q+hlZ&mm;OK;f"@%s]qkT1n$T6AHtX0FM^en7eIdsKZ<60;(:X88gEg1W@9f&[Y#j!;R_\7K">Y"35C0IXdi0O/$/jm(!l+nmON8=2T8fe&Tpf@YYJi;BrB9Oq&5gDl'j@9F4>/"5J0/Wg;ApWb::fBpp[B'MCUCsKnn#7Uhtp7BqAtS!9f(@Tc\>pYD& Cl&ZY*:5mWKZ3jDVXPZ2( U5KbP]\)#qAK-^NjVd.b#'qk>#F.Gt?ZK@rVt9FgG3mQ;iHIe&m57(h5G9i/8n`:G&HpfXLD:\g:RXg`P)X\k\V-`Bp8Q/[UP0OBCCMHY$i"X61b>q.Y^-7K8ENOXTF%A92nmd>72e FEo(JD?ZNYM80>_iD+1.R^H;pK=AAqLFXnDD>'@oV5,tZ6rpcpAh_F-$A(ljbg-bS>N#i5 j%dT6I_[?_$`a-*)tAjP Pf$e]ak1";1#G/\k)%+c[/3P7\[qQ:\cAE+4M>^;lACMfV$_d hcesHeX`,E7a$_?sIZho7V&49_)a<JT* s9EW8"P_\!"QD)_0\bjUYH!80P)l6:'isq!t4c(Fi6Q>>X9]mhD""gYjf[9K1caC:Va$SPl_KLHR1jo?Snk[R-l$`'aWrA@_Iio^_b!2ZsP^Vg_6Pr`8@>BdRtLp2_G\#iSoJiI^jAj3bm[=T"@Si FfG?o&r(?"gb>% =(jheYkR(BWC_H^Ki=1q-aZ=g*h:Ls! =EMTN[-n2 [MC9*d$s2tn'@0fr%KBG"6k784fZ Dg%OTX0PpR7Kb O5..q`kZ]CmirOg6$*Es#<5VXV,Sd1X*$*oo.&ak3N+g80Uje[H0$l+\1I]*lRi)6=h?T9FOHk+>)JT#a))fl Gd#/"!24O6G:6@PDQm/?4k_n7%[!Ei2Ap@VXmP_Agm9?=F:7WeW $NF\3C0%aI>G.ZNDQLQASrn(hjfH,.Z(kp@:&jI^.?T2rLol<;8o[P5tS#U9%6Z0UJ!dqs?(d7Lnm<'K%_)m6n^,IY;-j'OTCZS`A*j_^b-G'56kcZ'IGa^kNJF6#.=X4Y/VFIG[19(A`"`KjoTcQHfL9Q^0jkRNZK5I>'&YR#g"6.(A3nU?OIcnd+QL[&jN!<!g'`LOUoTWPO3/W^R^`#a]'En5)=N,?D;TmBitXdG0OG!JD=5;HkkOY>AVN];igf.:E*>tRBO:S[*mYjhPCJC)8Qg2$s+0AKeBd4(s1eZ3WD#_bVo'6m.)\&c-?V+f9=&A_j4L?9ZQ:-c'pW74U%r.m#DEH8f6F7H1BLDqa+eIq_cj&T]dr DLjep+oNt93$T10 GXAaL(Dsb(hT&(:FTX,OtVO\9I4#2%boc,0Gh5p(f]'bU$L1[0ZBkF#?ogBjUm2oQH]pTinSN":cD_FaEkA7_M3\*:Q)^WUREFZde1APMp`McO8pe^:-^Y&H9QR,#+n_JO&0Np+9re11>)YM]fYAIkCACaA\3-7fKIFfY7Xp[s\oM)f&*+p)pFXkpjGUalhQsV6iCn2iOBU"?19Ns7.m-_kh<-qI8OlU3m<\r;tM=]]b,/.]'%Lm*Qg1%jGlE4AfWh5TR,:nCU3ob!)XMF@^2%sJdi,@/Am2Pqgsa,nZm;*'%^XK3e9R!96eVbt'2GkO+s,%\F1Vcg^W"s`NR8eM$?&'MA?]^Kj<@nS75,jA-V,`;=V:=p*@L>_Th2>&7TI=,.m;XE3142Z#0$m$8&(!7EC%J<>+$t#-;-"1EVJAW,`AkjOtXb:;IaS#q)lDk6J_DZaJ-P-7?]MO1XrqU4ad)G.lD%aH4m[:`_Tg`5^=Dj_nNSfQ446ffRCc=9#Y.j%AtJ4l:+H2oK`*5;d9mAIl_J5LX$S99sY#TA-=nB*G^m3/#T^"sLOb4Lg6(nGa_'L '7$i;bdDq'j@j5ME_s1BPYWDn!j2Z+MtB8*Q_V#ofZ7Z$?K\)g2Nrm@-6S@C=^tSl)`T$bm2"p3jj8a^UlME$JD1#.XNRk/$,A^g-\nj5@>&!-mhJ*XYNKHps?' jG[*S"lgP$H"CGQT m"hkHk@U)N?"dVp!I(]]0$0;kc:)Fr2DsMXGZLWUFT.s&U@fk4$L5F*j':N&X(DQc.P]p*0ai)'5=^6r4,)%Wi]`O9,L`mPj,pJH)_S*IoN%X\[X'A+RoetZ*q4b<^;2I85HAbh%l5kgAJ8)+,bA1nL!H:8&F';1!V(6D'O;KDE&PhM8oRQViRNV4%Vb@Ab]qpP:Q^i6iqW%/'m&kBK:dd=j58ITNR+CRgI(g1.69cq'B+'+0Y[5[ti=]$0Pe9=7H>s$oZ,6,^iNoNJtg8,SkCjpYOPlSoZ3oP^KF-s1ME@)n?U*KtaWCpCSAFK?C*CGmr4;hCMd3]bLI2%]m*4'aPg%K5He #TLa@#%"_!KItS"4:;9lZEoTOSI6['*(_I^@qFf0+Kc=f3E.`(0hiK&C!jq/-@HQrk&8T*Y4\S!%q"-1H(_:-\nR?O=jKMFfFin0LqO9#prAm#%HHt[4jXK.XFEH?G;""Q0O\5>;jWL;5@c6E;`61Ne?G'T+Xp"-n7pF=#N=@@ri<G^jf oU\UK05 3*>kG,/Ze-3hB==Zs@:OY\AVX=_Y.UotK-X8H;Hk'\U3+dg?Y.W$_Cb=KUbm=j(AYc\CZ%82=JWY53$D2p_qITtj/.1M+:SGC/b'RJF67h7X=gEREg2[Z[9LRM$fRZ2RL4"r!`AYn+jVpPT kPZBHSJUq?AL!fBo`\ ToH1XVtBL0(r50hV['=UCt7Fr%@&e2K^5md;r30nn^'BL?Ra^ZWf&Bo#Xa@_FFUics@m[;tt)P!43p`hR\@O:eYqdAjmY-K7';gQ6Fqp/rKqYn]BsMO.-UaA$)#=-b:di#ZnVaSG:)*]AF]]q3L/0nGU"]2E]MLh-gp4s'QhQ0;oq3WOtNCi:ZQBf,_,"3Q;T&] XFgE'rg*;?MD3`*=N-7$#%nj9sUC%XN%,h#CA71ZAk>q%mKB0mO2n.I]h-1I#+!Y)n,R:rdpBbZ[BHlAV!q2cs+@PSb""Yskj.A81 A.rqFgiB6gJpSc.V3N\Nb&jJYI<(+%QZa7dATpLH'H:F^3FS;YdGY25_U PeoQbr<>J<+Sh(`$P=kcM"0nV\O#%lEcGnrN_=X<pG_^5Rfk@p2UPaY%&Q4>n?XBT13k=qq).!E4BsZ2"pqrGU\;l1r:re`W>b'.nrZL2I_&S3A4OnVW6V\E%14qSG]FQHi?&2);SqGFPZ)q%bn!Os(*`5C^(*>0`8f5.D*9CFf8,C3mMpmdn=5E!X+9Kp8'HHc [%Llr?t-,*RX59hS4_I7gl;;k;%qG4bKscD+RO#go605<^JCZM5pBcdA,oJd'75+Olr=aUe`l>[rL!36J" Boio2$`)Kl-=Mgge*+@Cssq1n:7KE(pZ,2$dY.AK[ D9qAKrjo; ZeU:Xd+q/-KAI&1WaUhsJA4i)R17&_1LViJ!EDpiILQn^sp*1"$s(^+^&]57\5A9G,rI_$&qFSKBff/)WBe!+6ka[k*YaKYG<0RLEA,t:_"g.Y5A5LdTWl"/_UisPLQ:O'Y8-_`.4&gHYIj!1#PfbL7M]g:=hT@M>6%1-t,!2*nXtltI8#X#<)T.L857G*F7JjXq3:n$5q(Ad(8>7J#H=4si+]U5\AAE2PP/h*!cEG?JM0:8_5aC1o1.cI,h'd8B%6BH:E<2"]rrfbOEZ+=q4t$@iU2hF1[AmRg@>t=r);Z 3+Hbd4PcHV*i@Nk_EMD3?Ct0P?d<#A:5W_!F+MG"&kK]4j]-Xd Q31oql;?O7Qa9t@bNSe6A%)hRO12E@VNcsSf407#@?#92KeEU2=b oes)XZnaDg[eh)3PG(*G>DB/:^GsR^-)WK<&BA1K*2i8gd6L"nn2 ,8Z4O5[B22Q0p"r=T .]Mr6AeC[qY?5W)d,72#0:\d]T4LM-2d1)>79[4qAVkE/Z^aSB%hq7@UL)iN!Q1=(-U+2WIBqO_RU\L$rBJ(q9oH53n9kBB5lr[D1*/fie8Q?LB\M^0dIih3Z*^J?)Z11k@,sa:p59]G""sB#2Q;LX@?Y%NBt?t8?p5FZWl_S(g[!U`oD,=A^_]3?8n'FeY(>,kqnsFAN)9nE>;YpIm+#\0lD/:mU0jDZ0+Q8BD+G'oAMtV%EC>FNl6Tn,714bS2_f`X!lJK0JikF#nqYP8DSi&d0+,%+CVq+V4pOd>Se5meYchh2-f4Uksj'3R[m43qh!'/.Z^3j]B$#CJZqjWb+XLUM&-a`^0)b>g2lFt3Ml%Z$g"D(i#H]4FbD E9G+BtjS?8[1ojO:";nU1s';M]F[8DTpiNP7iaPnr(/&1t,EW!f Ige-AD?U8EUET:3YB= &,E@JT;%7^rdl"-1A-@YLU%?sXNo?r8m,A[-H/2nS6#jEPYnV%?8s[ZEKI#;th?Gg`=[r!O=(PIh,TBX(g_14V[jS*oaF=I$]1sbg[.L^U^;gh(YWfco8K*Yo_1m:Y<9XcMf`cd>4B5_)2tP$jja#:\4!Q&4b7GY`NoO5)l:-NSdZ!odhsA<0YX:T`=U,f\%TD&t:"m`> M!V92(Df#!`WYAoBl/A#NLH"XGVXhdmrjc+[)dJ*dXK,\IGLEm)lgX-\MejV&!G=Y:j-ck52qU]f:?rkh:i7?2;1Q-l21cr[\o+JQb/1L2)t5^A(K(9BMK8ZALi4=<=tND"j]nXAgtA(i`T%!"+;A)nFJFVQU)$Mi`Z:1]_AA[aVB@XD>;h9_6WE(l2Gt>I:nBrLcj(nb@GM"7=g=S T\M 6Sqi_o/_)cOr]O:QDt@qk`:jA4tO^+:j#MPV<1kV^;k:)$;)_?,mGqe*AY8#Ago.k. #OY5g:>?g`$qSg+7\>3k:ak*qmj; gdGUiig&5U,BYiB?$QXWArV4Kj*DB,%W\1*9ES^lg^=HB>8qa4%Pol\nnS8*!r`%4Nsqr15g[*Sp[--kpIAq&^Nb91"\Tp_iT^&m='FeOUT&X*ni*rD\0P%LKUetBDK3A0^^EX08qjg+O2Wrc-@U"`M"3R291mG[$7G ;>pnbijT)6F(,$e?88$sX>=(P;!]7e(ht0^MgQ``%7KjDdCmVbV1SLTeWg7PE0g[:e0Q+,4VPfHg+k78Hm^0UO:Ea$>AV\hB0c\#Y3NZiA$i(hPh>PN@s_bKW!W_El%bNg^sA<)b*p66]'!R*Q9(K4'&YfSUHY>`J$0X.Q.m'j _%.LSMKF2 hcael/5(B=mNh&#@7pb'ZLR[41U60[S2L\Fn@eRM_2X+hGYM^-7[G-^h.^4m_d=(m]5DYm[g 9)kF0/=]Dog=hA`@.A!0&'kK'#l.2,T^qBde&[Wq2F.bl@[(-?d-,l>[][34(NmM8*/l,m/fjif[+b'7gn#A!8+H)tiOIfY-VqEbFZ_*d+(Gi3n^cWGP9"I$gpO)Tn\@m848(OA=mL'MLD+#aS^eo.mA0cDK@Ug5O`ig%s&b(t*&?T"O3RE;'g33#cEE.Q>B7Dl"&`\[DF;(RL8R9@%l'e4s$(;7Q3(Wo@Dg 1?GW>,B#9f(48d;E3nkY::p%B?E]4rUIIl/S>_Jm)dkbsPX]I1iedL@/lhDr+!)O_):A4=cK\S.U:*t%V?A3hk!"i-Cgl=KA6Xo:/DJ##(3"Nm(Dh+j>tg;ORJ.t'W;1=k.C5W1sm^T?g%slq,RG37+!"TtcTI$U3UA+B+=O8'F`?mh^5=beG\9,e^69I]@(&%moD-N!12*d]<.7Glqa!*ddYLqWLO5j#$QbW0oJP7XXJCRG,iXOM9&\=[HQ"L_I)^,EpN$[A@0&VdqbX`E[`UiCN%PZABVibPN)U&/l+h_E%h'%!t^k?NKmL9?1i^nB\OT?-_+,`*X4'OH8h%\#],cmg1Mr?M3elTGrA&po0n.XNh9Fk*>h$[(Ol cr-K S,)2mYCtm$HqMh,d(3$Q-Er+=6S\YWS'2tE(6">0]g3D.9*7t O!rO1C-g:JTq5Fa/>MoASLgTj9FA%b*%I\Cj1.jgkX?3n:,#WmA;@EUAEa&bJ$?=5(D.[*4F2ReSk8pq#oOWCW-k$1ks=hN q& (PUA[]iq(elgSlXbZS"I%$iOcin8,_h<*!@@N\raX+JL 0Ln1GTjgIj)d,8ZU#A\<84AiW'@s%#FZ">/ #JaU0hgBgGB0!Qc_RR&rQQh*7 UR3Z9@k-(lDP)XnsEoXt"An-;LA:*4KrF*13/-n;Q&[\U&X'&e97jkU',IY7AoppX5nKZ#s2JS_na@R6ZF2m6pE+%-"$6mt.t5\/:rcnO1B%KC@ r4sr`p0'RoCQ=lfNam6;^?dLp.'3SX;-pZJ?b,kdd;V 1#KB8WX4`Yd?ta$5CGBdo1" P+tR< ^oq-F=0-.J7Kj6)nmq9H>5(BWBc)jG%qIn*INl`TI/np<d'%:lf__o"[jOsqiWUa"1hK+"bA7`"/*+/6%?F$n,^rGfc?.&c\iFICkTtQeBgiR?_9g/G9:N$lKMdnpil^^p==U5)5?7BRiM0l?b78K"H]c%)GF^dR<4\tM"qfhWcKHcJHPH[i7a!>hUP<4<@19*b(^]?:KTZ+P?\/GE`[QMki%nfAV?A6l+(g(t$O`\-2pXCkcU 4p]AY;-+khk6PoZ>lUDbnGJm2``G<h@p$t+39jh;9h+?^4%B=VJ7^'I(_B0^ok/>K!iIe:rE"5UGl1c-;O@Z)ctM#Lft\65Yh<@c#js.!]J"c)jQn\GBaetQ[0WIGn$P(Y6;&:*QW38ffW4DA.Ah?;#-mJ)gi1YT@!fA?7`]Cq>[87HL)rgZ0hYj\<Nm$;h7A)M#PS?$Iq!oSjVCqpaS#WIi(J5=A^c*mX)/#S=%UI-LG!pl -(!pWW2#XiqffEASLdN,(Y*]FR36OZ[EIcY<q%S\?dC-]"I.,bf+rdB)RmB%9I7q8>/q+_t$%+.E7=XB`.PGg7hs7NiZm2`p)PM'D]*e"Y]@-a/7+)DAH[KJ%1?rGgE-G^B1EKj&'CE>-?`mdXs#"\b,P3LmFqOP^d7C:d,4OT2ZpAfBt*^]h"+Q/:8e.3AeW_9;4.fDW@]!!^!tIss`*le='i?_4.F=/L'N3(B[d$aQkA%4%+SF4Jr!AHRTWkLNlr+)_H',e:6sEWnF1YqAiDGt?(5Kgo?&aP/t"ZkJgf6CJ)&ER&^44_dnjZ"> @`1L<3f,*t5Us(Pb>bKLBA[*n:H5MA ;V='WQ@[iBiPFaWcj"C\=/RnlUoJ-HCTgEt>F,l.*f92ArUma2 3m5oT4%N^BS$=$_KW/pP;bL6E1lDUPM6$F8OOcI7I?.d>*E35",<tIg/JU%C/T!sWa4:;ohiZ0,mXUjpC9@b?TJpJO>9\>4R4>^8i=/H@%_*iXi!@Rf\akh(dl+#rsRJG]H)B5"+QEC[1ci,I8f`(QY+>Ws..DmH+/BDV@9PTTA5!?nKhVgAF?['JprQQEC4^@16rgRqELddHHoSl $:X3HCrr Sgi!AOG#TNg&*?r^o*Ms@< Ooi]j28T)^C=II-tdag0=:oQn&>)E-d;+mVrWM*mH1d%m@Jk<*'F$I@KJ>.:25Yh73gOQ!2?:O?2a=/(G#)\X#_rg35abm8rBj8K&OF7$QKH0YCp[D*ROI8F^$\"e[:rFN2J;W0a"-Zqa?;(Z1CU5;OdaHIULE$`^O^m=A5t &Q'\"0U#i\(EL,j)oGOKmU^b>\Td=.mn=9\EcLH`N9&jWAcsOE2!HEkag7:LefbK;MkAA_!h?iAWBN^Di_6R[>0n@[ FHg<_A_-&l:HNP!A_j $"]s`Q'*7dRl'd%F\B&P.%Q?L>q)\]B+ce )qT\KRgNNHQ#o!-e"X/S=(I2bDE3)FV&4:fKY:?&9;nS!RALA>q^\FBY'-4[>lQ,?]#3/8F3.8;J/FG>$0,mJ3dJ&hi$,n]iE5P?Il*"mr3FQ Po-=<)id_X)e/ZF!)qCA:#0Hlh9)R0L$P1O3s(O5XjCK +$QRLM&Lf#\D[tJhQ0g2%.Et.1EhW-I$@8PA7ElQFTX4 @Z+$[0ER'AX.T0A&m[J%F=lqa,sP]_2,KG6J;AN,EpcbjNpAM`HP,F2W%@,X(/9s7A1.haE4Z#FV(Ut ;DHrtNPr;p_V(@9<`YlTF2\`U9Q_82c#!(]T;r0&= kat71d";K$:+LnaWq))=ON$KV:rIda\(@Anf_Z/I:>&-k:i$jn-^O4!j#NfEsGh[#"Vq%5 qn3s3+)b(^.Xd07Qd$dL61bR(%V$D!sAcrh"JG'FK&r,d%[thtZ1Q&MgV 5Aa2n6jV+Mp"?& "i8h+dmKbo@<'k.trdH3P('@$-kJJrI7^.*$"Xl'Z/C#eQ_7@8dEmsQ\L<(8lqhf8OlRSni=T$@'FgGqBD=Xo"m^O8bJANBdn2$78Kd)Tmn.Gm.]f'S4-XCO >b i@K#>bL!a gme-G(e%-kbhB*SGXF(&bkF4M5[B 2ksLC[]j=BIm_C^n5oMk7>mXr><^?YRqJ-88)nH.lYeBA(TlT.Xsf%bM&i[iAqhD2nk#JkbTS.Bm tnE:?h, HONoE?+(+t'q29[5Gg7D*0"EgODHeaD'[O#SDbpNbO%h#Z6&7*0AW3*9%gZMk8C,_#4R*V5Z!5Aa``/PAcpnIc7)q3NakD44nF6.r\P(rB!`cQ#$>PE6rn,Q'jq2Z$.t@clQH/q)K@IjIV?Aa%+.qQ^o`6+`NT-Ac./4;LQ!"HJ&@)]4kS-dVEthjcMWCM[?Uj2l5`!(la4LYpAt120S[F,$+i]MY0q[j!bOcpABT<*A"Ge#%>>">l>J!E=#_#pd73b\J&81(+-=b0;ofqW#DAeENO26b=Bte<=Q:LbC/W4L'NOJi*]kC(<1A<.ne;_k2K'(KA!CN5IYW'_f>XmZ3J5E+YHf>66pe(+W%MeTFtGO2C^kjd;c[td7:f"JErc^WWW9P8X"EGNb`\P!3@kc`]ThN AYGM_6jlqXqj8RaH`BpnJFO2G;^ _A$Q0Ol#6 m4hSdOQJMfg_"j>o5Z$7gnSf%i:A=s5P`M/6*>oZ72@;0\\O\NI!bo0IG`/1l0FW/<@lnX6#\BVl'nb\s.l4/KP60orniFN!MnRO^2`l'KZHHne*0:lA(Ha<*Lq3,M'>&fo5';oqXZl.tbHU-`O(sJrsD\3KA^,LhM!:=YmKqDRCN^&^:L_#H2SUS+n0[(\SE?qGOYE\CV[7UEIkjR)bPsA=$%P:0jo%B67\S>F'D*Y(onLJi''3pJpDW^$Pd4\e='d[lCfj5m"ncOQ;FIGS+"*#kB#*.@ tW\Z&!rZ/116]lhp23o,2?=qpc"]3#8>$/QXtslaYR2e^A%NGOS6?^h"1-9AS%H[/tUH9NF)0cKjLAl?WT85G:_\%28?)cM#J)@i0ajWF8h#f!%9d68&O2;LHS`G5&8hUra(Edco^\Af_fNcgaoXaLH)b Y9DI[]_8B`=F*8"H&*)hD;]5O!DI?]VPR+`VE/.L[QFc._d!kJD;5.;pG^`7\?O(tsh$nn62%X>5h2j B1*\can[?.t5>:OElXG]o]BE2ni.m4GkL,#AM5(=5h'o5P9n sZJ))QU/]T!3ngkVGW2:Y\\=A2A]VQ'$-g]taXA8jY6@8c"He4j4ai [b*5G^>bRXBCo!^f!8c54&.I R!a`b C(<=.`Lhssq:nHF4m8`5BU>Wf(Fq/AnO:BgHbAXd4S@TKWFscj3@(8DA fCt3Ap7Af=]JYGcIC$k[#,%/jE+X8 f7<$!kZpZ'sT53W@@oTiKOi*9Rsr1Y-JI;>BOIqY]S34A:*s-hhkQaL3UCsK7eGVcodIqGB`P6\(M$9>q$OYtD-_`,lF84SFOAWdEcsW8p1fn6\UUoi(3iXNt[M-7'ZDh*ij_rhO3dr_V*E/3[iGGl:G%9 DdO%+[L):QVF%E9oo6_+j_o=@hg9c;nGt;7pWCA5OSEb)beNGrl7Go*:Ab9/La (Vc,CHTp -ed\QeI-L%^$'Vp]YT"Ce[HsM3"7?T#e,8Gj". e06qYPms`_'mp:AIgealhh1Z7$o5sD[o+^XjmC5-kaX]kGZC,0Lo3S!dg56eJ$*G#U+k=. <3Y149a=1@ _Q8R!DPMU^/Z-WKoDM0@!E5@Ja+&)`I]-H$3-@*_tMdI7;A!Do'78BOZ#9RXOGj0Hhq[#^m4&75kF tr&mo6OD,#G (Db4"\e0hJfAj!I#aecb4UEfl>.a9tA'T&O5X]j]I=ia3HB0158N'.%h"6j6Ip/g,nke$",.('-%UQYjCQ'etA(]lGP!Cr0aFO1GBX\F2;Yn?j ?DK"]kVYLb%\1XZab0n:7\mt1sHdf.pUOS_)#B+lat?3L:.T."\JbMJ,EPN^2 6d+31P,TJ:\TMRa6)*]lT6iG=B/W9l1)MmQP+oBH&&"Qcq4Ak+f$jphpbGUc\f[UZ@RXh7[G?O0eGJ AC=[ot6X5ls!ST!+^:`01dKna?8=_V0s#Lro4'bgM52UR1)!ACO4Vf>4'R:r=K-=6Y^j"RFjjL_R ij?@tpa(EQ%n5.B&bCY]];Qr4P;LHZSm2b)M?:0rb!f/C457tRmAq1Sg\=GtkG;saf9Ag[AS*qF:FYp7$rm;;ksPf3Re9egW>eLT_V4L(a<\LAGjmkD1(so:)mCI\4QYXoXN9d_8R>+@& tGbj*f,FC>+F`'\Ep`J1Wcj*3N8#nm;c1=qIi9*#HMbtdkJ!q4Q+k?VIQ(NW&nU]DEA&8pMTVq@6Orq;NQ[h6q=)?AEoHTEcQN?DYD%F8N=7F75UsA=^DL(* Y:odI+^'3"c`OK.;G`c[8;?c2[9bUmA37!/EEfNIQB*A"1#Y"3_._Y/'Ug&C_`&5V'')6[t.4n\<b+X-a[rH8Ci^:E5a3b XkAjD]&HWWVS-8/.pNM/n+-AMj6=1P>+>[qn #=A66c3'"a?_'R\QjPd\-f?c 1ga%M`^3;c+4RUe+8J]Qc^c,Ea6qR:1N_@#i+BgPD^QC4$@[7'<8Xi8^F\gEH7_,mHW?ef.$QcN6:C/?-W:]`RDCKN`d8GV@@R*k=Eh Pj1@94h%n4D#mA8Rt0O<(l7;R4(sg)EZH?!/(iS@WX`.fro5+$Bg07]NU^+S7&3Jik'IOK_ZfeGma;rK#$ZF-iPa5+d2LMWJR504_EW'/!&[&so,'GJ]NJLb2kEp'S87"_VCmXsKc8&pDg399c8Zcqo+(^9VV\-4QE'79ir/;2eI#HTb3i8nXX9po&?=i+75Cg$d8QYB"qAB0RUGUdZjq)EC)99>ednIT+rG2P5>/"l<$^#62@X.OP0<\l&tK2fqSko[-G5+WXG/4i,lt3m7j*gp-Fqg,2;DQAA17Qs\*:UZgH@MD$7.Yg+jAnA,_E$[ZrA(SbGGRn$P[ Pn[$Ak]Kf1tm&e"7\3ZgYWh+Dp4r<`'ha;]^34 ^PTd8$Fd[_r#L*tL2S(O/TG34Te\7Kh%WSk`CocYt@2tI&0YIVoa@#:@iq#5"gL79n$[Y7Esp?b-3Z+QjrVJ1iB&m5p[nZO&j\7BHo@k(,;`>b@A]b)Y:*C*%g/ab=IG/^&W`7eG?"X>\"D':(p2`D>QANkSke_V6MeJ3X4&gB,fes+mGORj3NApg34f0\+L:%JPm\PA=;Gbh^D\;[RM9rV/!pB$qNAA9sno2"bCM\QRA.MZc4&Q`?^OVQ 9'DLP-S,'U3la.pjBK1\g5Z)i>)S33M& T52iAlVo0`A76jFEimi&aafI7>pOU8]_SroKVeW. ,lM]!(:Zf1=V2%@/"ZPF:XF8TXDtAC'&rc%9T':;oLIa<&P(D$MF8KDsKMAGig]UmRaIbOnP?9.Yid]s6::3`e4[H*l0Eg)\At:J#o38<4!>Jb2/QQNE*^9An:I%-bm,)Ar'i?0,So/k-G)S_(M)sh>TqJH:_2T9n^P\A>g)[Q:`L 9X4[k.#X424]_oHPg.faGtb,"!s8\ PqGBae+V9R42d9qQ$#GC?>fTUd8KG!VIAiV$MWr$aMAf>,e<2jfgkB=i@\;CD$Oro^2B=FN M^o+ n8@07?E!`ebB^@BWN1?IR];O_f(sPdLnd]6n;5"7?n>2I[N2L?69OH.>.iZq6&`;^iTaCK !?Ai@S.1%n(A2\$;/fJ!6P0[YL8XT0@:Q:i]C*9E[-S,t=Jqchq:UW[AKFq%A6I1R(F0,'DT3UZe5PbG*?FHaRoBd[MNja0sN@4@X2_T_Sd.^> 8Z]A(dD>(5K54HM5@h"CK:`F/4='/0+bgQKc >Vq]Ff.HK*Xm`Lg+`L7mk%1"32so5Nq2j6W8d%.QnNZP`t5eV, U3Jln$]5^5]^O4lT8@SgbpS"F)7'p?SYAjBSR Q`opb$BV`:"3bt>WM%_CT'(Ap3P>i_ C$rbf47bdK760,a3\&EdC_]d?:\Na$)_5XF;B:_ENnF&Ltd"XEF[&0JfAsID)k!?*21!rI&:Cp?/tkUh>:&:C6KAFqCRQe3h;nNtD$kAqj>4kJ#s@L'YCp-mRRZ[R^p^Z,BUq=6=`9+!)&5AoJEg*rWK]nnb@)'"/S)CsYO-X@5?dq.MF[PWEU5pt5F[]W[M#rZ\Isa%#;KeQ=4t[r%K)mh6b1o04L]N8jlEB-*F8gn5o$TcJ>T#%;1Q',oiXOQIi0Z_lm,Dh]&0e6+I3Qeb9O[YEX)VB*K\_1_t'N;nNc*$I_7'0l-_if0pYIRimXPt?ZGZIs<\>Vl4t]F!X4E&(rEEV<I'1!+9: S$Mg:/*p^'SN,W4_'-mm+F9b[pEa$Di1&jU/,n&I:H`\6"=!Fit"f+W^Z%s:b3-2D5,]aeD5%[a.=F50nZb^Rn$>o6Wp[Ei^=+r*q)(lWCFrUk 40p(TP#ATs//KMZLGDmD3G9nF]A>_E+*bfHq<nB]hO$KUAYS6%B-I:_]CN1PPN );>A.A_-X')92nDI?cj^nTCXE+J]Jo\"$=Q`l-,.blk58Q3N<$X?RQdA5B6=B8pEDR6:KH,ppA=jJa+K@n6^bn$'$O/)Y>J?c$$I-d,#3j^]j80Wt41MWs\?WJE,;COD?4ms,oD.sIRQ9a\!i8t961pg^r4kF)6VXh%&Hl9b)q6K;`hc#H8^n2 )AkTmRhAMi3I"RWbVkaFcN=+%5FYH[*>XUn0/b8XsF!+f^5/0ZfClKWRFbo)M5tjDPecUD2m=''7eSmM/[mLm!r[f?JmZcrkg!Lh[1dUfN?dA@)F.J-9M)3$.Y20n8Zg`3!(UGd(MW(!#5ZTk2.M"2cSaNAOAUktY' nW2%P$'I>U\FeZ [N"$%gr1Uh=[6AGTHBICP3:\*l#_Y0k"Z+i)W#8i_:O a9$IBpl>:i(VYHQb=`r"6 _fW:gmJ[^6*`E921NAIAZO^#7'9Vb?oI&.\S7c%#^#opo9IXehk=\0$T0,G%e9#82k=g$S&G%6N#^S@rDA!+rrf1"bRe%AL (FOT^tDX"( `1?C:Ip4sIW(W%[>5Jh\UWaBn>X."Kn[=A.c7#a"C)<:kfN" 9JLLN_S@aRHtdj<[DVF"f*9?)do<>pD;1kP>]0Vi..`S`,5.>9fq^pL]A0`k3Vs6,]857=RYbq@!UHV7#9\,F6f[O8Rh5,X8b!*h[.&6o?BmZ#9/Z)=[Ff"EK@J`p.i7?7s%BA+n6$I\-VL0agqa7[42#t)+a`/-F(Rs,.6$+6As/EQAETU`7_`*NQJaYlW38t<[FGQ,\S2*q!7mZ]E3a2[gBgS.p=`(O20#3ZfCMTjW);J;1_>6$@ZdU &m[HUg>Q<tgQ_!)k_QE`[%.ZUB9]k>^^db"&rlbj?KDiifhg/ZZ_APqgXga](?jl%0\"OeGm?l*& ",ptA&]q;N[%KIrr&p_YC/BpJt>aANfsB" <=<80jfO3+pc`%iQ[G?YO6eP+]>d?nq"5,^/b+ZacXQa#(/!&"bCEbSqpD'3WPdblq$F-AJi5)2(B3>5`jF[9LDU@hh6=q_?L`R9H3&:TSj,hfhNA*J&%d2[eWol4`ZW^)Y0^!M8UM)Fcq<;610>oIQ6/7GKALd+o.:$:3kqk)Mot^Ne0654ciIqn%h+O@\$V9D+tt.B pB!1fVL;MUGE`s;(<\*ZK3'.?WPO;jH9K[/G&>P$8Z#-&E_i1Q(^(>e+;[-g0PD&.AIlFo?\RFs!T*Z?#W7aB/.+4oOgQd@].*bW:=T.qJ3\j#%5^!N^a `[!tV*dojYTeUId.kI>%?8Q&5Gp#IL'^Tsct/5E\imT>p*oJL KO#5Dr>1.1mRS2eKJ_rZ2_cS+c>rs;kE3a<[K3[T*-%R^`@*W1eL9&_&l#=3NW`+Y^]KVcg]ZqYG,l2Z,j.7,[02J^J]!oeoG-5:U23"5Od,da430\ZNXIHd.rJ*;jUt9d>(t*L^GPkX]ce Ya#NC7c#MGa)!7cN)j5LF%&X0?D@Jn%*/A"NAV$G#mI-+mj)#/^ecY`^!WKfRk[)Krjj1ARmUip]/P#qG4I9H!<]*fVBJ)k*dr3,gI*\'M_bb4C8`ip<-G_ngYq,YmqEj,$oYIi\#NF(>ZsEZ"JWrfdhTGDVP6tSH?`Z";]:gMo_QQYXA7I4Qg?Z#tE>?_t)*t](SE;r;J8cS3EP7.@3p'VJWPL,fHsD%eim[CThlG&SH>eTd-BUo]MC?D=gptat:;":Q(X;YG*5rU7ZHN&[9[!)eRGqnV#8A44nOnh(0Q#+G))c-nQl1Wm/]t4bfpO&A(p)H_8@!A_!rP+0#(8NNa\53QCFI!Irc\#NmmKX;AX:haa'Xl)haG'N+(A@hWfd'QR(Xql,mX!#OA.-?k&Zl)HK5Lmf6&Kp!!dS[fh:rabYhCSl#c#B'F4ZZ-UZ\$5XJDf_X74K]nr>T+"jem!+*`s[Pq'$C$oc'/r=h,'6!O*=3.1m3.SPF4D]jS(X0#&@ZCo)[GG_?`oddGD 7s/7[bL2 fN#KQ:7i:B5(2q$;s=n#^1"c$,5G^6$`V!H?!I%/M.t5n;;?%rph(p0YP/[heg5E,:o3toP@=.OPOPUSnd%RH=7k[O&Pl6c&kYdi^%Yj?"FEl-A>?0isP3KJ*=k$--I5Rr:EOJWo>1bA:n#($pV_7VoIs)GR2[p>C2C\p5A0X]o J?QjNBb$qIeSQL=@62^#QhfA*aYA%f'$XRl5l9gh_G,LRb7a7O1Zg_;r&A$tA\PK&B8sASCYObeOA=(FACKH3!`[DHfpf1\JQnEb_aOk@UbO%?'3-WfSV?b)DIcVD^I;eAU#9`ZH(rp!i.rf0tKF[aO9<,A8#or;^g50XfIG5;t:3<)i"gG9)7CQ5;7MLf>)nr9EY@kSD!Uis*c0/^Y[aIYBlKoX#sQTP4p2+]$ZA1;ZmF%b.aUTSi<"*+@A?G.\6d:EX2%=1PfD'oeF!UtZ^KJ"3JnSh]"s^8M4* ARL^S+oi.Z5-$j`6]%?H"gr;YNAr)-rNT!E6MgGkVN>8`9e#$ c#/`"FR02ME,e2)ber_C8^$#USH:EaV )pi;h=oT aW";R&&9B Q]P@K:!1(A&"G?]L4_c-j3lFVCCqRJo*<$3$!R56l<^*C;)1GBl.">LC2QnRi"AU.,%2o;E9>F.TW4rCOfo/.iH_\Fk'T9b3bR=T06("Y=C>A%7JNc(`.G":j!GCto[aZnDR2LTk1C/,A$%Qna7/lFEjJ-dHFf6c3`2OQkYBi"9m"YZf+,Y%.&o*;H<*=r0- UT^ gp^c8J,5cgsUKleXTH^l?kDPC1 =*l,qpe@n>0enhaI!4A?OR6jb.ja:/ qrO(T;_9iTMME!F/]rOD0`%V.]BpcQfk]Po:)0kN;)d%.W>GCY/gjb,#Ce7'mCOW2FKb3Ea4ZJei%:a@^T`p>D9Q(;I?U;F7(Q!eV.$(O>l_q#olXJ!=B3m_N;0QB4^pjrmRp-4.#=#)Xm382Yi&8jA[-a!(S2Mi6VZ+>Q lFe ^h6P)_N+0nsbb9Yk7R+FI(WZE8\nN-.eT;105'(^QCe_E$J4e\/8ThAI:CU`R'&>HPL/pt(n"Qd\A.5G3r_>th%lS_^sk6H].jfmTNpsJ=",8$"TStbUY#&8Gc-q,Xh4]h.p4YZZ@>hm8^_tZ[@AK_h$Xn>47//PMT@Y!EO=m49=?CO_;(2+nS`3AgXf&][c_"$N&BUpnj+SFhTQ1aCXsZt&WFpNl66A&2V-Qt(&&""=IfljF@"'&]Peg$ik5L%TKo)_^7m=H37bb2(pOX-APf_IlRmiAE#c8*Z4MI.bJ1:``C@pSH):W8CdoSE#mbo9G5c5"b!VC9IZ\6GqgGtAAlS#S#U6"kE@+$`P3YC$n>J52S5t5P\*Vt=Woj.->>WOg`d8:iidhR\F`Th[l?;m<,OAag'DY_DmXi-asq^VA6RW=lpHj*"3;J_dN:(AZ>CBgWC&2tqrf]/*jl%:Y&MtK@?>\Saf.>:cmp(-\n9K>#5DCA$!_+k4kJN'Th]3Qq!dU2Wd!=QlT&n@^eBd#$`/rgc1`IYFjP1KAh7!RG2-%I\t"ECc`n6t5`sCgjHk/rMA5])U\7hMGh<(UAc0RP1M*VaqH9A;2XY.s^s8-KeAH#ipk+5@U*DF4`#+h"*,>3`6[cWB?cGR-TehldI1#E^88TCKd\m7&IQ=?!Tb;DM_$RI/&8;Sc%m: V4o;3[48$>5d0R\Wem;+US0E)+`G<2=]Zb*L$`W0[^dN^N1jQAWEcA$)L1sM 4YIaGB>9,e+4m4C1_[g5[s-S_5#L2f-ZkCFE@J"l?s1(&*":A-X'Ki@B*Z?AFdY5jlk5OaT,I^aTQd^V]iH2P9GY":ph=P4oLi-)3P&[LS3"cA.85a Vfbl5VA`#[(UDKh[fn8+MkV&B?]`6D3o#JZLa9Sfh0kp%Z6>$MMN.!ARk$Q3og AXd"CNCM)&)669T76A'*lB&A".N#Y0gsJ A3sc #/cL"&a[dC;S9$.C8R\[Tg`Rk)nmt @AD6>sk5+6-8V=]F"Y5`Z-^L>(2Q0_ pcig6GKqho0/5dZG>6.U__ S6,!L) sp8eYZ;F`K7GK-]ViPKqkIrhM.AT%3H%eH 'mqa4bh>\.3P)Cis(/;W<%LVXeQlQ5lO'31IB_&Ue0`<AdoC&s#KA;A*1oGdKf268licsVtcpU,5<#jnr*O`Yl_fTAaMrlPDU ;d JH4g1]Hqan Y*"qWsiA[0&h+6EY .D]4&<d$ t5-T:-@/Y6!A]7;@_#k-%]A`VO`h1gDR A!i>e#eCRCSsC8Yg?gRP9rhdg:@g.H!X2Ab RNKBsQ=>mde.t3)7&m#DbLG]qkm1Gr_tAc["br-7-,3#r];%W$ 3m>>K%JgT;,!@t`IH?]R9]CEq*k)At7Q9<@nKbX[8m!:OB)BWP#<_AAO89sON[g=LMBk3](F]A8\RYt[VmMs#,iQ[)eC6JA8r""")gW?Jq#5!AJf7nAa)R,3e2Q?cA`nFp"M^)kO[))qS6lq#%<8%%,N7A`#Lk= >kAaE``=S,r"EQN\3JMMR)bF/8!Wf.O%A'MqIg>EC$s`6%: >3]pHd[`hZ ,,j#dH1>OWPkL6'^HNb).YhY16B5&s:!k_,"&%A:!ZRpNfHVTO3q<\QNAt](F%K,B03a,MYh`k^jreYh&?NCqF_H8\99 tWpjJJZQVqS?p.!-:NrIC7*[7g`dqa.M[W6i#8`I80ie6GGY+FWfAp6Oep^\=#=B#.rA8:X/=d` rP)t43i,s^bKkPBS4G?_Z]Vhb=HA)+7E0M ^V,&^`c'M&kS(r6b#ft(F*@rYg5Zb%4.gih[+,r '_V)d07/8(d7Algo)GEhW>.g#jhJ\`C\Z,Hn7k(41`o:. `9 pHBRGA0q/%<_+43_2)lB9gjFH+OLjVa&:GrqR"$_'m0/GYKA`FPio<Z-#+1qf1/2YLSUW.:L<+ti7k^j(tVY131(Yf !Vm.&^rl"=OR-`hA-jlogkW]M.k?UD-2KlH`fk"Zh,@sOG30,e]#k\4a)47S:%)lhNd2-Olmb,r)hWDW^pq6t3](2('jj8V0oDRe)-r/[mfAHol)'>"R/5U"5;5lW>1RDc5TB7`gR<(%jmgVCl+.dLpmsb-t I^&@.lA(99NA=eL'j[ZS5iQ7(27&-JjCTlHt&<4r;OorA+Qr/1-3=jc'g.*$`Ap>3)O'_M"h6Q2?ghgsPrJXRbA8T._&_)04!0k`ls3/]AH)Iq>s&aGK7fU55GEQLD$J9'W3'.`i2=]F7q)8etEl!B+M5_Yo1bN-B6$79"0KM]CsnY6;cqeiHNdO.9J"BI[;MCo>R!rDX7T;*9[_ \s&=*p7e7>4L'L>knbW(n9K 45(T_G[$_4k3Y^8Yof)550FJ9,^6 #AXiQ/tekn]OA3Q_IG\;nbP^-@!EQP6n!h]`-AV*6Z8kUQ!g&dL"\@C&EP cN/>OB#AdfA["=OW]s::[WLCfiRqa(9;ldB[REY^Ep#//28eMZ4<W%Df*q*D5AM*-*Bc"9?fN67EQT%'6ZfDBlE[KP.^V3ljM3A%=?,>+/-P83Mik2hsGoB.a 4dne AeO7i-mqXo g"LQb)4!G_ [e">4Rg[Yi('P*Km3K\_=1(4IinfR:<Y6adAG eir?6UOAd'Be_bM6""?H;QAN]Y6leN`6TX(I3f$::F/ra@fAjpA63Yc %2\3rJS8b;qsC@]c)UT'd!A:Ak!'\i*P1 25WDDb'D)b^:so`E4l=?8F"lpb2nAp+\eDT21''$m\&l#h\g+%"R0lr8lfk=94PLDH.IoSBf,;]#nK"3kb?Z6RY\s],LZi_"Sd@NAI_$GHNBECT-grSAOcL@WX1,'FDeT2XL8OK;d-,L)lP,3\ngKVG[Riea`tK2rist,D&OfRZFD#p9]8CqpYIPq*n)pUEMW- FEpiW;_(< <6To3Jb?RdV(@1j?r.$#2^>U)#AT]+t?=FcB/aO1h',8peaN!_qE'CM;aLTPF(pF"b'`kk[*G@%bJNKU)=]#?FpeV#28^Ffb,1+mY6<8J4+=$M'!7 =_"1PP12";)Zt*MT!V#B7coB0lRHT]rLXEY+3t"-oq%`gV)1IEs7F?Y,67h%8@6,[H"ihY9+5:sHTNc/qo-esI"_nrmHUZ7Y$!Gi*k[.TFrKaagJ#.ZYc`IZDb@S;$R`T([%\otr(7'-!-8_P/?#1qX4e<^==3L3codji\,sAA\)"NR^]KX38CDA_ZRk9g/*Rgd'dIU'T:UREr*9C]bR^"e)&Y6nC(fr]"=0?QX:6ldPb8)\o\Hm7b`:k_PNBYO(itiV"o./S.s\Q0g(!@%qKX:32LDk^S(t:MBCXA6NN1AsNU7_-)@(He/,ltg[<=IUe6,KP$1APhQDl*O&lpe@2At-@SYUb0%WYt6-,Hg!)>DV3BDO:9I()T/t. dja7JL;Zl3@ )K7@*esQl?.:8Mq"YW@DisKkf@T:jA+<\AaFYJm>1d%;m:('"A0aP`C?>D7 eN>JIfTEIAS1Q@B4kRn\/`4JId3a&'^,\n0XGE*Zonfp$1?rO3LT3Xol:O`46kib+<\F,ilohHRS1?ElmM(#eNE(!'Ip;L3O"t'lr[VhZQkcDO\5*,0d]1PD/( mf bcoCVi2chgQ^I%J1Qa3I+[#k&b;Rd?PUo$Nj_:*[`pPNtob%3Xt!Vm],\`G<"[AAYl0n$k>dQ[o-SNbQ'ZU,<-T" Y8Zp15qL@=Ao[NY2M;rAJYMn)X8p;c7o6*ilL(`mXG:aH3KO oh1=t_*QZ8?L6Mrs^+U9h%O:b^WlA9QiiRi'nZipZ._VbMVI$4rBg(R5pG!DD$bn=2:!*HVUHE(4!TDZO(A$*knR\hoWjk8Gojroa..Sb]Md;t>Ri49_f%8q6(p0i1+7//+5P0Y+lso[="9V?)#\'mBrihJ9`0NG[*'KjpP(*Q9ofL^e3h*kb,B5YJ'M$#^P>&Y135]ci3aD"d&9P,"%5"_YUXpO"F83JU))9PJk=?tp(f0.AO7SO$K>B4AIa8IqNl'OYbY"jA;[7n%Gag_9W+egY.f8(k.h)q%LB@G$:#C1FA2XM0>TkgG$kF5[gPD#m&`je4[-'8PrCC"VL!)sf;7E5Kbh)r,&kJHlgEAS\-`bqlN]0Ya#ka2*Mi;K+@EArBZUIp.E>NBh(j`U<+-ntk>t-QmF`Y,jA*I__nA._k/S"U[ql^[Ctc>e=Rs:/oE7/i(6A8^c[i6'\tlQ.q[#DoBe[ZHk$ Vf1W5e?g2f\6bK*SSYEZboDaLqNrBB8nX(sIU+*Ca+!K:&/f1_`Ym9rMWU.e,r/gpt;_4Pb!\tIW"m)f=T>UrS2+ErcW=!#LbbR3h<Cb(`3n(fOSX2!jTA!i9\K1K)AV]12k!!Hn2@8FoqfBK0)5kisTAbMb:P"^HogtX\4q!OeF^!G,c;boDYB/7$#cXUV,+0W*GjL[3o\#(:a?H'BqipVm1-sDj$=d>niPS#J>3i61;qWL.aVmT!a_qA:%LZNW7(]=F^p^D$$cELa&_e:AACH0D/b'BMaat?hrA+9tsc)66"5OsRr(ckAUFL=TgA_4Da")KA0@)1gp#c1d.P4-n*ng*.XG1f.=\-;(f]\s"sE#sfSX!gY,?]sAjAOs^V_&b4c^?i=?iDjp7p%^[O+jC$Nb@l9CstnbkrQAb?'tRRE!KJ?+TtQ26[&eU3KW(L7`L)O>8E-)GN4H6/X;Pg7A7j,$]&[?KLq1* o[o'mI\iP_m?ECe=AMh)Vd%?os1eQ9#>+Gn8$L%dAkV=N_+Cb2/C9h0j$)i@]VCNeZ;d^A,Q7:Z.?]#DV6q1SsmMT$pqN""p#`5HjbIH2^((E*dOp\UFAZVKkd2S?FM=n&[nHMJ]S2*aA%WFE7(e"tQ!0T()5T]?F[RQ\R?S[Ms8*-G[fP!_J<6MbE&cY=$;1src9GdkKiJ+ZlR3m?M(;Fe:<_D`.;I HI !25$:BS-I<^1SPj)!NEmJccU1`0 >o-S!b7hZc+C(.=k(LI66g-"WP>Kpn^p`EY)T^HB?nA[UW[HMD6&,qcNb;($:gJmLcLa;mR17pA0,I1lBj;sB4U>?t>'_sA 2<7&`HACF9IMJ?HlSCGbng-J[$dG+&ntD26WAINnS$ A]_Eo&;AJdci;W?kUBK JbHDU2=G5Ef#hnf1aTo\AsqX0nBCH'iF)sX*->7G?;;FSkT%]^U\is?>BNWMXGh\in!Ld=b0g6OS,41jpN93[OQa,1.*kNNVYc`IMI?gX_3YZ;ZfF@+o>a^JZn+W6P;UN0U<.WdE4)=s.m6_%4fQD&t9@Q)9>F"O)3*oS An?632I[`68Gm$rdPAKMtHb:dU)R2DX#mmVB3GYt71=dDX.D,kLOnNd"EC9mP%S9Ln0IA&)MMa C@1.a+:"J)A=>LimCYW(1t+9,4h\./VSQHRJt7f4UJFn:HY7bef%/5=-n=;=Ek$o[Q( .:-a,fQG5TE'dntYs7hClXj!)CQ20gEE,3B4^hFrCOL$;id=;lml.kg-]dX0[ZiJ?mZISK"L#H=4T^osPQU(P/T.AA/Nq=oh4%n:m#mKM!D;QsN+1?+E^>iC(5$9-K?;J%^E3m.UIL6WZ>i[bY-sDtO+6_BDXm1tZ@%c<`&b,g 5XVjH+AdPTWB"+sp#^=hX^'NnQ;o;<7-c_>l]%:O@&2ei68IoJO0+h#Sh"'0C)^1=-qb>C)SQm?)ac!5DHA\c4sNW@KQO]c_FBO^B>5B('FV0`?C36-&h=ap6 ;KHkY'28PtoM00:m_!:h5AK8<^)O@&27VPRr>s5L6CFB9ZssE(ZfTdeGPI$T;hX#ksB(D8OY[:7_8oD;` ld8QA#ON4+:oi(Q75g]Uh#'YfDJSR "nVWiP$q'>(R[-=Z8T#WI0rWo&k;0<$\9F]B8O5!baW)45APX0PTd4ST^J[F5moRCC0InB)/t7Qcq'tWL%5tX!]Q)E`fN38\8$hGDg5AA:)e9cU;qGf2AG'2Wfqk!!j.SV2EYn6a'_Ors;=[F^6D5B+M&9Oa3J>E-DAMA#[q4::0jp[l)h,:3Y*IVcb/"pqV(EjehdV:&\X&]'f@ffj4P;)'W Cf;_2-C0Ps_tJ$@*ZeV6)LfY[a2U.m6'VL YFAG-)?-D<`8!bYab.GE&AiTj?*V(hAsHaqNHUN&3_M%(Z3.@NB;%gfi0.aH,XVl8UTlG6gAlcZsgYM\7ZoEb+</?@ekqFW(OB+m&g8AR1BB`NdPmTd8FD?!9*NHZFQ(*Hq5kc,/oJ efAmpWGYtP+QHa#LqN ;bGdUOep`3&Q*:NafN6@+-q)%l=Bh(AjZjaIsF!32;'aP31I';WtBo"_DEk<#?$54O4mOH6YhRTp\oUZ=JTEfDo9*H@I+/A`/H$)PL+EVM 3R4nR1^jOc!_^?`>8KBMT*]QFP4_r9a&M-A/MM%9&Vqm58C;IJPMR&!nXR,\6'D'mFfh(TN+.q#$=k>T?5t9H?$nYX:@=DEFLVkgA:'jM,?dGG!AIKHp"$0!KA%2%!d;(#\TG>ULXZ]'24H?Kq-hK%Ee]18#S$nTE*Q$m;[-:@7GI]r3$#bNg26YaDRCdb1H&G[]@f@&!#%]7o&J:RpN"J:Pt5M:2;Af00/b"F.7!?_r6gHYI-&&l*42`PqXHAO&cK1S q-A.dej%g2r_N6UPcZAj'/Q)iMYQoWA!63at](rR8BrAmc@5 g>XK5U;H8nY)jn;jRV$p.%cAZoJdZb0.U:dba+h,[E\Hhc6PF(h]l*!O-%"kg9[A3pWJT(CXae412[=6,Ahng7YjQ<>VoYsY>;?.56aQBtL,B+c(9:4]43_H(T--b#jp38=3k]5PJZc>mN81oF\,V))#F!FO8pMD:$BI,H2C\n1(U[r.G,2."jbEj4"h*G'5CQg"*o-_,o9Yq1"=MFqm;enNo)2me[s@t.b1,006:h*-7kAL!,dmGB%p3.[dh=meVN/,;r/n^Are4-1`MV4rN$"q,n-M0s[K#J=@/X9JFr0/(gle^TC=,-22CM71id:$F"'M4hWk9mU<\GM13iO&/+F'>'p;UlE'M$X)i2^')8V']\)W8i1h'=]!;D4sMj$7fO0=[r/O;G&@%:E]DJaKDVX0b;LB>1H7\r0+C':R5aq1k_kUef.BhFW40Y1^AN!bM][3j6#88q33ddAoQ5NEQ]ZZ<5A=(/cN(5@UZ&7aZos:0 pdrGQKe+o!!c !I8N0Tq7N*p/S;Hpcp6*<9ZEG+V%;SWHk%eQ7hU908p$nboO:5E'(Gn'BG4)&E/6C?OMF?ZW`(lq7QCfPF89#`\SE-q2]N2nstM`&iN_ '`f6Mq6&8p+*TI/I.!kM2c)Ibp+iC6Ll\!iB+2gP/7b)?rM]IHA0AXAo4"3Vqjr6K>D&\7N]`j92l9[Fol\B:l;QBr17S4dP,X=_US %]LJT$;ap1=F"U%O3,AH@YfgaHMP1RJX(P]JX_A@E85Z9A-MQ7Q4tR_htI@LRLoONhYCn1kpqIj*Zf:>@iD*9p5Ag_-7ea#&Xo,![+3nY>#c&fAjY8qiEjKl"2fC"HU2k5Z?(VE]lc2o&$N].k9o?*/;TZao'g+`[E/gpCbgp+2[B8nDGdtiqU1t)HBNMn4Q'j;b<4k,.V?XIQbon()B8)jnL$)s.JGUo><)]=+#Ha=+dLlZQ[<$Hg/@PD7fAi).d5*Z_F^jk\K`7&9#>W3V'1lE;N!`N-<0-H+R50#A_GJVdB3>@g^XX`4iI3 KU\6*/:BNo^U-YAlY0L`(BS;EY/rHeA^m[]t7^[dMT!-70VfUgS5`W$mH"OL'h5pO2640 nVA[6'rDE6sDJ5;U?[52?Y03-h$jT#6K23$;7pDLR\8g?SNojB!VLtchs`MR-75n.`SZKf? ?+4lTFJ;jE6*$mG4'$K>BSZf/=5c/IK&&Y`MARfqg/E ?[3n+fd&NKKe-HkFVch+[3ojgg?4H [5<=>]Pl 4?Q9Y\4gsUq.AGsHP3G(#^]6nILm;9dR)I\sH2dM3UVKE7l2aTN)7:iKG!$PB>`Er)j7kP:HW[0=Ad@p_(52`>AXOcgkr0aM=UR7!KFs8Q@06JF(.0sSM-*#Q-&+Qp$q=JX3X?O`EC4eAtJ7fP^DFRR>4MT/jnZLqnWafK\VL\!Fcl&j,?;aO@WCJ49e>mJ=]d]hD]qml#mDsM4t'Kj9j@@jWp:kmmoSU=7Vm"A74oA+SAe^JX,K&H_7:^"i^->gKdi-UZSs+Ghl32NZe5$7:^Q7WaiW[8Pr61_KI-e,r ?%4n iag8!+,Jt.A*:COLpr_HK$;_ga[H3E+('^")O6n]N@#:;dl?]09dbH4g^pS60c^9!>RF$PioDhJJb14(oF\AbC&2$JlC(;9g>DniH(`tN'>5aqA#3[mT\9(F&!J5L3?F.RU6M9;'=q eV&>Y1%d]5e9?ZE&7D;>B*-QJSr"O*WF\S=c(qe8#N4FJ!7lCIpn69-3B;W^+6l4&K>;^U-R\@b13VigD%Y.a/c[N?d+4-TRjI,k`m.LfE##>#lt27lgCeL_>(Z\W]$a0Oj-f+t5/rnJc+dj@d4d!H(a3DK9lq7 .mUI$^/HTDL[GncYFbZ& R60(<C7NZV@sA$5>hmHPd5FT5$[BA9A"!n[;#) (n3#5oC#q%f+)65O =tR3\(*dIjm5\)WO)Qn+6,D9'P]A9OO-V^f7Sm:__ $=L7SgZ ./&`hE )#T,R$mE"Io"_VLU4`qjO)fQK=2fS,2!MMY?9]=;1Osa^T rQ.OA]NZ/<@MWrQ4)".Z- o1,XjZK\3EB75DCpL^pl8aiUeI9p1EcH16ZQ(^V>NiA</,$R\&J9m 8I'qh4l>OBKadMKOl*#9nhBa`?_:+I]1@ssK`%AH&JhK>(L03mPfr# J534:BkK8 ^QD"=&),c0%-^WY1ZmWg8Fn422;M+I0UZEA<@-U'&A/`2D=Ni88)t\+F+`l569P/Z`7R.k=ei2;CLTo:'jGb;"SaLdBqBHm=d;O!5Aj MCsU(AKW7US]9e"_9bg,s:??4VZ1-6HirJD"67_)%Fh7MAN\S\BDSbY3rmWT3k39I0329e<2o;0`:W:4RMdp;mN)AC+>@=chL?8+XU6t3`iI<O'jjBo:,RC5pMQOFpY)9c06hS%@<"`N_`>e2hL:Y9)!NU)97V@U(tRck@5i+L,r+iA`9@A=MF%1crm%2(YLX&.ZR6IIFZ$tjZlZm3l&1/[.B6Yl8Ug7V5m$;/ >EB4\>MOL<0%&@d21bOK@_XNFh;H[J^hQN[?9b8(QG7AeG0NmSAE"LC>?P!M_IV@2$WOJt,O#0D1BAF3j80&)Rfn)EbYX'ke4dER48p*VRiW"3'8#]Yc#%bU0bo1)M/n$r\QF13hkF^sh;4KC*^[QoPi]MpQNQJBZqm=Oah2=GJJI^$HcK\d%_e7f$6=mP\;_QtEX/_J-+F'^%4Y%:n06T]R]^Chsh)Y'i_mBZ^ib6^A%aP\sFa[MNb@GCXC/S]<'jB"jG/)^&@@_ADT^bht;?=t":ZOi9b1lJQ':NR@gU%VA0ROb^[Z5 #Qk5%cldRbrb6$j$C7.r8p<Na0r)^4pWN09k)jZ79g*:W"R[\8PGqd2;e]t5M8=)46^I).[CQtVofl@>?.q"pm=Xc" YLPr[:]nh TK-qka^LA5Q=%ktd?W/cK!old>\C1bUIL3LeNoFO7.j+*Al6'MShW0ENADFe7MZM)1['2tK#;aID%gH9oZ6BI:VUATCX2K%(N$=i]]^KJ$tWQMj<="YQc-fMEJo<,rnQd!0LO;CdnqdL1Wc] .n@Ni2psT5BK38n@h'%PW,XRq^gH#A=k7t;4Op\]S,e1+mNgj(:9 IEO0$T&X1G^-CU/RoW_O,F(6rN<6J?SB#GY%;c=B;Glb>mm*&XI@!(]!7>sT7&m_iqo/#QNDkj\p8VTmK@$H;(9CWojQ9@ejK;`nfgOoYbH>E'MQ7MT$;nG7Z'9)^WflKHU@:Y4O;5I\FLUb5t7e:gkN"q(EOdOrehq&r!ROY3j>U;iTK,p1sJ7s1?4jN2-dnArgtpW0D+eC<>efRa_Kh?:aZ8$K1@ABgL_n,kgQ:\n*%tW;#CZ1'c)Bks@W;'5P:hg,iJSFcD$P);k=6mh#A:c/DSOpG9./#iTg57o7rU]Nt,2KN4rW/'!gVA"KgN8U]_irJQUP)7`oU9_NqSfZ2`dhX,ctR6T,gS,S^78>W6hiGW%!rJEdqX)#jsk)6(^M#cAp%@d%o]4dgqLK]5d@jg&pt.dr)`$#$WECm[Pp 4Q #0f]At_hMl('aJCsA2S/M3jiG.a1d@c22R-WIb3DX&S^pK*qs-(.TbG^_/E/F'_=p;U\Ji-hkMS0:O4.&i'a+9MObIlfMF?\Qd=#A$pq;N+bh6j>5;Qh>$5 N!dT&XSAbADW4T)`/;j,t%IK=GA\SP??R/f9!'E%$7mK\tcioalVe2g_FeSCE)qLAstRl;mOLhksfHc>@d&\h&FsjdS/n\d@aDA_PdU-_%fV>3++RG=qc>T:(0&_G+9U;MXYUK\AO?H+s3D!R$OV]mYT#dE#g_RWkM"q(I\AB81n7S%M!VB,O\6)l9[Cl$ F["h6ARRBHh/At4ah]s<"b?4;fL[9GKmc75:A2r\0'CSjY\ ?f@o]pWN)Lo::Y,-#+jtJ`NA7`[8Mkt5T5hqeAf:tkTP[K_,GE%5A'jM>h3J@h%WG5oVsbDHOr5V9V+Kq?iY7-:EQ)8fAS<\s3WlBPJO7O]$o@#L@.bC&hDoW<#!.8j.<deSSBIlfMlFMSV$)=XP]6_r([V2O\ddm C27IL+'0ifqoH"?/,Ji$R`$!_tN4=Z\^BU&!(PKnsrC8W$*hPSh!JZ?:j5e%A/YVOL?[po`CD(-at 4c#FcK-NZ'E.V7+pq,(3OrT$8%E>e37o57[BeTJDYASSD!^;%ob5K)46%67J"l.We*2nFE_+Q[#2o]h7@AKg6QCZO@rFNT=M=,"'fF2inBMKam-B85$AT6$0ARI,"ndV*_nl7"/@ATWWGg:k39m(>t.AWg&?f"3>/Rp/ahL3dtB `2/$5?1bYrhmJLfcMKte`@/n ;s\PnT/el`laD&EK"5+(3,l*jjPWJe(E7Ikt9cJ0%Fc@mm4c3s^AaaV6B,<-O/m`>G+(.&:#aZ#9-4LM," NefR'XeH@nc1AJ?![jD]Ct+iFl[%%TUY_'I:%<*,/&hC@cWUg-2(9>91LXW^WRb6Z1Mpp$-:l[ DQi0AoqIoO`]b[G"Vn:+jA;%kO0-<5Bag=g_$P\tZ\Ufl!4Cii ;QkA\1%*dY(s(sSHDMq=oX*gK?G>A!kST(H.)`!NNb&A>'kY/-)&n'UKd',g+4$qNIQOCHPYBJ7!80Lrt;"M=>5X5G$;DHMNYQrdj!jJjQt1Y!DI?Bq)ZRZH>nCk\c44PAC4^5PLIc\g.285(6$?(c/!0j8:NCC0RiF*k?AT^qQatHh0"d(C1H4W8P>>B:\"^Ui?A\d(YB mOnh*JlA 'VqmWe\0q4-=QqaMbKSI45>A,Z>_#qfRJ#[:c^r\S2+6le^O/TCPFI>HZ8=/G-548sSdom(J?C3[$25 @:Oh<;JJA6)#$H'B+`06\Pr)o%;\`#+FA@:D7CMl8."5'AU5Y0UCNL](BA2b`2 $pHjf\&jS4<0!`nLbYrA eMZnU`,o#Q.[: )3-IZ>^(MUp29?DC.a!)r7#h^d,;D1-coAB:U;=))#Ng!GP/>"]q>9M(1`FW0a#Wr$7"cB$>#E 'eDCTt]3.FS0roi2q]J'B(JtbZp-es2]((SleEpVd4,B@X`=n,LT_b+/I;b?K )<6CS7;lA/*qA"_;J:1O=mrAgeP&JekLD(Z$ffEi5O(E79KWOfd]SG@7@\\NM$^nV_B/US&U7s"kM%G'"K!&?gb:%Kb82?&'"*Dt^bXt>k9E'h,Bl94+.Ns=el@F/FC\1-sA37Aa&<4p,BO5>LLD/c2N@01M\pDte )*nCBEAN]bo):3V r8BdgCl Jq6TUiF[>CJND$=UnJftI5^ApC))lfM#&RX*lFnJ'h5c@/WQ14=GCl'6o=;No2"C"JI/TgW7SViQ/(cjX>M[@.K8?RN([-2HrgS4B.@A^?AP2??N`")AN+U<@;BRAOX5=9<)\F/B!sid \]R4qV(INR$/o\*\m(_8eC3ki.QkkFlPkVSK2?HWAXqMY5*L<Q+V:HU=/[P#l*TEt!fUf5..0q/;ANor()L]\1ZR9YZ!^qaJt4dWt$AoGk?B/@jn?;1LDiLXq:qX8Ip`ciQ>87TOE`ko<3Dr-QBPV >cE<1T([B4^_CgZ,4LZf!bt)t9iVR(1kWXpj3-rrq(aG_SZM&O=-2QU37V@gQn@Sn,/!HqiO-gccspXsa1$%e, ?Vf'5=@/e_,ItO*U2`3mYcqB^eZ+#Adk'>A;.&2osb[=ZEO@^U#:ifJ<;GgZB^o!>D5Gc^/Hq9XH$KVb=A?c%DI294lh+]p[^cDj?&J/CH>p>,l/_1E#i?-YZ-)._(QrZnSc5?KekMbBPs;]SmRbJ=(P-?I!AedL*C@,$dqDm%P&*/*( g*qmb%q!nn8.hs\;nt!UUlXRVsAQAE*#qaO#Y%E)r"LKQNJ@dW"EfX)+\Xf=5.TH3/>dJ?9W tU9s#&CHsFT =c`3DHLNJLkA1cJ"D>aQJh%Z+I=h^rE>d1VW7'aH]]JG6I0YGaA\I4_.$q\b$R:pKB;n)m>%K/0l9LG^(bW1$qiQ\NbYONAA%c. ;:PFQ++0-E5P^s=7^MP8$)rr47`":&$='>ihiFb/>A^7^3UO39<>#]l6N[%B8M$t2jP@%RBeVOYO0l]pOnrFAN&oO:7o Ts,gtoYh7:\1!Bh9)!XOeCHYE%9C8pB10HZh'L-a0$c3AS=r^a67gCNkVht<`c_]f>R4ZAitLW!L;og%CIJ*^T9RsA,q1:c#X`UI`K>kJdN]*A"qD#1.Ua/!FE7e?JEj EGALbU2cdRpPf&=$do/?2),R]p 2D(HtnNsNp-J+k0V;gb6l2;k$e5o:JBCXFf.S)SHs:C/![2kk ,cjJ Kr2,Qt@$$t:-qhO"bnT3e>GFo`K+PbNMO;Rh:fKEF b^T7a@'oJ+a>"^V2Zk)@J`@N^pmAq%QWQN+!+M+bt90mtZE0 `g%qYf,qqqpKg+tr6`aA;Of*\RbV#Frr=&+-pqWsEFAZ/&ToT/sW&kO_7Lt4FL-UA:phLq#DbcirKJ;:J!iUhKdJk`Iq?!8S=dGd(kA8d;klrp4J+:88cXMP*\1)m=,E9k=hd6*I*90X90`?JA1dXAYfX!D16fdaBiI2gA'(;n"cBp4P\XCih-r#GAN3R<%V0<q2I2WtQn8%:*V2D!F@KPQf[A1`^V*qr7U(D%1C0t hd!_.2J4'jr-]MrGV+bo'"EoM:^a3rR^#fm*eQ'T$gA/d'Jp>5c)Ad)p-E(Kqk78CE#O'\:KZ.$GT^d*>)K3MQq&G=R]"2OGEqP%;BH#9<f.r!D^/1tj[ik8tIpRlXq@#7H8R3rJB;AKNR;68#k&"1O)^$.PB0(p]pN$R2i1>-%+i4*lhab2R3M5=b(`WeqJPG@;KkT,dQe)M*WF>&D_N*ib@0E#,[WS(Ne3YPtT -;'m-BQ,jbp'eo[pBjAF>f#h2b+qRd>%^++bN`P]?CNq2Ks$^/XnGO3@G&rEp\_&AX7XH,7!gr@**7'BiS)pERcqFmntb5'[=Z"c/#p:(E@_eZC:p?kPH=o:1p@3)J$\A]q'*C]G*9fa`jeSZgj2laCfVS/+Rgf9=%S_KB[8,l[@`lR"B[o4mBA-dY!UM%Q2c=13AZZ[6fc1["[9g\"=Uq5Dl@d4n^K:'982?V909L0= Y\5AlX1V6$1m'%]"ERYJPnT)Gl#/Fc<]k`/U.[4;cR[b)j#q4q0Qpc=c$eAr-5V+n8(\DNtiJhPis3:@<.F:[`KrKL8W\i,[1].b((pCjbj%LDh0?H$2Z*)J+*Lc`jQZI`Na.k>`PhQHNn2A=OJ@cppcMK00LPg"L@-WWZ5KE#s_ldV&Mtf)3DBA%!#?1I@"`-^E^=!X]4AVDEQT#%;70kd_4V"dKX!j^/UfH'O@[*IHC(b]AZ$ZhLM/X!0/Q]Hj*V%k0mI(Y8$XOn\.qIn5/e)B"I]#/Da6V\'O]QkN_G)[I=8'Y(Z_.RqXB/)[MIAq#n& +nm qtG6g<`OU\iKY/dQE6D5kNJV[rJ=8[(S8T$Ig4eIP_Ff),`&Lp!cC phI)oG57]I6PZ7ciGAcfh87BP]!`AMF;<5TcIYXOemL8En[ag"!hb]T(1\M&7[4C]n<>X,.(bE"Z=([5+>& rentPm#3'4/>U[ mc^#Z6rV*\t$LgGp3$:*IG-1.25FGebgA4U&coE".Ab+j-&ZR+E*e!p)qS>1]'bT-)RC+6/A&ZKX'T\CV2Qr3`E]]iQn[h5&5Ma$"*M*)bf"rb 1=p'I[c>VGXD4BO&O<7Y;W=qbng1bNU[-"<38PdXNhN941Oe,:'opR3b^,0YF\\+f07p3"0lXp,tKtrIL.0e^*.pf'00aE$R#8W]O?4=0QB3LUr?mkX7B(m;)co6E'"<1lQtfQ@5mR0YR*`FFYID+'S0K,Z(nal4ssG[7IS%s^48pi2B,8 (A)KiNFLc6m=&O)5j2 ld*[8=I!/f h4\G#i>h?@8P#VEE76!^E)V!l$DeRMMriK1&8NgVG;f,X^bfZ8;N4$nqP]C^A\%?AmO '$aWQLR^Va,+Zq/p@aiWi?>N[Z"2S+^e]cMRH;7DWNFR1OOaj4sQ^l*]XC`tZV8T>FWeS8N`'`ZmSGbb2eSFN!\>bDh=Mg:S!ks4EOLh&T0[*TN_`kpiT1=?:k_k;Q0I]3Nl])gbh8Qe[+!k4U1g]>XHKo9tgI1bb V:/`FVt5e&D/pg:(d.@+Ti`LPWE+W&/"YVOO`C4kk nOkoUl jY0"< %J9d,%lsY,a]+`A!Qd$WR\n:0DE(XF nG9G?GMXFO9&eBQcA$Ma3]LQ5RBX""7_De@DAoZQNAZJegBWjA36hDcEt.OXm8d*gd_-#0fc(:9*/ N2F9AGikh9'/sc_ISAj:h"s3Lk_'a=a`^3(<`BbZOk["B^_Z[[/,eq4;LT:oHXk;r5;lA( n@cjgaLC2[i)rKZ;OI:EhCnER4k#)1Yoa,+EQ$i6)dSr%2Ba.i3: Z6SA($a!gl$/nC6>X0EE_a72CE`nHL"`ZGU_5SWAA?W! (WXtM9Wj$I8P'8dij.S0aU*$(MBK HLH6'U[tq#JP7->J=na1WgXIWFkjdW;1Y/sUn#bTMqen^`7bA>(^c[!Kn[f7p8AYb(N2%5\FG-L0^5"qMVFfaV;sBVm9oiEHgj8H#OYoUjZMNTL]MqdZ!s]cpa;;lN)0USZ0k+_G!MnioBE=e0hs3r-CTIilr>3q]9?JfI)sNDPA#dp;\3rFdLnA@Vlgp74%r7>Cgf\N4eLYHU?3*\67rK]pP cW23D84fAQO=2,.p#g4RL\<&QdV ^;qPsYans`GF=XZhl-GE%EW5^K=(+(V=OtTqc&:bh48P[RUX/.YKGC]^DA<><6b=Gh2Dq04>^*V370c+O5F&r,CEhV5fK)nMfG)Sr8`i/9K-7fO=b@T+\J+7EJ@6klM`Q4^Yf+e^kXIrNXAGn;/:SJYhcqAr=0shWAs',%1sM.3OZQcJeJI`fO4RV]9g$#h">h=C.AR^)4e&Q&K5,iZ-B(t$:NFV#FF8tY^GHO5n1q#PIMZ_0JrgF[%\I7R\CK5A:-rc-P6fFm:TGqbU_rjs$q+O(I4So>0[ApW!qQ5IQnZ5GHgr=EL-H20@6Bk(AV$0UUF_#f9(6#g":j!Vsn&pX)b477Sif2mg^V1$*D#_.DY@_CmmU-8`$i1,h6^8U.(EtH9<m]5og)eJ!bbP[b!QGEpJkP@:bmPkCONM-(-`U]cXU]gC"%Mj,@f%/]*q*9;UYd9!)=Ne'4Z7rtB]b9pj"dpVkMkA4d>@k<(tQjjl"\gQa7PArYdrTe6r=Fe=T9cYL&@LU6=r5r]hD:o42!1ARde,?dMrkU;`BbNYcA"=KM)hRQ`r\hoQOAA37TNtXr^(6q9@=N9)j6I!8CJJl!pg-_M;tMdSa2sD)B&*c8t/dY0;+=;j)*-03I1n 2I7F1jpOc(ocb%%L/XUj\s$EE2[!<;]8k#])^N+AlXfNZ6/jO^Z2^!R,"s'd:k<[[^ig6Z6W<#(\l5m0+^GHLN:tD`4,k,D:V*HTp8)O_K7DO[>f!AM&]rN'< MOn)D"o@mK?jmgi%FltcD*0.@,-H(e6!!F<5Oa!Q)A4OHKi=2=NDBR6@jDrV&Wj.p`!VSUb0Gh8*Zjh-X[3(Gg3Nl0:'`YMLhApqnB0#aJC$$_67?8k]:lA:+pqsqs/Mm4jBpTGGsKA8RH@k$)kJI<+c^HbkSX0%Q6i%m;?7J(<X\V\G.lX)qP]=#7?7HPMQA>D&q+P0N@9)JKEX!8dCA0b"8TbCZ-4C%L?#,4$UAo`9IPt"K`Sf`b$7?,ne4fS';ok_3l4HIS+7H,JV(5[NqX4TO0KdO_&'"*ZKDtK30&f;;*"3p#]t1@ZYl82b^sjLL,;P)$tJC='b,pm1Cm1CoL1(]URj,HA?_J9;VST47LXYmIq.O^,!54Q4RIsp6QWdbW9CZ0g-5J;Z1i^4bRIk96r.nI.jUBUtc^I![At*:&UE(KjS(/ Jd]I,aAkEn]?QaL!&MV:b0tVF\$_(fq__Uo3W'>*p+6%E,[*>T5hJR^FkJ*$#43+VhrK&&p"?K%S'r";pKQ_1qb8JL_:#Np5>I_Oh%>m3;' $kA]i&P3A)7WUXm*#ZnF7kU 1WcU4+/c,^ -0gAri,BK K=cYV*G9sXa#/#<iK-Y]`m` ^jW GtqIn+LA4/bkSW.9MZ)ZRbNBKV_LN\>$DohPie]e3?rjWX GP.8#A2O5-\7"C,KPlP5Y&U2[KlMQo25q.3EZ/#]X2UYU:gAI"E4Yd2`IY%O<$ptj+Y5]LR'G?P^mRdRd'qh/>A?Dch4Ys!%UG'FYh>6K5g'Wo]c.oGTbGS-?^eAW\3VOP=+T)_WecM?5/9/6e//Jf,$7((V@0/%O_k?8A&H!C(gZA$\lIS=bt.=ZY@%!*`3#1(<:>NNP_$?-H;O/FPOsqr#q?B!C3%4*:JXFlF#cLCIjr`AG:B!d'B:ai=HEr&4cICiI=dGf.F'X;M6n5/S8'LkO6,6SRf"?UQJ 8,8[=tiC(UO]J/AYl0_?+#]rgkV$$.dI 7HGbO;WJ8I^^/ZW:jj+m+ZRir%>jmWXkmbC"Z$[TT\)Y[%)L_O+>NLsS-^\Kr>eStgZ#G A:R:mQ9l024Xb[V]M'lGW-%sjY%:s+b?o?Oqid&TFsJ@HLOL+=1SP31P hSX@eR@61(H7f\W"`mdPf:JlLE\%sVboqP4m\Nq-1j^;jA3521f9X,Aj8 h61c=0G480E30bdNHdj&m!Dp.4OQXj#aaF!H!=VO5-2R)NsdM]o;)bs d/2NC8_'%hG"68'4CP22i5 ID*8>Kok0XF^'mPq6em/"*-0SQU`KfTbIF."oVADl9.i?JbIjp!>4;qd>\/mJ%tM9S^(IBK8CF!'a:/*2^=R&TVHG1AoIgh$;4MMC.sTZ18b@_Zo#F^a'lH%VkRFeh2WYgs>2'$]7o 4)V)"jRBN-OqbfGi5`bUbEG^cc4TB*.I,M<9sX"\hpBYZHZU&@Mp`(t:oi*W:4eUk:j=1q ,E77#5=+>#V]iiI`,A,]$+;aTN]qO^elX5gd1_cZJ&FRjfe50o5YP2'/3.:tN)GPGsWD^3FHn<Po<9t.kFBFP/9mJBM`>qf7Y)jBEs,'lX0J\@FpCNkj$?;b53k3K,1&Op =ktW98o6go'DlS/q$]6qIlD'XPAPmF+52*KkbNsoh;Et'l?WA^MS,cWZp(t5!bSfAhfY-_Q]XtfE,'-9JKs'SPbdC1h*.2MmDb#CcO5ZK4qR hc$;0*<<]G<3F)bo 'As'2@+[.Oi&<\UAp2/fMeA.>A6/$Z"R/ENAd47X+n*=b4Q+FRK00@a(!! leYn1B)b%]n7>`@,nF9q4>7"BE9fLGLt1!X3%,!\R5KBn;AUtn2@2m,"#sBAj`+n(HN2KR7c2Q/&9'N ^XS:_/A'igE2AjG,k@@A^R,I/t:L?DO'U2Prl1NJqr_k&80fZcK>Og<s-&1HYFbg8i:+=@8TC6GL^"HdhZa@D$#-BtK;.,Vo(!keiM:(oDc,3m`!eK8`/jha2Z&Ch5ohpX1bFM8KJ(4*T_*g;DQ#N/SH*GBlsjtIsQ(*>'6c3$J];t3h6CH,g2P/MT7r?t,TKRN9\;OM3RbVC0bhSX_6F5R-M# Tg!EoD%SYW*1Qb)JLI/!MfTZ5""s:8Fmr0*Tp7P$FXqJ#%`#=_Hi91XEeFU(m9+m2hA%ZW4E[?l`=:QW"mdF>Ps03m<9`7jB""<4<6$-`bCsKjMAMPCG2W BC?^;O17GSDg1l'"Pmojqq0\C^,I_\).2+#%I?.kI##'n*@PSh /o:lPp2Z4b7o0EQ'c7%>Xme8V0/+A[A-_n\L\l)=Lt!%c70O[C(7qZ&Xk_@jh'DphP/i7p^g2br/7boPXRH[Eo?l];bY6T&LrD@4Zb mjUf9>\b\PdtDQ :AG\H91r>R(6g6qAb$7DXRdjt&#mdFFjNoXE&]0FU;,LKf.2lK`7In."M0#RCDI4:C;p):5PNIKrL3?oqj=BUQ3;4 AVCAC&1nibS^kES7a0kLA50\3((0f?85.QdN-/k:in<)tFMAkQnN#Aid/G'-+((:Pf*)lh20R&gpeI7U\Yl2k#r3OD%VKs\#i>oggj6J8"N-QlI4:t=+raJWD%Fj [k"AM^O5frFf[K$SI?eH2b,*H<YJZnt5(@Ir6VDUKnPh:9lsHAn C4]AD&Q`"lqil1BAIW+FfiQ[K]K="X'dM&Nb)L*R!A?Yq1C'gS(Y0#U'52,4&f5$">_FN4iT_2W5`Dk;&ib\_qM+VUPX*#<Ftd(f`XXa]BO';.a61BGK(DaU7XWs^d* f)=8R\0C01IdA(>_o:LX2c1!mBV<4l/QA=!gg5c!dX"1f/cJ1P((2,_LkH?hi77HZ0I=A:fO?4 ;$FnW3F6sg?Oof1g'GCA$&]Y)..5U76;%d!Qn+-kp0BTl'km"!0[bL%2]?d_Br;oa(Z>qta.#5A& 7P;BhDR&rW^c(N?H$ZG&eE-b0]m"^:$D&m5aAeh=a_.]970#lT,`a5A]BVThe@Uk)_8 ZpR+H-.YTY3;1>![%_HdMoDPG"s;(hh?NRqHZt"eroGFR9`2OY#VA1#2g>Fn`]<sQ]!,Mh1Z'3Gofp(K(sF(?BUJCHa)%'=L?7gb07T-&X:'n"3`8jh8kaK,]9IG6\/(`5fS$U%Y(qmE"h Vi40&3B5$.\'V/S^Mh$\P#,Z%43m%R()7^iP$oVJV[p@6-t)n&\87=]I^1L\7Xm$T9cp,j7KZNa<98DU:iHc [F!naeI4_E3A15X=K/?&%%JQWN=Hd/_DN];2 a2d0B4+h6($ 2kUAp^im/nP ZYNj/+7+E>\t@9r<sP'k&JX9 h2^2QD0/;go?MKAsS(<&3AQ7?MN=Y(hX9#bLReJ6M*/8L>="H34g#/NK>Ad1 \CmZ'F^F6E`PKDjC)efPUQ&-XD]o?Eo%(9,N3NA#Z[P\rhcrL<84n RsP^.b+KZHk#;\'XYg'knHL3 gJ#doTCiI%XZ@alWl]r/9b_7@0q/TIMA%=L2AbG,3a)lo?H(]!$t&k?)a?b;gpK@tF:H)I5+29Z@Fa8^58D%0DO%(5564 (&RH(!OdYt9-C=.ZJMsfhMR%ZFUc(Y\\5P!gcVp^+5)\]*)N .1<"i-71jr$AY7p7"9T),c)=`S)N*B6:L0U*aW-HDXfsXVf&a<(l/tsMn`;`[l=;f&rbgcDP19ZEZA`M6]Dis-MCIcAO6c+p_Cjkirb!a@hLMC@MqCs2O`]B#rob8S>_U5OXA3pr&39^o:+e9hi 'I3"4N@\J7Xa=lJE3f( #c!T]m0R%].V"YU.*=4nA:rY`)W`4sGkr.ZjqmcYC0gq\QpDs/%Qp5h1>ZaEk$iG4ddArO`raj:VV 0a9Co?8!$SI/:Y'1@hY75]?Ff'^? QFb4lTA.f$Yl90*85i)JDM)1n "UeV\ZcL6WMYrcW7"8A=OK YqMAG+\;q"$Q$C'>(S56?>3A2UgAC#$.EH]?mL2VM;j1kO[A__NaH)etB4AY.nDt0PlpQqVNA`@O>JJG]5joI]sKc[gAJ3GibCf`aceB6$AQO@=hcmn[:%9WVS$?\24 o>I^]qF01Sc18 KGW9[F]`I"A$rA]$6Q?OnpSHiaO5_q'XZfnP:UNHje<=W9eXhr+2qdXobd8)-FRk2OK?\GHPXt\?Wk`3n?d%5iZZ.fCG#MDi_2N&OObPNm(' SW:B8jX`%fFdY+_'f#)B?:*J8sbf$D8f.?<&Hh-37eQOA$E [(Z6"/H`*"%I??Gn<X&q5,@D!$gSMs/ :*&%b7,-&<;A"Bs3CMP]<&$r=Mrl^`$Gg"Pm/521-C>ldl[&$aZ-6gmUAESdC"t`86-WGc'm0cgT?0g.!InTDh,_;?C7!-SC-B f9t$\^.0oSHA94BgE+A2)Ca^"&sN4aY-`fF_N`'8''4mTaq[2kH70 i+EJh<,N:0<@Z`dsBKA/E:$];\j-9O5#`\Y6.'F4+AAI*L >.+Aa"smg1e-;U%U)M/>o^#f3*la>+ E/j!4FcZM(9RbWR0'hE\*-A68[F_G?dIbeH!+cS<,-m6L^8Ffa)]!9>E;kkaW%rds,W+a6mDnhJ2E?DU'f0OBb[Oo&>"-\P2'Rc!Ls I0cE'nArkdfYsfo_`.74[rF` Hi:9a(?&:SprMXm4Z#nC>I4SZ3Zoq3E3207!e`N7pL]?ALII%EcE)UcAsE.W2Hp;H9f.6+, ghLDk,_;h T&AP("mHq/_[9kfk(L0+c_kI+X[b[n.99_:>$f.%.56=4%s9A%%'/"LZ^Q)EZe,i%eJmpGE?Ys+0$FUa@=fjAQl!/Q.CH2_%2AX^<_Y:3SJ]rcrXA$dP).gd([HQlTq=]p7/]!LO9*@=ca0/Z3@0FIMFf_siXZa@9.G&^+ C Fsf!VNRTJV4"sdYt1e`A8fG#/1shHkP&:Bo8g,r^['#Tg?tFsP%J''$2>C)+>P`r)'DP&/J95^P fLEpi4=G3)34qS:,XGEEiEqS$Qj^Zdh7D/7C"8KP&(1=We3^kEtL4TbtU?mk;.VSrCA$8d\08>K*hJib__TmH4e!?G5SN_49jl!&VAO^s"^ PQKL%5)aA [@#,S0O&p]=6,mKq=J,mAB.<#*(_eS ii#NK#p\H>Co*SBDXiV`"%;o^=4VaGiDdCsB$H@\[ FiZ.iALhM>=p0R8UoC&CRV_OUDI5@4>iJ,%'G=Skgt#hMR6H)Ka=91GU[ao9UJH0Ym]S:ZY!d,-1$1"ae].!Ao&h-`/L"ej3YYI.Ge(Qce.Gn*QrSaX7WtSP`PKoVMA;KN3/?YreI$!KB'/mi/ h^$W2`BjDB@9p_JIrqFTq22\`WQH:;")70d"di`KBZOp"<:%U6/-@@T@:KiYlANXit!UJGtk(.t]$C#o+k;:WA&DgiP+TR1r[W2n=KD.9,<_F>i6`85t/+(]s:7J?78q*>>7Q' (Gta[p"f`;AAsNQntj[<HcSFF"iT%Z,P]j/G4lXD3O,ABJ\L3N%PT8_[='i+QhC8A \.X9$Krtr0WPSG`"p8 tU'AJ#e([Gq21Or[em.EB,"-r'+:\t:ZmBb*&( kpA!:63RTsJLbATN`//D$WXRI7,UIpoJ+jDc`<1tVGpW$Pcr#OHRPs6hbZSTU=mkPVLAhL]>@*^q:UJ,G"`'&/)?BB3]4c1p%P,_% +/?^@oPQ1?7o+ppq"@$J+cK4!GY">?J1'-1fA_lNn/[rmG1,_j4oq62Y?^9Q11P0E5'0'3J+tnBlP^]e"0kN3Ekc1WonI9-qsMs@b-.'/AACX:FY190e GgVY!hZ+ Aa7V`Z_k0E865">AW=1Dk^,,nadpT?l,%$1UUUqnh51&M:W,(UFc8Knc0ULMJ`f8h]Pb>T*i_Y$RHG5hsO 7bb gM/A5A'5 5,*;5S82DX%QmA5fgNi/1&P;q]dsNU41[#D2D^Z:M&[;0>b\:7jR*e* _H;m;@09TTsFcjAt-$H?DmP*]l<i`33Lth-ObZ#[_K:E1oBKA\U%ZRW/$HD3JrZ$M-%5!t<7.Z0]pM.75r+4gI;5rS?sXMr`\0Dms:P]2@-S@b7hF\ N\EOW*Djph-em`ak,Re(UkHPWM1`S@_8=pfcP8ZF.\sl9LfGbh6r!*fU Y@Hf?VDaNQ=><7L_aC4oAT*BE50p%_nI),^WUrm>77Ah65?7lQMn<"4@nc]oi3t-A5qp*BD@e'&XCij9#C.FZ6\dt?YRb+^2EJtNkB#o$)'-j*T;Y!\55BHQ"*"fMtP2[jgYr:N!ncG>:B^p=+AK+8_oOY8Gd/%R9]$3`o'aKE34?h>E9q%iIQM-+L46?T]4U7`fUoR!'Wekf._+*ED9<%CIS:^tD+/dd>0^3NWop?Inj>Nj[%&qpVWQ<<'dAhmO\pAECmd2l&?2 mDI:dVSc!3[Z`'!%dlD@8pAKZ8!mkb^^kWP[l.[7\C)Ut\hHaj,H;QPBdpohH]fdK?O.A,EX'5g-6 ZS?]! 3rTg@NE1_r9>p K>[;D9OjYkX&b1g4#fGP? @VHt"HUY@2Iso4nIZM6TA]&Uc]!nEHLj2[@dUd"(f(l!VOgneeni],`S)L:dL!&h2`!,$F,=5MZA4(5*0m%#/'iQY 7D&mN=2VB,19(_Rq]Df+Y!\=HGTK:1J?rkOLae^5`JbE9dah/X,k\]:A2h.Gginn.j+Mb>EXl)Xsb[NNF"Bltp.U=0mq?THM0*nHSblADA&aHj#s#Tf13Jt4@!6NKoK(d5.TLh)9Zneh4)7i=N;Ns?BA5kc"=Hc7gUeX 9spSSBdPO(,JX%a]"Z_fAJ!:"Ds9frG$$lIrib./&@O%f(/`P6E`3T@e?Tgo]rbc*+5IM:H8"GN"j"Ti#37eB@"h44>+B"gCU)eXFRsTHp[V/&a QO:W<^A$_:tU[/0"2>T,YTRNY Sn_@0#m\3"cqBtQXY'?Ial2BW6nhIA\cUc=c B^!d^W9^_-2_/qD&1#nst7C-&W03D>ah.%AU2(Je.AB.e#GZFFZRP_GPM#E dNaY 0VP1D8d.hL-%'UnXRtLI@YE"@q"QSJ5*.1Z&LKison[,3VDs[^MEaS]Sn[35_.]M@DNso)?sOc94@$QJ&533m.$k%T[B?%5:!;D95dCAt"f8(M/,$_8@4Ng[TBACtPE600l;0IMBA`e;JD.6+d_!,C7X[3Ap5S+JkPT-T>@p*HfGgC8G8l$Gt&;j qFHG47U5rP;'A(8RiEp@-"gq85#djA?-M8U8l`BjW*7"o#3'\$dI"Da38TRHP=P=b^Wq0LaaA]%K'8YkcHJZ0>RVokpZ#)k4 $Ta( E*Tc`dt_L%h2PhE.5Al1Qj%)HdAUd@.S4R8'+U'p172,a1$&m'*N+8iMb:A&]JN+-=Ad,"N$NbM?d9GjD's27\E<@s&bG1?me7&qFJjE?g)-^fUf(SoF1K_\W!jN@`lf3h*-Ud%8Ua!AkXGOL%U]+4Ol'!5J)M_!`X0/T1,N^(.SC77FpSiE_rZ^N*g5Ul:XIks/gDdZs70+kKtZ/sdg(l6mE"akc.1'.6) OI%Xoka[%<;iI!q<$n0[X\X)sJ>:.4trHQF,< =UMci)!lr1H'8bAc_m\8W7C0[fP`^sZU0W?$$.%XAB5G<%JTq#0L7OC#F"3Lb#eC?XB6:[2%PM;S+e6!8p[lA*QK7Ci6E)FZNRk'42FmIK"7$A NL!DG0!ih`'L'-@jH*PF0+^e$4336K>LoV!'YRt+!IpKM5o7&]JRKrL qaLj\W`;_NT >)t?;[?')A\^oa518(VaT5ifW7i2_DFA=.XE-R%Y+TWiZAQ_**DS@<6]AtYN3qs=;"t+ni@$pS;*K)6BAta'lcX6kMF2Z:H:].7)+*EOFhSH4S;R7:QU`N>c.S9B*o6^F01lSo\/NX3nd:7>9Nn0! 1Jm7c8X$<5`jQ9,r;qNsognA[a*D2sp5:JlS@D QI+phUn!m(;kKD,2k+b`Wh\M3+1TY(, mAs;!2;NTN.U^ /L2%D^'L[QT2Q[;4OJqK]Ck7E[o2IM7CXBLW*m1?#s$* H"MR[3R:[/.gC\[T!`2h0oWM]*&K)&Z,Kh(JB1&.eHq!N[M[AA$"Ee"IC1\:j7:DPn/h):XZM\OPG)o],.9]NghLT$DA#5Cl+I# V%t[!l9GmT;)8AOiFEXoL^(2'AVZMN#>0;9L?,JF(gifpJ_*pOHQ3o0:dC>aAU=kJnrVq_:;m5r9BJ5Y)df/`3nlE-6e:^i!!7@!b&&cK24pdA]mdr(%hi@YfJD1YJZ(Ddrj08G:J$iR%o\o@4aVPjB0h59$ek;]W)hK1B1-(^=.gD^<1Hgl8LmF9M*e:B5`Zf9!)IH%8(l +VXME\Bb>IRe8JEQ) XNm9A8j5.Doi^+%c&l;N$LXq4]U/fkm$0$;r.q7aX3)I\b[`RhVg\&@]Q.n/>g 70`Ugc7pRQ*LplB&QOro5!!g@8HMZB7@,8RtoC01JED6o5:l_/e'Q(7hal>EiWOh)`KnQh+h?5r912!?'r5'b+(Y,[Q'#='!H\( _`CBR/d;`6AUDN:%d)@n`Ag[,#mPGYWrZ]7?(NRG'Cl9$oCS@^WW8fL#po4`[U7&;&#MQ4l9T.Pr902kA!LQCkkb39/GjZkTm)8VkLZHmj5%UJ#G2ngHtb([`WTN$Q+33HbF]qfKqUmRZ3H$m9l6*G06>+h g^`NWdnW*Cg4kkkteOf*aOTRrN-:\e#%2m^87^1[J9T\#&ASQI9[O6gha2]jqa Id?:@^8]ANc>@*G&.(W!%J0?U\FJIrV&_CKVR))Gs@H=0I4f]-MhcM';9"l;L>dm-)P9fUJU@G*`SE?AVGn>AkA >Ce`Q_-Y`I@AZtkJq!oD\aIZ5H(X;g<O5U]Z\hpOjksfb aKpH>9K2fds^;SA%_J"Eo*"F+F41H,KleCP717"L69Z%5(Ah*j%:q?HH.maa@to2VqoQIm!5CoXk&"Akk>%/['&bP\X']n-A.)q$1OA_9C4AqpW%f`U-PrC< M %6DqGB\_bYLtdAd)L$+4'd+6K/.:ANU.5nk<5$9fSM+,PIESS]a'Fn"=*qg5PO-=bCW7EhL6/1.=hgF.JkE_GPMLs7/2WhW#ZYGLY\Y 'UTr;M7Z[\e:JIEAEjr nisP*ZAD%%X5bLSMC`_0Vg>hbD]l@8Wj,;CX(K&3XT%tFR<>F)'q*#R[bcS7Rke'E>_6IV[g83]4@QT,&,. ^7K>nL=N'[,Ka`2s4gerT?c1>+%+T9E6_""$NjT-]_A:C,\O!N)oLJN+cIh>7M9P;I8f7L:FJ`h[$88Z#".tae"1(Kk12CWL:mUi@[/R^6[Fl?`m89[Q'7MIKRtbVtq?jZOWADLb)5LfY9NDQlo[I'jbtm>1#s;n'F)J\B&X$T!9sH@4@gBL"KZZ3lpNV*pm%E,i]i5PQY]K[8M8A02L]4.P_8!6oBbT1e4U9s+LmG9BX1a1SoTJ!RArs-M+4oHkM kmbd?dm^IE$`>fCid0I^j_FA6VAr11+Grl$h=>6ptU>V.D$-Go<;AF@[>3j)B^`8scNE>>Mn-B>,d"H6>3]6_[`pbI Tli@StiR;]&^BmL(.O&ll 7T:H4n21BRe?`b,Y9@G=BC`3%/f8^#S]K,AJ]Cd>%tA?@JhO+3jjb6mg.[lFKH_N54JI^7n+.R9()PAAj',,kea\.,*heik"i@KE_Wd,=KmhG]")2:_[JOp,G[C]tGs-d=!_7L_pb\'kZf$1I'2"0NlS5XXH\hW0+tL6tIa8gWqDQa6SWil*jk4V31KfU#h!L-(2kYC=6RZSMKj.M&W44@Wikh*,8+A/k=b8h5/*O^Ei T.X=b?\bmFe4p =Y\%/5Ad:(39>AWP#ASmINmgl"gP8&^icBi;B?3,qR,UdC*COaV^0r9^j'J/g1'^k gr`W+8\reRBgta9P,Tao#^njl!.aR"nT:YQMp[+;sLi9m?"h, J.7VpH.?LB&'75J%9JoR&iS@9[rK=UldXCCraQCD_O("f>ahCTF/-Pq,e*QC7HO%sAF9-@XEV5QAft?fZ+]j6If9?D/*Xq,>H]8qjGaZ,4coEai+qPAnrsoL5!OCPl#OQ2Qj9SNTT5r=@-ghrL#+Z?)f9Cn\^+VT4['%"0Apm \ajn%s;She/E2cGUe6S7HifFtC\C'f$Drqhgn6BknpXP`&%lOi=t-aD\j.X/SAW)7AIZG&UWi_(%A! I9pLp8hgsS>;Q;rV5oG9dLDI1=[E9K19`__]/68q4[nWZ+J3Y0X Xop\8bDX.*#el,[HVfpa#`@JL-`dp)[Tk#.:sZG[J>9P$:LU$DZ--9Sk;"PMja,,b+r*i@qMY*07mWpi@@c*@ G'%setr`Oo i$*<)K6UY/`X\3./4W,cg])P.^>ENU4ZbY,p08=b9KW;06emM0r2D]rk7*eq>]UYAQC)68bl4>opCE\@Cia?Yjh'DNB5e!*%JLf=/:.eGj+P4?DC_Om=IFNsJ`Q,R`E9*te+:d6sR8O$k?=rhKA_+]7Z]$]6aNKc[mmE,:FtHn"Z[SU`r.E6a;'n` .6L1QO(!JhXaMIO@+Qsq)'+DD-5?B4d$!Oqb!;,%/c=+I5tW,Oj<^a?%TD:r%f_9U]1t5js[JC>f&O_cV"rIgiJs^,mD?g(;(_GAV)i\M)[#kW''Ur!O*kP57AnnHY7[47,R[&9SbcXW*BVr;=mr8+_U,nUr0I_r^@ br^=pAgHqka3BEOph67]1U#"j3567IZTC*`oGdO21Q3l/V:m7$KdVE;bV28[Z#G.F^&cISNhZ82.emT>oY/^rs.//X=<$%]BB"528)tTn4ETK _5C_IZm;"&."APR@,;=JGk6"o.[?<%Tq4S+9WO,Y:aB#0JLjW0#Sm(\nr`o/sP3Ql%&%j&<>doic^smX8+27 '4\1M h_0q6)99eo^tAm^GH!C'QF`e5r:ns#*bFm7-:1 ](B`E2trob<6e`^FeI\XUA9kMIt0'M5)T_IoX5pN`2C*E#\2AcR-Nsd+ pqo5=;0JsKDQh+'kN'%;"o%:ChHIN$R(KD5)A7Jc[eHBs'!C1>3m(-fGVYj$ZiX/Q7HArA'Mn;8r.W]i6m8/f,>4>XB@MJ!Io(o'T8A@s(?h`KbIGDOkMW_XCee:lL;\#@1I:YO8,p&dMm]#h,*B[o;-E%qUt_O00%l[_BkDt,Wkl8g\6@:S#a302_O>dZ>*>8)Sat@-\/Z)ds3.t6]-a:eLO/0_0tPT-Yen9(*eGfRT@F")SfYnV,$?L>%q,A7NT=/k'oh.kI9f.4kQK S(%_X%`:"%g0/]-iEm&[U\ARk8N+U3bl4(Z]G$9_d'hbSoK#bYreD-cQ"]W1T26F@^WsI QV,cpI.<WPTPiGi0/^_H5W^PSetF:UY-Q4GMPIg:1N-Ol;P#iQo3i4CE.]eYi!b.HPqP8?8rqMK&)%ltAtt7I[2Rc,.F3()Il`)9B[FH0NMiF"imOiBAAQm??^25+I6r6eonS@9&nM5t#5HMGTm&V?EMn(#^6B(X%X_4*o&["iSmAC77R7$h<(k9T(XHbMA7/&C:WHXsLIsj:_JJ*Pjpe$sh@tIp:F*]"#H8KFR=QiEorEFC2VZhO'(\4^C9qNQh,rjGm8[JAmGAC0V@=G;mMLn%Va\ZK>niK0tYo9E7\)kK\U<#6(oX1Ngcf?Mo;dB`lpDI9fVs2>#Hf>LXnq7PtYp[8>:NaCgFI+Z@#As?kokS9%.00\jN"UP+F9*5dQ:ph\)b]Lr*Z:E)bkl q8k1L3mKlc\70&ZNfp7Xq&3]dNg@[T3&/p,id;XI54:&`jOVh]U"Gd4Y"gq5)\n4f!TN!A#lCG:4NV< ,%p`b<-4q\dt^n8b&lpgM+dc/HXAsPgFABAakW!5h38tHVne0prOK@GV+Dh;.A1#;WF5Pb &)A`Has6C#0[TASJW&\8JYpDTHK3_DE1RTlPjRrcm;G&I88C2CrFY'Lf;8c&sr&pBrTSsN-&LTj%\-ct[k^\Ro8JPP% J;Pg]p&8C7`CRLg:cd+T=L*p9VD+'[R$EPM"iniN=s(57WT0eU$K:l,;rATGAKKE39d=`!N-VEA&5[b!MH?;.kKP"XrkJKa-\kZ[SLD5VO,Z+J_lNp@2\HE6^^NO%l%+D0^c9>j6D<\'V;;6[8hd4)2r@\">!pAjXRrKW_:hPT*039!&)D^slWa8AVt35M?6^?8)XTqI*9O9$SGsX!cbr@t!.FSnIGf"_TA(FO)_DGr?Cm"*'hhOkF)C2fiNoDP8YCIkA!l0gOG8bCXsn.F'3=9#(A#r@K@Uq51k=@_,Qmf4;^p7XqnGH=0h#]p](HJ?Xj[>r>?U-4ZH_iR3c;LenPcIF/4\*.ORidj\:Amc]oJ.XFN-<es"F#Q3IA9>aNP")GnN[r.A9qFK;Uc;f<$%X>U+eU]\#pj=Z hqWM:MTq$/&N;eS&<8TLd:&Ab*r$I`^Tjo9Vr=O)->.eWoX67"jKGNfFA%?q-'EK=8g'_3k:PMOEKE66cTU99+#(D PREH#Xer)2ZO_:4H:'/d Hp!I)nqOrglfos*[lJ#rR&]ShTa)$W;ZKenVk`)S[8@?B*'3dHLh$9&h*XmqI]Vk#@AZ"RV8n(tC#LlbRUJ?(hjnf)ZtlUY[ sgHsHKC%1nREJFq+@D.nb4aA!9pS?c$#$-DA*6GQ568LTrtQOT79!lk2d FPo5@"s!WY7q`=s1(Q^S90M#2I/3pHgkr=3IlK% 1r\_'N\1cEU!;668C"1-W-JJErl:VNKbji+2SUDcdH0\3kh>c26a1h#6$8AV3dCAk<5EbS1Z 4`1CE7a7ELnOsLFXTVF9S =N$7b4;a&,7cUY2hr*P]nX06GrASL`<\03eZ*[lG`_k`i);at3041D"Q$`9L]YVZ)Im)IX<\62,DmYMR\HS"t?]o1:NBtH=[:>b#K&Y,$Qa /sl][0 &?pbqX>nU?)1#?jkC0)^$T;OIEGAQ6RT>Z2+')DgKA232na)2586_o1=A>?mBk.9\J@isKbA6//kpEdDbA]pCoK$f!%#?`e;Y-;d[<`&+=XS\&VAoaFZWlAJ#N\)4E=0tMCMKXk$6 Qd<#5@rNCh%7bQeAke(c)Vi0bEG/"8`maPqA!RC6D1 ZH8ME@A_[flBH_CGObF\AAL];j_@Wkf?hM25%P6&fg3/0&ZQYE4(ABStJ'qKG&=YQ"A=esLca`BO5b\!,Cs%U5WTM@Xe@59in0#Wnl2CGU/f(I.nnh8d9nL:.ha],dL%!O&(;Nq5MR]rN:/Z;ga-Rd_JjKB)*`_4T'2AY=IC:d./8@WSU1) [8s3E[W#gm#Y]g4;[r>XD`LY)lAF4[TCgf$-_4' 9MH"I=N+!+g4q:;4m9WI.n/0dm?!6mW,,C==\O0^I"PPLZq2b^J$q?gQG-16IWAdHt5a>4J/_ls R#6\J5$X]o%<%'"3 `A*]=0>+@dhpC!UWb>_+;@E;ka\a h9Y9M"7Z_IET>)L k$dbAaL9]AM>As=oO(Pc-D5@p#<'NM[JQqZT[P=BLtscn*t6C+EYZ_fh0QSCk$LI0(a&`:jtpm6^%=L?8?]\F"P"C](I*(^fSr'$[gatV&o:&k?m^:PMi.f?//`>jOF%`N/ 7-7N>d(R5l"q8=D^C0(-M&tddJCYL:UdMj:pZPmi$_;/0cb7H/1?AlmR(S62#F"e,&CpSQO[m9[-,&dal@DWZ.7+H!;etAsatJpZg,i*okI,S;8Ef`rj$F-N\'%=DM\;$jk (Wg7!2531OQ;Sj$^j^m0jU%(l]j-e$RGirG"po^71[Ie9h+(OLAU9a D4e/HbsAne.d%SN;;goAQ1_`SV 'N*3#kBs 'TfNp`_JsMp$VYrcpIG9C+pV7[j4d,5N^\EK.q1ff!AU9AQ$44B8T6Hg=T-E%"VjgbM%dq d@13`UgbS?#6I$pdl=Qb"p1;A-Q]0Ro]bA "k&5G(8>0`#6)JtrC;_hdrU@CBBrb'%$C=ohkmZ0Q[\1a4A'8l)nA&o0#<TM1aXEGm9.%BqO^dP(H&?q%?'FKQ&Y0g];8,Y-5c"f<1V.t(%#H:;ek!imGA"`(k8+.ak^_CUl(T(eZ@^;sf0!saTpj)5peDp?ZE8?S>n'=3!iZCh-<:f'ZOb0;C&mAF\[7(f7=KfAhpjlM7RT)%=jrK%C&I8J2&E8,+c"mag3"re'""-#rrA?O _0G;KM2gQo`HheqqRGAmAm7"I3r2WYc'eeioojXT"V!hZ3`D\Etrgo-O,VaX8UU_#7GiCgsXV%-PK1(JSm7R'&eN$kQ "#kUArkU4lS_VQ;rVsiQ &@A`csf1E`*+EjNC59F[V\'o0$#Rhbs)><^/Q^/bqL3Z3k. [Umki)clEnQN\. s]S+8ZF0?MBlAqgC\[o7F(1WQ CkHB@F>BU2f2Z>AZ694KkP4q;tkSKaoF\RJcB(+-92"7=6Q_*$'[h>e9W-2,'"E#:D .TqXm'"HeM?]3-jc*(T *QET<^]bb3m-P Y#-\Ql'WL\X5r: H_BjbLsb9a4N"Eb/Em)"hc2XLIKrp.QIXGDL.n*X5A6:Iob=-6k;SAQ_N'>e#C\G?BtOAd%r'H8aX7%5C.5iR.`,Ng0CEKL6_:=UQ7F])d6r(Vo,^O6[I. IJC(Z$kS-sBWMT(mRG*::NS0$Oo!1O<e!7hE:R9hJY6IE?as"^YBI#/Cp'9YGW`V*c>`IO,&)k%lQeG4&oQ*2\aPM8]Fka(/AH508dooZB@\\I\5;iGUNH^;S]NpcJZ>j!EF>NGe<i!2Fr&"T\cMiC@K-h2\g^pTTPl%X3Q#2%t7H/cBGACb/q%>rU>On@+&d"5;;Lt2A=N;$S67l*ZT@Q%7A&t&c[&04&C]e3M;+!:k&ZpA`B!oT$CJ:IJ@Zd>ki/!2_-9/'mki_alD bhQB,nUVA#7dW^8EB8?R[o.T(A5E-?80 DSoTFEi04?%h1h$HL$L-L=nTrHlLAj;q^A;lL1E\XL'p/B5/@9orORMon>Gmd+6B8_r='+MABWfsqL:ipbmcc[lY!A#^f;AS\(\;inAR$^FTn<6%'P3dckS&]nV/q-mpOIgF-6\kriesO&TM;B9hX.[d[>qbd-J[Bmfbd_/j(OVKX83N8Df"4JX^:CH`\fT4,')p$T#0XGfAqY`i]/rm7"PNQ[e6J1OD#LH$QYMMqH1%QL.[tW $etq=r$F=YA^L>DNj4Y.?_C?+2WppMb^:j!.=gl1/:?pBa6#tZltcS)R58;MR09A#p!Rm%RDaTT^"o@-C@*%<;)q%/4.W)nB7^SrWMB3l>$3`UfoUkbgRW>FGK$M7c:gV6G4cWcj(+&BXnc]6Tp+QP%.RW^'-d3Pq! U%l'j26D41c H*(gS3NiQIsa]$Ion p8H3nr*>A^qpl.W[6)\-o+RU]Ydn%s.ON3@Ws`O1*qj/B5AVF4W/-1!ib\(B9@a^gIpW;e96\E*d0'bmpb]\1)22,D(jn1X?ZEglE[U[9;%D^n7Ad_P7)iAXj@tOFI[@4=>>%[g87r8T3+Pt<)4)5Hh>ODI>'?5@APJcV&bXH*AY`#L<4`0ef;N?aC1 P*76q!4M&T3T-/A$njY]p"KSCla\=(UAaWKAi@>iViK+" `]F-EJk2b&_:6OZo9rJ^!tWW/OFNCN<3lF ES=MTpc<kpe1G32)[*p`'At?J> S-AnSDq0'Qf2,.)r5q!MQd03c8g=VCR:)CEe[2HVNg*7p'+Bp3^i#3HjDQ(7i#!!XSAmt 4P-K;,!k9iJ ijHq4k]LZ %KNOA+kAN/^X1fJ"2I,0#<1mlMX59[XUg7ZEm,$GRW\L%LW>Go/qCES.A-0D/fBHd3R("7&n5[Vi;&q)4Rt)js+YEJg^0 &\V9A"KD&8r6t-@=$>! (2aNc:5+I02R3qS9Y n/FBP%$;&T8Tc]_X6p7(;*D)m5<#b Noia*7V>Wha)9/Z2i VW;S"8h=LsYpW;%_.iM3=#g`L][H1rEKIPHVV->?):`8!*Kr2Tl?hq!LQ;\4=rAfL*Aa"RgH1_lR&S?F5HAjP&T0PIg4XLAYRAh [a1Q+lkSA [("*1BWR+$W+i&G9q1][oPdi\' V_1[kqL0K3ID 3h.MCX@V<8Q3PDP4K@=]ob7A)cI*6YOkn\"R=o2@2rXaZ=h&&8SLr'2?8ht `2Ygj?Td,lsoe`b9c8hMpQX&,:o=A``PAX_W;(+4)UmgC.k%k1`?HfBg(.l4%r2 b;s)4q=/kU07;*Z!qJ/3_n$j9"=@p<([2LfI7M`##'[*meTIHG%AZCXWg\6SUo]>aLFk'&#RA5n:oZ,2raU7dIE)l/eo6S<6^EL+tZ*dQ^@m.nr6F`-;sX'@'hOcoT +D)Sgg(\5B/7%-ckN^1gB77WogW&+=4:f"d."r)paXl3>HBFX6XEGjLJ3*ChXJS)k.IXhHZXITitshjDD;mSU43qBRH!,MK$AD-&H 2A"H?q!dj^rZ9= \TYg;[G`SU/@>A`0n;(a@Z/2O>^1=5);qCFnM*3EnN-rSQC ;"+$BK: ?ZjaHJ,FCq>R@cBhXG6\Nf?Yt^99f!pI2e]S1*\p)78"LIY;AY+f5%hU`s:heEq;At/0?^2n\V&=pP5/n`KPVO9UFmNTgdZ[ZgVA`\ILfOfA/$\DXq>@QZ/1AC:73)shS_[o;&%iW<;^2M3=hU'@TOmK>A#)OW`#A:N^@bWOpi@[3st>adqdQF>5]CsdIlI;JrleEc;"dtUI.iPA6A:eTAs$G^oKcUJ?+ct4idA+(`C$H%M?G42c*h(3Fa\7j^#U9(`34N8R1b2qJ_dr6dhKdU62W2L%];]8MN@ipji.6s*fh[Ji@bJ3Agpt_cIBU89Tt('!t)B'J`3/,W?NaYSr92X9t.n=3A.djBQ3Sa0p:@8/oqFPYh(*P42s" 8@:1D\>nE*sn`/"^ATJS3W/?atV?Bo&P8@m1 HK;AS7+K,*FEm#4X9_oqJjXkHg=S^#8RWRp1`!j)k*PY. MmlA&1\r@*t$//AKr8F!R^.bqmse14(AF&Z:Q=o*LSj:>FpFn(erd;IsnaOKAmTMH)9G8G@YFp*(#nh95M.@?iX9,lK"]%r><p<^' T01#ekmY?7leqSFN_a? jA4B'I.VB_K:)P4#;b4#CR*A`cT9q%CUV[_(NYU7LJ%ciL(4P=DW\G]/7)=M31E=Q=._hI1+(Y#4e;EAK9!6qbZX7 9P9YY8q7a\#PeKlAWO5Z5A(1/@r1?J@FA:X5[0+j9I9,#)>26ScaPBl_T8G$RAk4^b*K[F\k653JaN1Snf^lBG1o=[$7<``l1jAI2TsIl-;#.16D%>E(C^t65)0Xm0(CkpN9F'Sg]VPQ`j/D3?$G+?L;)$[Sg$(^80m<].TF&C+h8%[-,ojf;GN8 qWYRg/CPL$qj7b?7h-D24*G1mC?c;"Bq trOD*aHJ+8:4M1'8AA,r2*fK!%&P)[.nQ'af=`W6/0:h9!9W06U2&YW*=m/K2@ANJl&KPS"e:=S$)sYC< _8E*4`=d\]NMLW!R*=5H!@g4rV7F)AtX0!^U CFP4e-:b?0AOmp2+UQh[PYK2H;@\cmW*!QfTraE2BFWQ]\M1jBphT6>_?#8A]'A./9'.[%o8W_KcWtoF:*>W,6PKR`P=$N#*b*R.0.F*gIQhgV`)j3mcLZDpnLK_*&=@)>B'.9sP4DQV%dnb]>=.f+bMq)#kHHUJ^dC7"RiAL@QDLj#r%A#QV)`5.6esha9J7*>-[C#:&N(>\tCV*aB[]$XQ3S@tE<$%^Njd>#n9>.K.0A\j@pEbP:FBAt9qap*"GM$]=Q7 7?kR7l6,)fXV;^^GfoFNL GVS.ni#P\@Me] <&>H5o4(B!g9pUY5o%[o7dnYtg[PlctW`5`T.RprS0CD2m?*/a.?+sHk0BpAtr84RE``9iK"^$i=aMg_e79AMf_p1qGGjY,=@>E+E%5Ft PLFgKN$;bA)XYFNdg[1DPlckss5mfe"A>Sp@R`mL%KDnZ/=HU@ZA&a,N"cA?KOY*(W &UZ+f]Wd6R`;q)bgnJ(m>9D/c"!6(ki;AlB8UGY-?0m6l`l[q@J;.`RF!^^psAIHXr)CMPbDRNJ\dFA`oVG1l&\-?I5QpAQTF+RhF'!#=F\bOh.MsUKUKr;2:Arg'(Snl$W078sP:kPhTiUGL[0Q!I$/!+)1i!@5+/hs9@El2XkddQ&JoX4f]cB>Q9#EfY':^D.I&Mtl.cAR@75]Q\]PbSlsX"G/Z6$NUe.$Q)+gGpF:I2iJ@O1HHEgA,d=ZZ:-jLe0U4QjDtN:pK.CV:d&_^:U(,EGZPF5rA73&L8V\ t E! Vr6\J;*\[NNE8QqA\(m1dQ[6VHT.\?PWq.O:l>"WAm+H^AdIs a_H\2FS*tLBZj=*oi7+Jf!T##@ 'gR\Rgh(GL0^)a\?aZ*53&&t!Z9_h)CCT"]^?XB+>/ZD>e,==9_YQOYZ@=4C%J)n5"t<7mA+s;l\?K%e@pCjq)Y5(QCt>[&L4m3kb&5/7'Kmq^pWUME.pNKcB Rn#b5Ti='Fr;c64M!@Hb:Y/O(=0T]K?8JnVf %(:H<59Vl&6o#ijl&r9SQl(#?Srmt'#?co"JSWBT"7)PanS%Z_=4aSf.:1-Oq>266R>OclW]*4h9_A,j/^V PDEN2e7cnnNn6Wb6qb4E-RXK/DC_nkW5roNrb0k/T_mjK:8)P@[ i^-:L]_?JE.S^im:89(g2?a8F\->fZ\\YqY$79i>p8l."H/EmBP=QL9JX[jB1N@,c,bg0f#=/nPLaQA0'a,oX)C0Q1TQLSYs/$;aGm 7mC&<o!2/ph`YH;ek;#pT7J+RO19@k7D0Xk4K4.sVX_aA3FZfX3(9Pko:q%PY.H:8@^G&pL__G5^![#d?bcRl-kQq+3WtiAr"EMiTTUB@Te@YkR`1W(TfAf8a?dP+aBj:A7C-eKSFcY?KOrl$U==9e:i"gA(?XBcK`Mo,)igG6btA:%C$6shNsn7=[`83AOth^RM*W%*oZ(I)WKae@:K-"Jno\#OaH!"gYq*Z^d@97OX4'%AN+lQWgEd*K,\=L,iV]!AY'o!ba+PXQiaViLAW P@Q$n!V9n;].sM$^o<.[mlHAcK?b*=XcROiNF]eVD9Yb*&iq&TWnlFgb e%1e1+-@ gN*Sb/1q;IZ%mDJM0r>Yo]i\ZA!%:8UF>@CDT-e&t[',Ag5#0GJhM''L'f7tli1A(rPBYUhe5U@\%!;3OdHa%qO4V>!B059/Z.c4-8GCm+=q0A]b;41rQ9W229`FprnZN1o!#.$^#eAp5R(*1K;/\i(I0<_ISZ>.?\^Wekbs]eZERn@5"3)OD=QBrN[krVmA]00HjR(j=.=3.#G&jDT%*%[0QUAh7RGV1=O>a"T/KV)b&B<%JOM?!dkEf-q^/d0Mq-Jnar7HsTWVeZ3j)ONakRK_FJN)[YTUQdsC/$^Elt/blPLHhiW81hWX?19KVeeB()c(piE0CY*HaZ ,dpSJoWHnrkW)BtO<pa?s;M9K`E+1]$-W.s7pCC(&AL Kp$dpX`/Y0@RZ5B[;1Cm"U%*D?.!__E<[s=$XbZhT2iVH@[a4JRDt@*XAh]eXArr4pj?YM2555jKLI`2:&A^ad)s,#0K4mXTpU..-@*FDU@TX.N7>%(h:JBFtYkr!KEG>Gh5KstO#)H7Da@7j!erQ`_6qs3 $8T6D1gP!5H5\`nP-_TCk8CKoDJLNX5-jbnhU`g5:gTf>g#"\QUk=VoSJ4d@NMV)ZYmbP &"rDGK Q7roi.+^XkhrP\VX!m(:-,lEY*bd3B#1$*UY&ans$GBc*:E3=&mZM419#E/mettA@+'=grDQJLY^]GP42R;c?JZ5;;LCnD0a)nRYoftWdk4_c(5#A?M;*D.!O[lT\Mn(2A.$F-H&+P/rg&TXCZILAc9YjBXA'28IZ'!!F6A__mBA?D2CX1:H?hQ^54O\Ba;=F=?rYPk3)4.^c^=OV]b3??]lU%$!*g`YkAa!GRG+UQtS8=)A!Y2='d:;#Fp8B-X3sl'qg+iW.EDU5n3[1"]1\<^4W"oJiE@Ma*CdFJL9`K%-4 'lV:5'G`mj)[]bgA3W)e"3ls`aP%05SDcXSM]d$;-mOc/?H)NV/#j-bl0YG2K?_c(N\5AtW^7mP?b)3;!!$P8\2BRsML.(/,.9t+?d>2(BZCk4AnR?AG*Qfd=c9GAEfXIp9(a3T8Wbg&+A_MN]'p$EeTXB0_4LUB5YiXOsMigM*SY2?Z9+&=gHlk\i7*-M'TP!e,!nb]0i21r6EY@/c,*np&P`( Y4ntisD 'R4DV.h7e'=gchIDed:U?bR9=NO,s\3mm[#O+:8+6?hRRS@*VAL,UH\Y`"DaZcgTFqX<"UYE7F^DrG?A 2l3dZ<46f9*"WB"Cd]$&VAo!JK0=YnoF0QN*ATZ\$16RY(qg]2F5&\,(29'(H'8q!)V_'pI1l(R'm444.QZC,@;7AJmP.< QnYbCkEC]$2,%OIM)'snFB^4T%&X8RMOS+8Z\?J/'8/N\2Gb/<20A1\V0IN$(O.MDh]MhK+,NAN'$KKfUXb(L/A3EWKOk$Af7;ms"Jrs%)H#VL>#^90!42jF?(+btekZPD-_>RH/q[hY%eNS;MAMkAM3[E<2M*6C)HQ>3+I(I^hkgE*;Ai-e7-U53bDR.E?0#f2f4(gm"m%B[2J!3MPZ\DXn33RoBN=>op\XBU(.:g^)g@'<>Qc#9e?Z[55L]jnW_^Z5U/:+@/`c9s\K`)6OZ[go(agP,i+Vpbid'A:N5]Q8q%V@!+/*V%Utd_R?MU1e+;@:*GA/\DQjcO8H])p:4A^,i[:\<-1tj0VXI$->% /5m(OC&";77"BmI[^.8C%_;)AS6+m,;j^hKG0`Nenf!@%oT [Gnf.n'Q1WQ,SMVp\'rI-M!tHce>(+B67J`NiFJi7SP1>j>$)&T#)tF_b;p[ecN,Y?RN!$F!/_>;(>:;GVT\dJU#nO-qXhI],t$V1aD[/]-[2B1%l0i\E$fDCmGK?hnG^p?K_H)\#UCZ)O$C_&JDX$F/_o6UJ%'qg%#r,`1jE)lDL^B;TnsO A'mk5pi/1Mjmc!AET;Cot?F3[1J"-(i*X%eRGp$.nKfVJ=A?h)4B1W&b6=8P."oo,?VWWIo-Y,DZ&DL7]laAWLW)$sI5\NQ5<.eJZ?5(h.L97rDJa4bb&AsH</gZ[5rZ\mWKlQ%R#6rcAbsfH1"Zf322_3l4(cT?q;dB;DrfsK\mtfJ12.^c!hlcFJZY7qY\S$OtHXpPIk^!Q%=5iSD?h@%)<Te#Ad-R%\^Ahe\oF@*'f0 n-\5R:,lm/n5_]iji%d$;!]W06#\Bo@D:o LPPEM@d&JW\n**q&Y:R&E3b0>Aep ]PP*9f"q8-]Y$hA+/bfbe5b-p!"H(6C^P&k&sipE\-"cb],a[B.kh^ ,"A=/]B[)6L7'9B#LjOR ST/]7ID`Y6/n]D^j+[A@V.&UXVnS7.J0Pt)<-[tZqCi#sC2PJ*68,ngP?: D3P<!*)9ta/$=.'q^dIRP.*ec*2/^YdC&JB3Db^e>=g[lEAA"1G5p1`7nr@sDgt8AP7:\dFYSgB\e##sM)kQW=tmI?A)qqFKfGn\F>5cIs 3qM0\fC]KJL?A$.((ij8>";_a2[=Npr[H",#s(=I!a&*)TY]bt8L&bhPq2TK7kGdQQml<[*i]jF9o7$]gK=dd ;>jU%4:(^nqQc/c[>T]iS9sXK_UH+UqrL!lQdM&_S7gr/tbFA^P2"#f[kYh.^Z(U(al5m@TL#Et$`(LO57%Q c^t1&\4dR1F lqANA+o)'@/IetJrJb%b/WR-$8N$A=d38K3[is;Y.#7=Xt)cQA:lX&.&;cdq!si125Nr#GW'f!"@jX#oNts9+25Fa5[jt0VNpBVE27/@4IPk->VGdg$ZOI`c? TP)OFJ8`%nhE@=SflQsXQr!T(@5hPA<AF;mVb@m6<2LKDedE(o@r&F>#F?,,\Xb0c"]!A31L(/7fUf4N!Z,&O7n4YhpK['K>FVE1R+oT'4)YR^,=FMNCUIa_hS=8''%VofLdgT,Ik*DggSD7*X0:C!'`PY]qfrU+76Xl"P?sZKmLAgn*LrcV^#mF=1'LN<6+[.@qTT0;0#N"FIV,F<_s=^`nF$tm"1h.-Q4Ri0*OI2,iJg05>*X"!i#_ctf)lV"?kn=1*0(p_]SU[%U4J2q,LAA,b-h q;BFRs6)kBgp'L/4EAU/kf2+KP_o";?t =44MWelLiom7@UfkO:N"k\Z2,=AhrY$s]'7&A&A;_I8Xc)dMP`-*Db9&U8>YeL<4#-d\eFCM3;YM1;A)8\LL9q1G[fCd*(MUSZk"/LTs42#&YaFl1BFQ*-/)a>>@2X-(;ndjcTGT d`o(p8ESY&Edi;q9?#:qG'"AbAW2$aK/;.UjRU0-@Ih:[$n!c2I?n'^IFArki5)Dc2,'XQTO+5r5L(^N^PP $OQ',ET!pp5dLO-E1kJO9a2=g02OV?Z9DV@a+fASkLjo)aF"JNjgGZ3p^8g5^N:58?,)JK#Zn&4-eGrHXU2Z9OPj]p5$+/Z$-Q3=[Hib%jL6\6L3^G(sAZ;/;$!9MIe!sVY*c-)c9hX ^B8!`V0=CY5XW>FmA>3X+M2KiWJl#nRL/]<<=WG3Y=t;_j2hS?_12 X7O6lAq.%n)&@bbm-%g,e->2ipK49HW VD%@c6'SE/81mAL6?\Z0ig9"l(%-&bA@NPapRAeBosJ*H;eSBq5eNfa7KI\_`FAe?f<*aRKKmm4Y8\mY.E?a\AnRK-'nCM6R4_rZ&7@U".:pJcl[+SNVAp0QVkA.c_<3!+/-KpW#1#gPoTm$-AVaQbMm)+` #cY^(s1(\d3-pG[bQTS#X2e>jSN*6$6& :ZR87O>&7=1C,7q9_`l-f]fln ^b`^CQ^QI5%nAH8=j'Z5MW&BMi(Osr$*22[[js_:%J9Y7FH9^/$>%%L(e:gQR:f0;s24gOi&J%5[[39bQ&f/%CO",Y'QZ>>&g7=ag=@q&9Q*Dfp:7-"6hJ<"7dXNpIT1d;]"s8SV6l?9Ra7b=heU^<4Ackg^FQAVhiU;YdUIB&V_m2#B$/c.`Cf*AK[!*0Q@fBJ#X)cZpt$=pY:_&bJN<mo[hZpDtn>Xf@&01[g+j_Y1bBqBk6tDRZX/\\lmQ&n0E:"@BrsAD#`8MX5d-;EU:ODs.Mkbf m:\"08hIRg^6C=kItD;WM$8[PMNbMJ)K'3#sbH6s>QSlh5o1Z367dNDXCRM4I)N>)SFn!:'E^GN0A@6-6,sETk?Ak8=rA$L_@39h]X%-5JAf,3eeCXHWgo^3VQCD mVqd!Hl\O$15c8dQfHVSnDCSr'0nDAS:Y/Em?DMWqc.hQ2Y*;WAK&CH7F'gWTSho?DTQOj2_!#LEBP=NA,>KX5&>o;_PTQRO>\Y@0gCnerAWa!6D^+KF+YL.Z'b\-"6(F?g\OE;Fs0kDr"1qVA_PHSWXO&;Y+:2mhcGaHsS/G_Z:!'ChZ7I^Z<+:?0.^-@IS@1@? ]: !"$s7!SE?(KJa*CJMmdD,1rRKD5O.6t:j6IddI-! UfW#H33O'YM]hLQY#JT;=5WH@V!nO@BSd-nSJ:8&k"0'S$Qt[-K3,m! RX'daCqMS-dfPHCBe\fEKRoF%ICJQ`NcG'M/SIfQns,7=>U[_4iF(LO(UgQt4h844%[s<n!gW2_aP!mj4\1G"6fA:3./>Y!:&bP/+NL8:4c6+_-F +J_-[E[sV_J^Na&RTj._ 6at+M)2&DF98d.e;]b@4%KA9;F";Ag-"t8>l(-(54VB$\=lFO4[5tqc-,QtinJ*5]D#i14`&C@oSP9n,ma]*SXn3`;)fF6GA(Q_fl"K#gd$T&_Akelq#%h7kO2qN*YPY*o_8'2gXSmE,Y7K?"$7(KF[.C5imgT%87;WI^Tnct1@N\C!+qIT&a!0U"[)).N>,K-rhQ%p`W'RM<.JY@RHepUbb;?-3(a'r\;"hk^d[7Hb-95b(/M/f4"so2f--WAPQ7-C<+!?B0SrE$eb.)m/-`A8+-j44d6]U"\QQdq`^if0mrDqa`P b0B/8cni((k(oTd>Z[]d8k\Glfo25A)^[)Z1pE&^5dN4HG^($FB4BFg%TK1^Y(:,M+>4os9N=d[AJ)qZ!o[J9$F:6/G2f[o[3D?+N@O4:U29OLK,acrJ:B..A%N[o=n3%!U5jleoIPD8Dc)SoT! r^B'a4=+%lp2%(*r"]ATCh^+\[KM@7 h7*9-S(fc_eaUK\AA`U+9P;DQ1HPb@Wc$NX%gOgQ:g2dR>0,e$g;\Y%D.BT_jso>FpDAFI$9I?FUMS1?$iI5enW`ICBJSP^Jmm)pjnB3.%s?-MH[t$612MJ_B'"R X\$aV".J!sEp`q<'>[nbZAbbm$Fl49A?LS%Fd%g;[ggO;FQ-i0B+(CS/-?g*Jm%1PH)gOR?4Q\IogY-JXn8S^Qf0AWZt=HjmS[)Y'CjWrSUA%1&4>o`GA$gUU\LS[kB+,r`/cA-J.KWbjd4]X-*$g P\Al'q-d3q-AfbA@+_7k>AtIJlL$$M4qo21\SQFLo1_V[B;tT>!$^feIPTK)/)V>EYiEJOi`_) ?c7Bk1)XJX#PtR#eAP&T-j2i6.=4tsZm\Ht9XAI+;M@Zj>lh6aA*P^9Ymg(-nB==-!A!JrP@Ujn,c[r*(jRfkdp?C`Ka'\tCX"c-]eWnE2]?!>E.353qKs7+!n 6#@GFonM(-?c#7/U `%=RF:Mq*<"(TX%6m'N##4BN`FCU]KA'IAZIS6Yl^M@.Ac9lM&j+B^nBPM_F8&U9A>4A1\,?]Dm"HjZQoeBS+g@P*r(0$h-(o%_)tF-^\Zaq[G!a!2*+kZEg1FIUQoQ'Is@!O-q6,RDW&L*cfTJMr;Oj@K-m4'q.h.&*g>6UZ=(NAE6(&A`Zt6_.a"'B,/4g6Hfhln\_$VK<9b%sD6DS1ik7n?VoNl2"AkNMRJ(srj,ggIqTJD7qinH'Dr"1T?,?%hclAMI"nj1["LM3$H.A[]_V;R5U&`:]b&6Y#jVf)[s2<3^EFT@'1k[m.sAA^O_^LFL59`KL#`c@_.37hW^3D!7q-d+sH]H"PKBbEGaao'4X0VO*q_]DiJ#ETa`/.\VTG:6;/hY=Wa!&dS'jIhi#gQg53R29DWgDB2mM!@0YmiXSUjT D!&gnKpPXUESfKN#bk#]%`T&M!DV5H#\6\@D`s#Yflk3&2%qXLo/kH-T2+lB3B0d&IsS7IA^oG>>h%GSF V]s/^>I\V7Whb<_U5;P;9SW;iK^'9MkJbf-b>'I^DY% 6/p1lqe$rmpi%@9QBQLOCh9Wa$ABDN&:17**U,7=]j`42D]FA(X='_`0=&J..5R6qj#'X=_SNl&n<0UYriB=h[1YL>bUtqiOrXhb)B t= cb@@148"gmJ<%kTK QA(T9]RnQM5*,[3K/00#\qa(\$r7 pID+>)5j.mCf[oOPbk *Hq]Un-2Neb**1fRf$19k]UK#)%#/icFAV62!V2K=>\f3(@^SAhR6rO9i`c?MtkINO)W)6m9r(H2'PB gFG4,I[Yp0;d1!BqB[S;'L+& pVd.dlcQ*bXk:70KQ;WC< <O4 0[T,\M0h3dL;rW*\m-A%C,B=p:F/QK'WOG47'$)1C*`/I.tc7*``C7q#;%Tf+P&?gn jN,t22cViK-s22LlGpZsFE.Sa;f\QVM!`piM`[X/BOn;b]@p1I3\*D<B#Fof/F:/4Jp5X`4!Ab`/ ra4j:RFrQjYq`!8AA!a;<G*is+]e:%)$;VJEFEEB.A^piDC\,Im^#IfeW(68F8jA%+/Q>s/BgLP1DB$OV`lJ`REf[-Z?cGs;A?ec2WMM)E5QT;A10:]\WaUT)s%-iC%7nSb6>=Qf#!q7Fjj+#Gs X$k(m9qAm;M_4/:AsX$Q_V!L5@1`aisf--I,&;AC[7`2P4,RNPD45@N?C`k!ZR_YRgfWtIfA*6Vok#S+>E@>19/TQVImrkno550EkE"V)c9'Ak:=[$#_,JiSFUg'rJZMD3D'fQUcZsQ+*q/MbR]JtbAA;O?Qf.X,4.#q(WnbNEd7K_@]eeqZ MCJIP0Qjl<5XA#+c(53G+)42KD1'>-#71FPlOpT:)L=gpA>nio"mCS/C>c^t@An]C_m?Kg$/\&fJ3U>TtJCaDf&!+O"S(\&i!0'Og;Tm1Z7t@"jbk[D[oI1qsV4"i@3Rcq&doS$0o-1+U*T:MB!>$E8qA:,s4*UFg]8P*P17W2"*NZWk6$'s2@ `bOp,s1C5>h0fC!gX`X@Q>># BH'>bB$BF%'kd/j/8KKIm7W_`R4Xa49b7+Fqb4O.qc)A`iVW&6%S!,6IE K4o@(lpLEUX96o=SU#cE:J1HKn5VFb3T-kJh!!eI.b-Mfke/EhEm7T0U7h+q7K`Q*]D0X6o$H Y8:Zi`Wsi*VFDtgRdiPY,A<:_M_`^h,YZNG%YhF:_I7*LF3`R.<-.0(o?; F2,A>sW*Ci][t3-=hpVaAQY?Vc`R@$2cY;'8+[,kc"r;fiQI(6[_GF@TU!Qi4NI*?=0/s$VR<_YZIdI.=9@]gakFqn4@on=`"Z"`/G!59#%^lhAi&:c-"Y1oN:dk;isr'Y7FC0`hEAoh6,2` Q-K*``XNoAc(gpA!A=[nB- r/\R;P`(=7j:UB/(W\F!L8+]h/#]*;tW<dP/ai#piqZ0sXqT_(LOb*8.=QQcln\CWLL&)aA)fGi=Q^DN$B 'Z/_^r$O$kW&dU39I"'[E`)$-X$\9 CI04eEc*'n(Pf>C&*A/Z0Y,Vgksst7)T^Rfi9=38]od>kZ\$]h*9cUU,DMlqhdQJ"?h^/;m:@:%ho@6ZU3'gmrAhEq^D2;"=8[O(h>Zm^,jO18*&>tSt4UreJ, +Fk<,;A1Jld[J(W2D"41o[jBL-P_Sg+RI)S6jX1.<>B rd.TsO%nj)X6l3Qd8@W.`WN6F^j+tJg]pdf4=?q@,eZg0&*-ALgS"qb*St>4bhsJcZWA2!A2X"Qb`'Sr@-MVjYLo."C@K*VCFI 7kT1*A_HBA^M1i\j@.^b`NQU\o/c?'Cs6%hCQcD08#J.2$B;aQm nism8,ZKpAgh%.6-UU;le#=CURN+:R,$5oPeg7<.1(okE@\UHV0`\e @4Lto7<1I-jC=PU*/0rX*jjAO>U=7q*/-4\lWG>#KjftF@`/SB_cJ1h9L"as=]ZQ'0N&0Kf`>Okq:oXe*]j'hn;[[dsd*q`5kH8_TkB_4-ESEqgMU7d02[s#OebDd8tBH+jo*MQ s)F$.-UKfl"9+f@4'bd0XsbR^=`NJ*#`.;^E,ftp;/6#AA1(VM\E9m>*4tY pe9V\+Odq+V4VZtYmNShEfd9s<a[$C`3tN%HWU?,p<CPL_@WU#Tnl/nd^ DaR"cW`HAHPW" 0#][5A)`'LTC\)%4Kq"\2p`O,;(n5TVe.JjAtWtt%VBs^<`ZV(m@9W:hSJT#%IA,j5O+pA7Nac7B ]b+__q9>JnP3Kd4,?'R$;$a!;PEoDHOL\GO3R\Z%*^0-7g_cpbSYgI=U%&?Z2JN*"c8+/g4n,MUeG.ACAd41bI%"%1=A->InkNKHVX'AU%LP^@0n4J=Z+:RtgP;#C4#r5!]4kXAh/rtSRk/tah0h#qq6*UTRW)`?9;_&agZ@<J"L(d9&%$&W:rIWCD;q&OH7<8@nC9:@:E[7U/&#.SKi/)1Hp#1CV$[!O:(Gceg60Y!a);BjF:gbLWW3,65%1qEJ Hj;+0)$rN q'#g# UOcf@p,^WAsoi&Y4o(ID6&l5%sAjAq-+,"`JUV/B5HY070!'F3kNWTSb[A9!gNFG9%3-\^*Ieh#e9'_2]DnEg3<:&TeN#WSF'0,llsE+^C,,1'6\LCg/F/68aJrSHjY[BI1'&/`Z08'0YJP9&<=m,jYFBl N'JJ+=t>UYMrtFFj53\c.Ane6QQY,%FtlTt[: _>\P`WVoMnO]E"ne- BL>nM?r_L(.7P,$l <'oV0+_+h.-Yl5hLP_tRUMYJ]#`/5@aW[0;rZ(\DmXN.XR@N&jW8_RL",/`s"4V-[l.VF&DW1%c.<-5p:fY$"bCl3CNM[-9Ji^tngOUdo9WODbYcd)3@r3#hHR'3/K&/DLA\LNkD dM:XDU`=)S3tKgZeTSt^?@Ye&1];%b;NI4qde#_^Q+mSk"caS%p.NAIU/6/Rqq9J/?X_e/^W6"Osj&3QAcf,A)+s$NA7=h2I*O PT7!jOd/(5RU[j/[J+P`2XM2JK+q_f$bGlJVM*B9C@IWNoD-!>Vf$ClFqj;J5\@PX i8T!PLA@M69mfY+$Hj&GV36ko?,P1XL#o#5N]+.>Z&k])W2JOC-,Fe,@o>@H+/];/0kkj+aTqAHmYBfDiW_:I!JApEq<`,oCX2DI3I8ls4ZX/CmRi+_LMX4)`/b+Egj3W<&Yb)-,mq:[$).fYR\230Q6N9J7pJs#g"EQ\:O-#lp)@e`NpB[LHo$_JbNJpt&-5..ct@gm_6)]A8qRtA-P1b7-r3X, V<^OHNB!VLciffttgVP`1XLDJ!Us5H?daa?nspLARhrasnA:iF[PYI4g]5E]6X3EUe5-3AQsMm.*[J#*El(M:SIf])\A@hJ6?U &*Q+sJmVC sE[ n5!WVkb!?+n"Ab00Z8gnQ?i=FC2B%gg5qi;k#Cg>8"2o*6YpO_5p7D4g/c6ESf&'Ao/TpH>WhrpA8U5tO-g#>t?SAgG/-h9<lAL54>gYZ9sAX\Gsc0m$lG^/%%H(gY+E#!.iN6BnR`Sh8;7.-ndY8j2jrnC92f6GmAq""UXsE8-(s+n_3rN&04pj]'"8#TV-W/etb3T;$q=%>Wf1S^CEZVr7q6HV21L`<pg-f\0`ifI`/fmVe6Bl!F!#'UcL 9A`Ltp$=bS7kn3*8cc<+3t6cr@^Rok=*17%(KJ; $0WRPg$7#h'--o22?aWnC29!YPe:b$mhLU\XU0&mp4UM=Wqrs^htO1\>aCI6X99s_9C_09XU>4?E<(Di:\Rr&n*^]DWsZAI[iXr1Nr?j;gfRdO654c*'/k-D-K'k^/)NTL5n!63.>(&`hrYB'/-2c4lkKq]G YijUHe@% bSaa!gbLLK,NANVFKeKsmA^pb0qWgWt6K2iFSc&h..4+l)q.%)F$C!Jg6*ofZt$h'"\Y''*`SRa.ct)R$ P2JRs0'eos&9V5Gh"&eaT&?HG.ZUBDEH*gD&TZQKTY07"i]t1'rY8SCMZK5f`A5pF-n`b)U&J=p8?^>+&SG'sn#.X(=Aqm^6S)KD@8mqG/(5]^Z4LG[kML3$>>rUX7]Tr,kA.s`RNDea#oA)8Vc)F;NL:JSMt_`9FMlVLi[MLLAU;Bhg4qXW6SB-6S+]!pkG&/IZE4.J&p\=b/Z6EN9*!Sd Q,S t3mfRlZ:$Cs6d9f j;BU&&\?Uks_bSLr<Qg6XoeaXK?M(U-TeeB@oFNK_ Y S]tnmL?\SgkPL CKVOdIkl40HVapSC& h8le+Ob"7 J@#(E>.`P`IO(gGW1$&)m,j8)]FGtht?s_B93RKA0!^?f4_G!tET9hS6Q0/33RC$l'-FfdHs)RAH17:IsPSD3Y+L8\e-)W\d`qWrkkoidqt[A6PhNX?Hc,kh!,?,0i#TJAdmoaok['CQ[(*J`8=@FQjRT@NC31hk""_>[IhkY3E/635,_J"A`H_8GP=<.%rl'dpY/(`9Cp&Q=>(t<$fm<6:/a!O ^Y,%1&0 ghC&!F0'A5dqn/LW?7ehD5?>^Q=)ZB]0&lUPjW3B^2S1D&%,c%m*f^ @NT>Be<9O0No`VlQOVYlRV+=.sA_&ll/5n,@@m+RDkB(0Oo-E6$VLZX5kAmnr.I+?h"Yte6A'Ia"8,(=LJWQ_b-#UC%m1I)6AS6$rJ1G$>Y(C;;A77A!C/B2X!Y1$L?Y;go.JT2WpG3O/al,H/Y4TP7\ 5Yf'A&^;(5d"kSGmmD/!7(C<la8B!L#:b!_UHm9,qcc9"DYAQ't=$jhcAQA3"[&tF3\rs;<"hiXI3I(#CMFk0&^73Y9E!aU:m*27;!4AS`,X`K9JgWoa?N>1?a9Tq/!BmS%(+n8iJ#P[C.9\h6>1$O"5mZ?=L>UU7+r7A)g?g;)Dkcf`Acq+bUWt;aeqJe&YNT&U-^MUctE8=P@"M0Fs IZQiji)(!)3I%2:)k&Mef.MfPP2-b!\287:Q O43G%D^9T1e$/B6-_8JZ[ 'JKt&MM9+?&d Bb8IX-'tSaYlD8.=hl*Rck:+T!Y77.9I ib2EtT'^>A1YnIIF(A?QPAL-]4,jJb'g^f@[NRVO\bU)jTfRmX+m0+B+^O)+FDi*4IYq@m:#be*i"F^8N8^f^TJ!?W7$Ho"65r8@s12=X ZgBnWj^XhnL5i],M(#oFKs,YE"=Q<(2.s:0632=M_;Dbeb1Ka3K:I#NQZ)92HD1?O%e]Q"/0iWXY&Q8,7!HJnNs3tY6-($@L%^Hh8EHL(s)tlpa_t;+lW,]"sR;6(AX 08Jb3_VEBs'i%$k."rbc]Y(J"CnC[ES"Z?)`pQH&)P^T#V^J3Uf%:B^:1PbkacUf)p-T8Sc]AF2:j0W:b61-]N1khkK;^T-GD,1Lj`G\S93cH;?;df]meBX"@Q61BW?;N\>HJr@b6Uo`e/FJ+=>Gda\7lQF`2D@pQ\rUg:_M)WfrR-*a(:?\:BnTFNmO3)_*741ZFb9?L\VNWbUQ\ iNOY<'=m[!K4<:N&933(!kAQO+0ZMh>:<^.!BL-^LXM:sPMhE >K<& P$$UKZ3-Er`ZUO'Oc010APmiXmC$YYLmqDOB:&JJGr0p_h`U^2!Zi$O$+qqr:X2QU7>g-j$rBtt$:=st_ST#WiWG]Bh(m#U?86]Ll=[#M)r'K>Y(Yd;*Z@OPnc0O6WBIAWqE%ChqLXP"4XRI6g>d%Oh2c3Sl@FcA+]9TN!1)5Z_4qNR!JW\(*OHor2E9Z YF#ZW3%GOHbker*[$1[)V/l'oNts%P3Yq0hbc_\G:!%42PVKSTEXk)ZL,`sRD1Z>Ht]ioAri/5?oa:%rO%/f\+lI(de*J(!W[Y:,fF+3`T2I12"[ceY`4V&'#Gtn\ H8MPfCF"l*d1/4iHnaFoJHR7tG9rPtsji[AL: pY?'VlW;I"31P ;SQsd6<_88#Vt?#0q-gZ?CY%]D]nan26_$07m[/5'm?0>)^EI@q>a N:g^9DMY!#g%)ZmtXr[T6"[]WH&g#Ds0tq9;WH9RAra!0qPA#0^AM#s_&OM0Arr/Ng0Ym*A"MY`+GmNeHKVI#Bk4& Q:oG-<J@=KXRgr0=A3A^P4BnL>oWQe9t+QN#GW57cYNorf(ETGA(T4P(^CIF;\0s"r.T3QQ$Qn1.mk6a,$m"[6d@91Qrt%s!4.c7(nq[n'"*c0A^I!JoZ^BlUrAA;li[E-fC-F_chc>/IW,/VqFPOM*1+)(f=tmCBeJ`CBc1jAZ<'E"!pa%_Ig`80;/4H ;$'Z%9eJb[?W5NaPtG9T"tfC<=HRJhdRT2GRK5rE#9*>)5kJ8KD,8ap Ap="lA*c##gWa4A-c`if_oLc$L387$c)*TNVJ`'\L?Ok8lsV!A\?;?]46HkkRh,L>aV?"A2I$N60>K.06:4XZDh=6MGRheK(^]]EIID7ocQXN4B5HL4q;QS\>6qp,A3"G"GJCo"Te>5ihQ3`3r<(ctdP&!s)3ET*8&ib:1Ak08U0G`?7rg-AAN7&"lc,r?-6@%T-If4`m`/1Nq>m-Uq\hr\tl=hM:DH@YrM+n`(Qo$h9[[!6AsA7(JCm4J"-D0Lh^=$_OpM##ZRb5-&>iT-,l](anU0gdZA-=&-ag<7)glW=ftg_kRNQ043b%AI=r\!Ab6T&I!QCGQiX+[ADl:?%J,AOm#HF5Y6>/6Ls(U?lmlXW\Di?C6[a-[%$.Gl$&]9#d:#)rk`6Q`HEQ/ZR!dQr_K?;7/]>l*VAf;6-2O"#mFDfes+.%=CPbXX"0s.=C]Zhq%-r$GDC1]fO('PM*K>qB.H?9h8T0pZ.l<9EPlClV&_C:lPmZ*P+Q0\;c]4WdZ%==5Lm/BXMVTH_-d`::Ol*7q1c]A*NNWKM=-/>O@H$a1c@r.=0@;M*FRARei!@a:#O9GAAO%Kds&>ddJLcVT?IT$-AKATC8^MBRmm(GW\SX/WOIPH?1imPf(^!U&2A=(nXd&^(]XQ"AB. =KtFE$A,-8/Rkj^7>cYE,f?Je-AF"l,CA,jS>l`Z?&00JV$_X6262,/n*m+enS@*k1IUG-1f'C9QR2lG,\NcdHf^*N$JZB_#m"4`Sl cpW/6,)5nI;j48=jiE%4X_PFnH:EK"QRW?HZt-L6C#?V6ng iia$VRY>/X,1)C6*aU-mO;Yp"`Kb\oI>?9.0_E3bM8F)%3T:=T 98'L^C2M,'t],;*2d=(AJ?AA7LL>)+cp^F+5)^?Z \@b.#E=m%WTs!3?5A+Il_aA)*(1H>]nC( [o9'5b5%Bc!k.I-(?Ed/Gn8:sl-(Z\LA irQ+LAqelk@EJ!C`:":bpGCT-%Wism20#Nkm0lX@fM1*XR.Xeh4pHSHn=0HUL Vf1_r._85CGRJZhi=Kf=:a7(_(=ARSeai-bX "*&9TZORq.62:6DcMOFA(=NN37F]q1Xd)W(^L<Hp!"DQAgg_XTqP/(0CoEDhR+@Wnc"@2Wtod;\/moOnlSqf`VCehK]cI4%5&=`MN558%B=0E.s&G>5mj<,CZP$KDAr_[0kb7b4K"i#>= "[46g0F/0pPWVpNXUHgOfiV@&b=r* %s2?([p*jG7&re>C\qtb^_Y.Y\KT7GS0@m<0E6766[?_(c)H7JSqT67AQd3&0lUp4.`jiQ'41[,CQe2LU*.,in47K(`d/$C#"qCDHs4?L)rb4,H!]Tn7Wj<;j(f`rI90'$HQL231/4fq3A"cCd]Ob-HH"9`t?89AhYoDV#<\4DWdo0;9PT+9ba;E&.5&(s,,TFOGO."Aq\gn3-r\5#a& FAVPE(-fOUcJ$;*JZmD\b1fZR:'2'dS;fkfEh7B-kqL;FDp#s+[T'tpAb+cMk\819^86`6@'@k'mm!Ci3J1%T; p1TgG1mlKRe:C>H@N&lpR>_2'RG-7')C 35)H0R\88.5lFP0EhdH_FRPRRA/U*7op6c@HrKbo(_6InOgZOL(I"d12 .7';]bcB=PA1\tD^J7q oo$"`"=AW7o5M#PclL?%Y>9P+/+4I^[k<,08C\`o!=?MQdHI]SQm$SGZ%r7LWGZ_]Nm[G1Qi9,Q`Y!bUF5o);(q5rdohKafk-/)pi-Z/i#E/1Fpn&3fXEAl2$gAo%!9@*RDtW/")#H&jF!o$4HZQd(k#bT5]1qaY55B5NX*qAkh;^JAdlUt]tG.%AK6)=G>T0Q[Ld+$M;-U5mE8jc7%!QUiNae55V"1LMVqO%C001oeA9\UGglJ2QP>,]j[F?3bV&_X?N>$ mZY<\Af06H.HP"t\*a8!Vck8PR2io0\9!?[!>#]lZh*i/l(2m3%ZkF513FWEET;5f@?OhF&t6AKbYOn>H2g,$[\F7Do9-]dI!#!!=3MO*])A2L`Ii5)hV]*\n6;L4IDPgo.Rtthd<>HN<$:7@K9:!=\/0t'$CPsc(lF?jXTm*gA_5+X[X)d@EOnQjd8f'+ho-P7 Bo&02Fo>BaU<5jFKWrmm*3=9:M)U6MtbAX9_;cq$8eWP+YZ-VsB7_ZNntt;!HY5o0%NUq"7Kq]D`r<!6"W7$Y2P>Pf"%!@7Bj?nK.t6L%(H(:r eJ@A&)sjLF"OI/f!h#rS%lPRV:i3fhld]%\*;C9PTAJs_+F+! Srnq]BHjI4h;6AA&,7&j];Bdl;]X]Z[;H+.IC.537HVN.ZM1WFfK^o4aZ4#f:.Cp!rK"n+Q8q_@+99&AEILR4EF1*kV#Zi17-M`+#B-%C(I\ 8D`9EkPjJ:t@\;LAc(P6#%em7NMI9HhmZ,]@[#lH.W%&ejsADRKVa!B1o%!RXJa)%98 arX7!r3!f($ZgAp%d:$9;8%Xd$1.a&kZEKbqS1 *TPbtBYQ\fY!Ct\- bBAt'And8N/Z3elFBm*J/J5:qY)A,o@&`f,q\Pp.fCZf\E5JB>&\`2H\1TP4Jj*&IZF`7"h7MgNVV)(Jg[2HC_O)ipS8L[^'K!lp3re'pN*E"$M!GG]_f-Zh!]jMotT(32."?4;=o*"&Kks9sBRc98c=gGCGoP_=EA0R&B4;qAQ>95+4L]mP>%,$(6=@G-GO'* F@l>I-q-RqFB>?8@7<4Hb;(R3Jo[Za_dIN$=I'W*r-/.Rb&.WK*lnL`iVrlYa(GNh62Gt#Z4L^L(o>pkCn"oNI6sF\%0U[tLrdpq,l&NWt4giAdE&08K:ar6nBh&kH+>,5O:EQij+M_[@g5tM%TFAo#^naVFUEX `cEs/Fo-D5i(WNQL:4`WQ/&#LR%%>t 8).'fUYtMl?QI/3KE")l:.7)J0)Rr4p$Ui/?rV_Ui%YfeV9i=lGNb-I$HmR>q3(kdPB`LZf"&*%+"X*O@>nim?@nj+Bdd\a@i7tne0:hfH7WIJ75M*)?FUtYk?GXY/I"GR]gl/th[Liff+Q=hc.U&p]r<7Yrl07:T=\:(A1pltB8%dS#//>7%e;K_""NbN($:BP-i.aC*T?AmY-NM"_oDFrY3-pkL!EkM=ZFes&KC\/+:b?iA-KHX"AESPrS(*A>F'X)+=s/`!pPje] \"(EF'Gc&QT]n`9CM8W?4kraj?*iYB,0[FTt"3#@X(.\VHE;20 m#_da\(c$]3@CS?*s<ld9Dj^AW"k0$htA"BDK`f,/B.Wp=1W)LaA'Okjs)U-m L[n3V@[<%e3-gC!Z)+_f8i9p.'p3 #/940)^4&P1SB#.66iPVn:T7c+/rtgOA-CaV$%8jEc$ 23QX9j<9lC[Y_VJp'1?l"577%U>>(HO?qmi\^\HFeU:R$Ik:^*C@d?Jet.3@`=Ws::id[qSspkk6He;"kGSOpl__Dn@"!&9$IEUQtUM !i:X'G\LDpeEs:h1g4PJ]GmO@d:lkc^t3(D2WFM/l_9L5Z4#,/` F^&1:bXk9C_0jM!bdcd.j.1?s8O9i!Wg_P8=W13AMS+"MEf9j-'Q)^,o$hnsl@)d#e>l&+Qjh%hO=X_ZrARVQlT3N4Y![N`7,h_VXkEnnP`nTt\!\7!R:QTEK+'fSo%)kD0:#ZWe=*FO3Sic]i`F[W1)aY9kRIaS`@1_H<`hA9.#+.W^`V)Yqq2Hn7f:.2;a PZJEKRJAjQUqDYU.`Rm4*LX$Z >r[!R2Y*.ROnXYk?+]JJ`H/K6(G+(l0n/)tHFN%$P,R5_S]B?(AZMH OPbCX$*)T6"YjcMQI^B+; %:@\&+A$KTVB `M+)<@TZ;7$jggJ@b]V*[.jp3;I)$" L**>X+KHgQ*N&PDG6C[Ccs"MN-gl;jPbg)fdR+^_Ds7'`UeMn1,@a9`A:SG]UO]rCqXtQ_C j>AaHtKV,$-cN@D[O`?-A,nU1#!1Zd!R7nb@ZG6+6P''^ZhCNet:lR";8&l=3=6m'p9lA7m=Ht&g,?H"A`ah=qK\O]Kn=US6cJBAt?5Ti)Q8!K.MeNKn`nAU_Dh)=Zo_,R:>sQ+]O+tX&b*Op5*N__mkJdO*-+#n%3pn7?E 0A/pS`V9:VCi+*40;nXU[WBG]t=O2aDBU9(fLUH`AK(TYD( 9JJ/[#Cbm19n'3H,b(Ob:rprqVFfQt; )b&@WZ(tgah#SAJo+W%?6gh6k+*20T;Dh,,XpS36`4"6DX-nB$7lNq&X;b N,f)T?9lbGVFFL$B%9ofD5\5o)CtthNA]CWLAn67h.VS\Qp[7++]s/iZc,ZBJoA1j,C,A#NIBr6&!H>d;F37(A59@btq5./1?S;.F*94=?6@PCIln`M1AaBoge7C18K%JS0m8_D;ZQ?W*4l`1Qa^ [[[^SG U%ZMXP:.4>FpGV('i@fZ`bD8S34<Q';J(")%BkV-jk2c?RljcE$Z"!FlS/( b&k+e+o(3](Mj=jl#is4A&R*Wda-UVGdA;NpS/NCB=3Z_m-+fs2s1C17;qf*]k:*EYe-5)oAS=%"g*_\pXGSAb&doD0.f\SUjKO?13_1+9X[\=KbSM!0B0C 5PtgN( m?%;gP7rG"-Y8,aqtBXne5"_7!*0i/hG&jNV7V5FEGY3TW=L$^O2flhW?7.T1["^Ef+fk=&h!JSi9J_+t226p>8K:`[l^[&%AOI)oI1AIE0A@2mNr*MKAP)W$>l-,.s$614h&b:hW@eWaO+qS7/`)EZk=P)@UtjI)6G^4DiWRB[GpK)=:&YY @ElO5-P+%BV\8;_H=0QV*En\TG%_YM@@7,c@%[3TDLVNi33!2i3-p4UP.$i-653qrVn0&A0F(n5tPm0o.l/SWe%<(9$pSDml_9JgoY)\SQn6:b_>TY&5/9_BmY->iD!@n(W!0\2kS!928^B  Jd%jKS?l+S% GiB$Bk(N74jEcJeHF_ssI[&E3T\R)NE0iqRk^c9>t H3MKKH0FU73U(MU&V\IW\F"A%5";[ri=#A`oPY$=Vo=/%il;!A\*D8_dHL%6S)Kk2IIXBBY]3s9F)H!&$ahAOhS1?18SY.b@WX,.\SJEfbI!78Xg!U5(=N<)iYWOJRQAEIi%s!#CN_[/ 0#aO\7@2jepFrO\^ToBUKf@74VT_rg6/_:kZ2R?,si Ks9_oZFd:A/@\^r'@k^mr'6$KICk,F$;@P]1H[fZrfpWFbg*,f7[Ln$4m.+(;3i:]/A 8#P&fU/\ZI*\O@Y)ai64fi"#_G<@4N2>TDlRMe-o$A&a=l9JWtY:;*5*L.>'rID!qop(R=f0SD*S"0j7Sh!@M@HWkOBb+QHbL["*.#eq3,j;Ri8sGq:#6JRj)Z4?m(WtCZ@DHo>W$<(=mS7*dI :.f$X51B9U`"d'QCCr7s1E_,GfqS)N4Q](>[:4m14*k/'oW&g")9i>F=mZ3YL=">B$=T1O=M4Y@AdaI7\)23KEcM%-B5cQ'$lp]g\1LLm4Do'I[[+[.KSY(hj,[=A'QAHtZGI)iSB8.O-pDH:K6Nqg_AY,aaeWo;9&.Z6!lSP8$WY?%Ucf*l,m=.J>X1(+=ro)$hWSRY<[R*ESAO@kYE,+ZE=B12;UBgB[r.`HektD.RXZfAd=6tMIr0mkAgXrBbm]%hJ$Ia>?]p]>.5>a;8!ZLoc-eC(KB?3(+^o^to+Pgt:LT4Y(A 70sos!rHMEpW@T [=`SA-,jTCB`(HbKgY(!]S=OiPMRDP_kLd_V\?s`^* a,OXlt>i+6Le`,t'^_t[@1,q:dqPA855MEc4&m65\1j3n.+_J0-V 1jej!PM4LYrW],HA]3GAtLF*c%NpR#eAK7W@.CD08 .K-4QeTlr2A\R#P6:t;npdCXPmE;=M)H.Ao2ki.Gk^X7OS?jRr9I4D cg7U]'e69-f-Gj'2(h*.js:I%FpTdhnfDI MNLcQk7B+XY\AQWZ.M;&N)l^W9g*g1)O>cIh(t]l=:g.8MNR[^^HpbAEKhN_VK>=/C]'e@TKAiigaOjofP"UTKJ4?g)N,ro=C:q:<=Sfg4pO#BtfCrk^4*<$M_OI6>\V)"m[8?)=9K.!nH_\@,[J\l&$o4ZS+W_32GH\QKWpRSPo\9ST>,*YIQXj54\O<K@R9ocIYA#a@n!X8+IUq'Dg>aWT+KqQg#rCIpL%:/^A/Zk0!&QMFDtt7ceOoco(0Z9$o:1EV,bq!hT7QjUBK@FRVXA)b#FAG<;c[Ad_&R41&&P<CcTR'taj]EF(fCsFb'/$Of?@1M$!(.'m:Kb`RAXh[X9IHp/ ZG35b.TZjN*!hb(6F+/qUs'@A04ik-#?=YWgjc'Y$)47J*>">oU5nkr'tNTC&bnc,nG*!W5[`8sfC;aF+tTG8t9>1jIf@nOAaEr]DU$chWZ61 )fB4In+i<.]^0af-pJ/C8RlP(ZA`\mP;T4h"c[VMr1X1%fmdpk)4BF9#i&*WbY+A OG;2"V'LML,qI>V4P@U6H\%$lg+D>=B(I?-Q+-$Z&+#mL8f UffC2&RTX"hk7eYXi,55tjFO41th)'T*cSD/\YDiRmJ&4lQD]rrF88apB\qZ[Bs!OX64<PGR$adA:GTfT70q[W*X^<0:S_aiHQsq2%tT3]HYs%IYU'm7Ke\Jiasl258g>L*9lPXApK`SIA49YYMr/D;%*1]8G1j:A#o*MP?N.+=4n=(fW2KLhMD)CQ000_A%XAa^n?a1!ts1sg/V7Cp-:6[fI(YQp*i6AJtf\):mj+)`"[G=P9FVQJ\H"LDYi/<\I#aKdnn3,$eeltPj#iEJYG\(R[*.s&U!KcS).Vm^tr;gA$kc\P\?=+AhU2%V<_Cj/KS0sZ4^QR]pVSZD\:is+:-GUH8i4HIJj7B:tT63-B_m9K>ChXigVt\MN@BUmBDig5A)4?;TjAPpW>6Ab(jdh'\!lF&IH,AN!Wbq E&=ZeNW6:ci%"_Krid<\`No2Vq^]KG>RW'C63MXS1o$(jWI/J>Xp5=N4Ns2S4d33ifOM1!A$&@4VU$1&#-btCrgF""Ge^MR@TD6)Almk!ZgqKC8OgppkZJHl6ZL tR#n,31n]$i-)AO4)LKM?bVV`b[*A.k^R8 9>/ZV+pP(XNi),k(\X F2)T9;*?$9K"-l^#K``8m<@Rd'\LCGqshA9FJs[2Nqiik))Ek.M fgWa[":])lE ^igSa+'4FQ8?O*(DBWH\?8L1qXY(h?k,=i*/=_]l$%d$*cW+5KP87`6RF#c,1r'K6Sg2=&74Yd@7,b`4"95bD(e'UY)YR#kX )A*9.q0sl,j)R^(O'5kP7!jMprGFM*!r5A]BJ'&pkPdeO@Q[B++1KEPLJ0`1MbqoS!GgCZ]-)aDiol)cq@5bkCAn*@8 s-JT!R*mo7PX'&]\A&Cm)F8!1+a!rpK6#dO8;0:gC$?XEb6N.WQTK;cS%KF0*mraSTAP-E[aSVO@7>5$1E##aD5&,aIZTkUE%#9W]C.5@=8(/KHW/t.iDZ]QQ5I=ErFf)HqLV_J)#X&FbIh*QJT[A_Os-/#f!Qgb\!KArLj!UGN#9gl&k3*X3/g;:n`dY-!Y&#RZG8Klc+PSQmQ:e\BMCgJHQ\Oi!jVO!-6g@A3rmb\pVq*B0@5r*ktX\BAdl-L,@@GjBGS7AO^.!jU%icc-^+@!!nTN/E#9)1"m86qQJ$)i2^"e>4*h'&'=kETF-3I(=5c7,bqY5Mc5c,'R!n0hr87*phBM:%t(44jM(!F04pg"-R]DIn@"d`'A4##B;X9d`,R1S%n boGUpSY!4helQV8#69MQRj.(fRJi<;'oIhK&Va@g*eo/k^3O+9tOA)V>;gZ*M!CGYoA^Mek(+p0M7AY9ZY:sS)&7Q+(h+t.NRqX %`1)dh4q$.Ib7s ]SGKn[Q0h]mm+G3IUS@/bq$C%<#2#k9scGN*V$/6gL!Tf@.FF//.r5gBY?9D[#mGbQ+paH4rlVGsXXBqJ-E.ZKeP0AKQX(mPh?W_l.X\I@UKb"rHrQ3n*5nk3L_jA&4`@SkL/4f&,UYsrA1\JU75X `<2QeJ(4,(s*SYAO5<-tNh>V:F^p135lAmDd"#FA2_U@raXOmOqjT&=IdAoa"88UD_5e*=7Yib-q=ier1/b>(\b_?%D)kh(A;A,9Y8ob.WQbi'S@QsRf`%C@%F]qsbq-e&il3-&s/`riH3;+8M7>amMpJXI/XoHAkPKpXJU71$-'?>eo:XbD^N>1J]NBq:Xj9aW8L4"+\f8[r(Nk3AB2Ca3:9M>>(>r3ZP%S7K:Jh5'_)JiQn"2_ff6>#0K/hh2,*,dUbS(UhFeRsr"ZO^p*qM'BW9p8 (/EOjJqM<[pbme&L`2XT/b&$ 4R[GI8.6ReDO#/HEA.2Md]DH0<_YqiF;]mFEX?12oq,NnE5qIV7mM, k+a*)D3SQY9*9!Q?=g[m!mTe:jmq&jAQeCad4Wo^c34ttXHq8Bf&_*11a90K"$Ti7V-LCJ$_\XHOUe9';=>pfk5TFBpgJ.\<BA1RhL6Y7^tP6=3EAG=JlK\e<Mj^a6c-[d=VG/#L-djIrjB._(/KosS>`)$rV#[kDp@M@%)Z`2MQp&=kq-T*-T!`.D7*e*_BM:oA$`O?/,$FB>,^7Rb<`>?QNp0&P?HH\6e\ZW"+]M.N3GfLPSJ,&$UHZQoT3qk<7r'RJD9oFYcY%X*LdK5l\M=VVG%Cd`1V;0AV:/@.GP@&;pMo/%70[36V@UbeR/bqp(aA;/8, h3cYKhm8-!X>`Ak@.=KF/Kn*Lr9A2HBMb+Ma5=6GlaJJ7D)VNsYn>kS+[1W!rF-2=/LV(7ee-LM%)b]Xf@?MknFlJ?6LAbX.H7toG'U*ZhALkX>'`/Z:O7Asj29LgT0&V!+/ABRn=aEK+qI\,oU0sMsfo0e\[YXY]+Spbn67HIJOfCgJR3<43tZC1KnJr=f4fr:.#KRfZ(M=;!k;@HT :/iZ_H.HTPn2VkAnn)s4A1'Y]1iV5#,mI=m`^(4@+(`^%-ia"oh<N:@Nttel]\]Oma*LdIdFt+O6aV/t7MJ0c&8Q%M`attI'R0ij3hasMh]VJj?"Hiq'GR4MWn5aOt-K+DWJ\!\mn[?LXWA?MRs9 ][%Q7+=ZfN>6!%g[_/D&;8!':E1NKG&4))ARR-Ar6=)@Q &&)>/f/=SLQ_#,efRaiKj:*4G.8Lc*>*BkJi#bXoHQr&^=aXB0\-m;?\^F_AF?r5oA\EI`X23a=8RZR3LqN#m,VE5+C,"Lhs*mrmFKG^(4ffII==VkpJ"f)T*qO_ja9,\J"-Qt$"AClXSUTAc/t[-dR/?&fV0E3r-D% ]M;SGmMo>h[H`iA%a@.N\D+eh@*-`Ap##HP&$bIY!-Cm14pK7X@T)^%b'bF7M`F;)Lh!SN9FTG*dY_rT\pK;8A#6lINMYs+JGn9Q`?-oKWN.YfE g^?#n@ZFI8"a9:sc5$tKmD8o-;CRJ92+Y[3cAWNS:Jf9/T1#Y=F-64BiIRiQB3qCbIUXX=p=DA*/j=nrPcOsf`Ja18I7R=_(g5mABgVD3Y&*>JKP')OWdVkC-fRrPcX0KMt2 C`Fol[nRllZriSWs']A=LX<3RPV`?cBfY#-A:#F?Y[$Y$5.@2sW7T?L`$;QH$$VgYkr4B_"eSC[a36dC[ cT%*a(C%<%:X/_R6Fq;YBAgd 9)lUFXg$PtnA,"EQrAq;:Ss+tA"tF3VA^7$\]/!*]2+8/ ,0ES-1??Wq[>_$`;2kf8^lt-fZ>h[#5G>j(BNG.'Xqk]?n$cLOOLhU2F?W%MOLM%JsHp8GJ$VO=3h3P/*fp1)hl]iP"32CFGM@_$,G!`KHh#d0L"5EeSn hj'.3Y06q`#_%Z[%7PZoZ;YgN)b^@&'Ym_,_l_q"#)gK(#6U`k7W,ie/W_)a/Q;r6bl-:@2c]KGGY5WW iKLZe)WWjm 0:;Nm[dF/$%U"f:DoeGgRmY-Lf:tf:a!7_>G!lAB663CedhibAW+PYF-,_"26:NRO@:B8;>dBk?Ej(%NHQ_2:p"5aR#<:N6+]b3J4$31\a`B-,B+)M\0Ramq(XMV>jNKA=Kp%lXbN+E;#EbCHsaX00jg.iAXL:q?\L#1UFRm_%K]h,C%9mo^h*Q,14#^+Z@m8]FqVtFL\BH.m$t8SqGpc?nHLlMJ=@.SCkXhjE5-lqg= BI9Rq8PSf;LmfJTa>jBUaQ,p\,7V]"4jf@dT+,T(r^B#)gk3*FR;'*mq5!2)@N0AK/.`^1tp_p^VZ1,\O3"S]qO9eNQRo`L.eG?/f7Dl.2nZYpd aW8o03SA%ZDLNP3G8*1<6:*hVoJ=TrVa&!t(I+DoLW6h0tkmAnehjg+>UJV ]JTBnm ;hN^l+)S.CG:\j[em6m>;TK5Y%;p=>H.8ZedEk=BN?\\DOG)PP.S-!lT@#&HB9)FOII[CO(e0&JLLJ7V=d(Lr:=dm]p3"SL;'*_O)"6V897cWP$s>Q*I\G*JHZY6/9c[/.!:31'mibAEiEkRa_%]d+?)bna.,ZIf)cfcChc;gFc.e'[)6.eV#/itVK+:Lr0HC3$Z4*oLk%0mYLj3#DU\4qWqNBsNS'_B9d-*09U9),e'>bYi?#&dAl\X(7?0%eRQ:V*hDeI84n"X1a/N,ITr5/N,S2"3Pm,k5]s5gf7WU`NkNrdFd(7P:,)(nPD=jH8c4ksI/<.WUfE=_OF7Up4H>qic<.r05nsEoeXfgB2$ ]MVSj5Hj=GsCs"\hA1>c:9Uj?%[Y=<N6*`QE*L9M4K'k@j!eYC/KDs5AbA/-ATEn5F*tG:KEVSKsbc%TMC"tV]j!LA[8EG*-i^TYY),3hZ1tlKbf\(Y/o66iNjIW-_g."piGg0kT7IlVDo1e$ai'iJ 1k$Z%gJ 3n(ZmD1X]IZYZgHj_"hP-a)N5FCL9c@s[j-9SF-RAeDU)eL0oNT.\nXZpe$,ZHH-:ch:.6:P"cL(09m#L9&g_F)F`kLBfC+n&`MaONb\L8&'XOjW&A5V!9FqPYk1:i9*J@1/=4jA^TCVaLePTrY]2IlGI?SXRiA\0loHkLs?`O\8&?<>3!?SM3AmB)W>oRDU$[2k`7_>Y,a,+C.e":sEb&fTD0EA5.XdX2#ZTM>$X93b37.*$+YrFTorc85839WA[A:7?4>X`VIN3`<5!ZH\h^4pFA^JAln:8Q'HFG`jnAnCRf`8WHPF]]$k[B#1;LHW?)W5IS4@C=O$4E"]4!Cl2GpA ^Cm/tJ *?`6pLMkVdd.iMlo#[/<l\b=JZN$S]G]#Ee&/pd.#16olAklO:s,1e+9d2;SA 'j@VP3BEFcAUh_9Y&Y!cnMsh3>af]Jc#Jn^tn?BefEJ]jMMkWIh`]sha.f+e< 80^_)6 `G0=YPUDm_Efb*\&*S?Op6kBI;Ae!C)-(DFT>2iQk2tOftCQ!M8V(>S=@$RNZ*n=ANm2B1kN#I)PC\G;\aEHjW#XrRo">"YFD(`pU5tf)_T^8SLUZqU#.2C6`#EpJtZ^KL\.(n/&-0WWO&mr`1RAF"&LtQ=`i?5opDmm`Aahli-r,H*1(32^Lc>n<,]]-^]0GRn$l5j_N#hr4;*.e6P?-$+Sm%PU>9as`Ls1-JINC"eFPC%5sATQF#,s`I;SRFCN@:- C?R)b:tX\:iVpK<`0FR`].7k:KmlBjI[,Kq"@QGa*QK.mkd$CnOp$5WW@GqDZnJ>p'E4,/j[_hX"1@)O=A>`-Qb1Re+b'!': $kUB`bgrrJ`&"9V7e/)i,(:I:7j5gh \,&I5>&h/^C0PctX-3s'VAdCB6sO(F."4:OL50H3+o("=n.AU13=OsE-Y$8a0jSp+!3OS0Kn%TY1VjAGI2EcnJ/f,9?RRWUhd^AHAcq=%NF"c_O6\5>lK<IKE"!6G[/=OP!)K]mIYCL_T*U;BmBtV3[1j%_t"OI"c@`#Ib2mim6e*#KG t3Xpsq\MlB>L45A?.jr0B.]XRc(?7?6MB0P1VWEc1n!'/N!75,.=!D>92_FPLHmPDB"qrJ'BK978B3g.6(Nh/-#\"SsokOb>DcfJ^eEa &.ccAH2_bdA"")'I)7Y$3o%@l]RPrAogDj;60"LXpE/VtkjV[%4rYh0NAs\a'_0/Uc(iVb_i%?>[GTP\5@9%iiiB6r91qf0At[t$D-_:5^M_7g?M_ZQX][6OMK8"S,Um8@S[Z3M&;ZYT)N&_LA.=c PAl5A@(\5jB(8O!t% c$s?+Ga?,JjP.,#B_DI8,PPjK+!e"^dqNKdd[jHL'\/_eaPifs[2CiG^nm:.gjV`&qak@BJ0SRVSQhtQQ2[A]?]k)o`lln\^4I>6*SfJ#tc-'aqt7+?h-.Xsn!B*AKV25a'NH,j&YQ[?)@PK8L'PZDPtK>n)+F6^Nnj,ZrfpjWg:H+_*>/6K_]a?#mn^dAa:8tDLa3hi2_bZ@rk?g9%a^s&eW_#k!9Sr(mM0CQ2Ot`qnBfR2Pm`8hq6"g#E9XNF)th%(IH=^FM'bso!)n7Jg3o?\6mQ#jlI0GU5G+#DmC(V;7@(^gs(t\mJ*V&\V\@Ed[b2[[>N^;#SIWj#Af-cF!m,=1Hh$R=VSclKEqnom[0,QV-s%K#!g9G;4o@c^?;D,jRFHaaCUh-L -4\6TX)`\IB4:4(+Adeh9CQf=t0(tO>n;C@Nh__?Fo&Z8]TO:hMf_+B D8?+=PA*bE<M'6@Y!^eS:G`apd(:5)Q>[JP1=Hjn aYs>SRl"ITj4qL)ILm$i\f^Kmg)atqED,]34Mt+IAA,%Y ignFm3&[4rbl6#c9+aW9/R+HSXkAA'.Ij2>1(OJWF24H(SBY^;V1%&Ora?U#(mr]de`@&QJ&(^Zl"9%N"`t_[]E98>c?sGjo#;nd*,kW=>r_Ddt!Q,Q25FgH72eL*fW2f7E+[hihR;bqmDooi9`jiLm)PM-(A:i=D2%P/MB)k@'dTBLX@:EKK4`A0"A)`1LmBr U$ql2)AtCmUsDiAVAWb8""#kV=b65,&CX!H(Da7sdd-<=hHHo03,OLCcC6* \?(_T)47RfWfPYc_eZ&%1lj"0W/?.=J?M%orZT5?9C;#*N S*4l6*R_70:fP>"mlEA-#DPXVdfF>A5JJ*\Lk&!.@CNtQLn74,gN_NK=h'I`RAc'Kt7^AslCRjMGc'j+[,W6$LbUJ0@GLd3FK)]81&P8b]DT;@^7??c:NA]8ptTrR&,/eX)I]MK&'q%TcPe(TaV-er!'3j.iXGAmdG3$GZ&G$')>/AhbOtm2T@hNq\\sfps -L248n$^ALP]ho[@1/.ZZq3IWG!*2WXPs%[S-$**YGC?($A-;.G-NOa>B&)A0_.`Cr'QlM_=>GA(Q%Crtn_6Oi+pj*iq@eX_As'nS U[LJtt4p3Dn6FHIY(1I%D4\>r78crA)E4aD#\hU!][mh3)ME5bCo(OlVLEU35q (fjKUlBq^qCn[%N"WAV_8Tb-EA3IM]4S'-5\phTYY3SFsCn'( F<TWXKhQ&!Q,Nj*!o"],M5_YfG6*EHcZ=P(SiAY%1CZmnIfeA;Fb(hIdH3WA#$?mHK@OFcrF<.pBUQC46T2'?qr5`>l<(cLB=XG#rVjK5P"b9%bJee_/_AL>D_Oa;XZs\ JFHRP"n+.#AY^.$a1p'j+;3@Ho4^)W(C<;J+PfKr'DW(qKn/L^lB@X`8[9\.$#i^,)RCE).`gMXC?p_jh`.d5$Vb4^h\b;Q5LY&&7"BKkn ]$^-`+S9M'=!f:Vh643P-OraoJQnn*@AE3n3%kcMt"dh'CRBK',l@6`?Z)M7_1*3gg)].:Vad("+gft$T3aW]q+3o(d/WcSW:_B2#e@n&mq7N7W09],V[Hio8!6OZ%nP=LjAl"]h1@&T`8XDF-3F,%MD=.Y[j8#Wj6>=8;2nLO`93V8HiB3GYjW4CBdeI<)W(SZ8cm;SCGgC`ZK!$)Z\CM>W!Na/:VK`MA[-YdoS->HZ5Nm+^R[W^NrOI-(c)J6HCC7e'M=-DaNcPf]4r;rTdl\0[>6"\1)kHV,IoaP2\F!PJ2jL1G-4Y?)ML"a:G^^/EkX`>)@_#r$TZJg6;A7YWf+rJ5hec<&FJ@?3%;]GGmB9DmInjAY@^AE24MZ2Sb#(:!ke1J3mU0'q;AM8XHLgrj3<&Z-]l!M%2A5.af>ZRh!qLr)MJn>>0bbDLRR<[hq$8oi'2h.blNaY .N'L/'h[&3*\Onjl/LUoMjA= FQj<2l4[>JGsCM:`Q:#[QL9/U9V>LZrfl%=9OAtLg3.'eLrH75.:Nm,i>Bd7 3n<2-q8p=?`FM"Em6g_ngd*WND4PtcgT)ecQe%d1"8A_(qPr*iW9N#="aBd8N3bKONV* -p[^^h`/C$Oc[b':)#W3>rBBtQ<;giCQ?/kSK'j.gMK8i>6`c^h$6rX>,2t#^r$6Ai)Z8q^=8tr]BdP!WAb*5=[J]Fl $c#Q*JPX\^PnSB8BBSZQ2aTH5qT;:\$en7K737i'C.14gE\/ FK$.`6Ps>k@6+l0G^7fAmgEb\siM4rVF?]2X=Y'(4]O)jBFdVQ#ER0=.BZ,scQ \;l`>Sc3Sej^,YRk+ka%l,eRoANq5+E*$=edWYdJo<#j,8]YIK+t/&6<5.WW2& 6J$i4l[gj.^R&KtPq:+\:AR:cpX4M30_fl77Q*j 196-t9i>PfNLh$/#&+-:tIq__jbj@fj@:.>e?Ysd?=WF`Nf:mSM.0he25-Gbb3s< &Df :$OJ9X%gMm"=`p,(otl8II&M(kn$3M!UI(M\Y'/Cmrl$@AE9 _;cip2JS_e4plaNP)S(9;76Mj]deeSaT.[2b+ZJ1A<oh_/t!XWI\Ac0#@_m^aT6Ng@0Vl3AscN,ib65]4QoCLg58d)g<O87SsN_-eUS6#nccYZrIdO(&&qJQ=J!T^2;9)d+0WXp@E9/n188"eMrV4`Dt06]dY`pX;hE)!PlT(CAa+.MNF3C@CCG<71rkh;PN]Co0VcY%biWbOt]tLB"__IU:L 0? 'CS5ZlWbAlG#$"Y[7rZs=4UiCPKiHQO[ai`Ocl-/R@a?FSFaEJ>%>:qhrPK7O!qS;#EI\,Z(A.nl>r:LY2N47la4e]obrh@0k->>sTFQ6L6T*$AKBJ43DHNtij?HMh r#d.WLOCC"@LPX`-_q1Y3bUHA0<\K^k0nS0O,?f[lM'Y(tBM$2A4Hq-F!3X+,X\"MH?M/6G *NTRg\T[ol5"V+(T@tf=a5'g1(iDWr?9b^D12@6PX1a!C3B.M%PmMNXI:1k9NegL(#9D,T]c;ZhqWj;:[CVs-nflL+A\:7L:1Wk=1e+%4`J9go(4ap9h(trBJaP+3!]LJA-e-lWMp42AfV",>7(5$M58/_UAs'9m$:,J@Uc8jefpVg@PNXiF/b^bV+],1];Um31DAqk"nE"OR)VR/^nN `giO%X 2ZX/S`&rr5\6Wo7ZN3^!SN'nq+P!$7S]H`.(&gAs!?V[6:GptG1Z(Der*Rb]1^D--jX(gPGZ4Le<C&.N2/no ZMP*IcX_A^rOeOC$To5YKg"%r/+-%h%iQ>^0Xl$\dX@I` ]T2h$kFhcQsb/VjV<rF]D$!-Q9BWfQt6V&g s^O,."(KI4h+ARfselg[`Z;WIeV=A1c-jfNF$s6$/3\ek;Jb PHk-X9WpV/"JMT1r4/iV%]"UDg7%f/k#N\!ioc2M;CN1:4!@+XY4d`K*&/Cdjh)KO5@YDm?8l3*2 cnSV2KYg+-S,?NEAF'7o8gE]iVnYNXG9mPb]g [j]1(>!(l1]j5`7E)D.th\X 8?G/dOP.)@)GRSn(EW,,<JAl,,"PthC@,(Ttl3]S+2e&%>.j:)0#[1*kD$]!+[SA8T@jt/^iA,AE@YQ*a/[BPH+HQ5 FSG*S:,BiW@H_MdBK76.<-k75-AR.;6"PD(%0INhS7ePls57q;J1`.aK-E 7_W.mK"[VZlAEPkb7kI45ibQA5LonVs7Ds2_!&;r%G"(!o'FPDT)NAbg/.R7FR[ll.f]#!1eC<@YqiCf1q9YsRA5@`^%EfYcdCjA!Y,6 IK=VOm&sLmA1kkC6eC!*0&e+L"^)pdKQgXAaXk3$mnG(43KDI$Y-pD+h>oC9F`RITFR!D'oX)=OE^eO1IOQ>%Q[5QY9O#ETf!\dc;Z85KXhpALN#4g*.Y q`O5I#XUh*AUb]`R-+TP[@Y+bm6n,N?5`#-hoDn']>A[]Ar?[r6tAA*1;9q/EVV<3*>Br_)kk#n2HP9j.8#c+B8\38($=M+';<6e4SL4"1Nd&.O4eVkT@;8;fMXBrj%bWCr[Qcj110"pWRckp^>qnB.X*cm`S27'f]\0 "l";j(Ah.CA +$R%%6.lk3BPTK;T'aKeY28eQg;2%:bi;5EjP^PlDUZEDQ9 Y%s/'AO?s&+4=&ddn24D&0Z$D>%W#[>&-nAgX;78`-5hj?^GktMm%W=,>KjVV3/a;ik.[@=BoF\+fHtBd3Vc'Rrpm&+PN+sR31AAj@kf*mp[IieK9OqS\=1NgFG5d?/G4`Da&k#!dr3n7jM[NQC>jk8g!5Ie__3"7)/Brqmk1tFUhXKi&q5[9UPdt];$tiMWa'l8mNDZ?Z(SDUH\7N4$F5Wejo]_^J7AngphnD)O7Kk:$;jKVE1\aCRL5aJDW%agA*les"Vk3$0pq?dLfi#2*'S97(Zg5PW*?8m5rjkAhhjd9hk(AS\mB(K?i#AYS)?P[9(bj:jEG' 272%!"*r;tD>"X$/i0A?NJfp`n?dIA9>nb\1TOhZ:2@l1Td?M>H#Q*)>1$@nb[7XhGZKln*7K%,Jb@i4Xl#,_sURb_Q=eU1P()+Xo_N&ON(koKO45`8 3pH_-30HH@K3bSIi7UW*9/%F'SE7I?]<0rmcA43mj*O#s-U$ZeU;pTV[lYbr]$O11l;_(*.D/A-H9)*XrX;7'c[XNmXb+YIgk9[hQHlU]_t'k&V.;qh9+N %A:A*VSRQ\:VL9 I4L.ofoGWqA\90>\-IASNB= 8?W7Ef#hT$s-#@rZH2\ESG2tgon`oM&+9OgEU[T^/B`Kp.lDr(G #r"bOdgjCf?PDPZg.s+5%Gt7lPo"A=L%0cfi`NE)U/&J3^02@-kI\=f0radj/R/4242%X$&pj1`kbhm\F]M2?dnK(T+n'>D75ZC\OI0Ocl0[`2:#: Zd#bWXG[IRSRtj6!r&L/DhcLQ5dl!4n](httJ507Zt)b\=gn2!giPZ0KiI*c8`dpG^`N -6"dl&L2[%\G/gOPPQTp6->6#-SpLM^ aqAR#"])_*BgmV!n7:VU%9`j83E$F[K>JBe )I&4hD"DPo)^nML_nKQem!rJDojCaO7hTLZSUFl=^"al.;AiZ#2;j"ICgk!>#E(7p/%Laonf9;qrK!7&+KeKI[`><'8ml`a=<]TBt>!8Tl#(.JAs*i?NWLL>)'sSpV>2qp0FUhOg'm/@8ojW'&pf-\/hYo#-A83*gclkEZ5/3XSRd`Ae\+7d7fN!8GO(e4\qA&4'N pUR]rnlZn&oWCCiG5q1o_"_@3XMb\IWf$Y"b^G%^,rGY.7/1&&mF0<+cf3jW-WbIS ?'-"B6iS.SL,OrS!+"cGX_DQ\V5[6^7bZEeVP`C#W@;XaC^ oK3gF]9iUS<,:J;r1&U)Af(,LV;`ikl(b+0@#YY2s)%`2Mc#ksHWVjk$t2iM[`Z$%t<PbTEZG@kX4e>4iH*!AlRrpVHE5&)/S:sJ[>U)jXMq)4HmT#o0f;Z*@&%-LB([#m3";cEA"jh"_'#Mqn1,q'Lds ZL`b'A2JOoL+5.aH1i5l$H4+ ;*Nhk*gEl(PA^a;ggATU[8!3$C;JLU2ne9)p<$NV&Ma>W"Ak2rDf28\.($7DnUOGr-n?$K32WYa[Zb^N6%$,I>[>0mN+rn[A#Ph.>M0e@A50.g(%eU-bL\.bSU&imF1^AeY@GC<8qj?Wc"+rls,o%,QLdCk&In%PQnaTG_g!)t@O.7Ak!od5-r-9=<$Y?:5MAW\eD(8R4MK:WP?V6P_OUPoYnCW9@#/>DKr%2q5PPP:?)8L#>.n^C#`C*2k=)Y'\?2A!IDVWa"cHij2C(g#ht8S;9<]Hm@.`$]q#0":;oDCZ^%-ofcAQJp8"eGZg61bW^-U&:t0!9N[caoZ>Ib%,2$.:$;o61TtgB$mUmT:m/K^k/sX\R9[5=fk;#E9+NfC,Q;R3LoOgoDW02QOIOQ`M/TZWXX%7\dLI&fk\n2-;A0>3Ua>+&BpV&LeF8_?QUk7er `+MKIMqT7hh5H%Y'!2ahrI!-XC!aDWd gbdb-a7+"+&<$\s54nDJ`k8n"A(SP19r$mM1ArGA\mD&8UK#o0S(@4ph^[IX]@I"Jgr[gse66b5[AEG@Fa61jSLcCk,F7sF+e%\UV[_0`l)S$a<2WGsA2C+dg8lec]'^3l89Dcj8@C#$Il88b'H99feK%a/Ee>Q)%rOWf3kbth,3V??N$H,J>$lPUiA/gD+#!cJ=a4]ae!aD&.fL0e67s+g_?D*&aU=P.n;4EM]Y/8f4qPVAA^7ML>7IA&>*T =LP:VB"Q$m_q7U[X5!@4Y!pe(UF.Z#YU"K[[2GA5N:a7f%B]N$$OPD_(t@MD3<s$]A"8K<1ff]MZsD(e1`'A0S?[/eK;"(.j9c<09/58p$5YbeP_LS:1'K5K\Is(9jT/;.3"NtA^"WG>r_UEa#*E=Y%f(@GAtqfV@d\:0]ZN;B?JG;-C*0(-OcqnDQT?AS1Zf[Uk4s\>`08cJ?h:*,$Yp$#M'A^jq'DfmVA=QJqbo''r<&f:&`*+I6m/,`Lie:5lgK1S+e',SAUZ0>2LOB;_%H?/?Mt`MlQQ.5[ga>tPdD]&&a\8Al-Yn5B]QNaN!dkJ*!`Rr-;%WZ5V_FgbX$"AMbL&CSYRhS*_WA0qZGn8UYIil:!.[7XsdcNLYm!=@kfg\onU)FT^[(GmW6@lm7=2rGD3.FO2b]+b'l+VAo.]c/sHE%LKr;l@+A9,BP&p##seO-I"RUJ-d4]fhX'4B.LAI+,eclYrVadm#aeQF00\^MU3R4eUj-hr)jTX-F(SZ3AI@=k8bkn"]>&.(Ce"fT\50#OAk`RedN!JqpGEaG)Dr@a*<]3`.#k/56P;lZoeQqt%olh:,_O"37pZX[B$Af`>r/&DL@B\1tso-;2.frdR/[@Aql@D95JQP0+jc#FsrA!814#c!ON2<$bjejUOZ*9FO\=4k_[[oG1L)GVVE.:4)P'^r(JHkV5HAj+`Z2,AHjJmnhRLK$=<;=]V^EV-J@4XHc=>@tYL<d6 XEC.sm(lp0UAp;2 ,OZjbJmC4TWLA#5,Q4$[.[-nXI_/Mk=0RZR5Y*?`4,267N`Ja'a)9CA:p67de'Va4ZTs5*:_g>P(^gn8T;ELls#Y0qZn%%KZ?"4EYX8Q&>cl1]5` V/rMX1?PcbEN=+mf?_mOgpAEB;MQSk^\1(J])oAdGL,F'KB5iR'(:#i<&f[r-9Md\E(#2h%Cg^_:6ISQ+(Hk;fa7A(60^Mp2(Fl7`^283p."Y.bd3CMbK,b#/sXc6Oh:pKC;VS(UI<2T9A%t[*T8V'_AJ)m/P- #+1i#90\;(!)e<3j$pL2L"#oi^9L@)j,^>si;LXOB3p;tW1UHlHo)&GEQMN]_A^DN2=$;M3q7%\\=0V0?FGd269qJSih>/acd9njGn-Q-Y:n%>For#\7'o@Df0Be._`)j[#ah"PD:-+&k0,onnBgH;U.qN6/jVT(.U5Rp),hC7$_b]rT1<d3r%W"L8!M.3=`52(1DtP-X%`dSHZgI*1p8@eXK^DdYgWOt59-DED+56A))BU]mU:n.>E"-b;caM=YaZA=VB.k4EQU9qH@5R-K<!k6qT"V\j9SeiEY#"bBoA;HIUof: B%ACMn&fPsCpBhqa68)6>>eimVRI&,)q(F:AaE^4gGOjb4XtUpotYh7:DCk<`G,d8\WDn@pnDW=%j6"#PU[&?1*9R 1nINUf&LE5*tk]L=q(`+Pp'A^QFg"Ff,!UpgX?9_FhQN9 WGn%"6/TXB0i=@P.]qGlBhG-TV.Y,&/gU7AG2#t6+ZDM<Hf?r4/`#5hM9U]EaeVqRm'0@aA!_4XWM3-i=4X7I>*e#4)N@Am"8O)!YZT??m@,\CS3g$3!2_V)SoXh3ptCNXA'BS?a+Icp$S0Fp,+:rO%TP;KW'f2Lh3ap0ngKVc[JIMRsXf LT#n>6G39k9dj,4V89ccR<&bCnr$Jft*ALJ+Kd>,Em4p940ItR[1Lg,A:(WA$d.Z)PrBJiTPn;kB>7(/=D[Wee5:T;n:2CfWM`"T#nW2X+_09\pr;KR0j]R;s)9F>k[oK;c&.'J<%,Atfb4a+8?#U%M7RpAT$7:!ir$YDY2$5lL,Gk>#JSbEA,ZgeQ[BEg""FFc.)5Gdm17UAV1@?E'No2ETDfp!(@>0=.Bf/o% lS(b[:Ji4-9RRiQD8IT.!bVtCSh\c\Rs7147GpTR*0g"o`D6 3;iHc\Qh8ojSW9*Tg'.RU@3]ai]O3Dsj-a@_0TZ_9Q?*<EcLfr>poA90%g3mkH+->"sD,^TWp;W`-3pP??NI%QjO?lVqq3-h(.W Pm`/[`3F.'4.6/:@%b4lqtnL\86s8@QLZ\On14Op:jRkH0q52s..Pk,<0%gq"2%jdS>(RAVi:=7N?deR`1G"N9D 0`c] 30^+mBmYHW(,o/:*g,VfP/?t`[:i1pd]g___+t6IH=JNUI>e8SCpa:g;OR:eECAj`6'8nlo@s53e\WB8j*DF4C) Jd`K#IPBX?#N2@#8OK*EjZT oMhTfLjt_TqAno*3`1T'.d/ R.kffa6E9i @=3k=F&h/D/n5Z,c tZ63f$=ma!%BOq]1%n's^k'ZmsGE4*:Q@7/JTY]iA&\KU1q<$bk9N9j06e]F&m\207TRX[4%d4g!3,sU`cXAY9$de]E@Q!C%q8P281s_d7d(bpA.*`1in,f^pnIElntTT`1kJop*<<2^r?G5Y1dP5BBYQZ!btf3G#1oP'EY%N+'MU2q82,SQo6j,oU?.D9? rZIdf_AB(VUO!M*_7$,5QTTX@(AY7IcNcT>-U\r!$.rRF2!d$=MBkBQ*(A`Om5)LJ:. 1*c6YAI/f4o&%OCp33UWk ,#k15.:I!@]mT^-<;'_ANt)H0)!FSjpBV;7[;I1/D">_4.!p3V\CL=@slelia8UIF Ra]t^X=mFrQH.Z,kVnk`iFl?mB^;aL,6DA_HZ6A9(9n0sZ<!2/@jT#d1GRR;tkP>a(q)[`!!Q9,OOd*Ua[>\5kXh,0Qa^j`Qn_Dc,&A\BF Z\]7M77#*e<X[tbhG&Zc\*j*O,ETQ<=$P_qL)ssU6k^mf])>'a>HGXk"=rbL4gF:E5cQFIS.0PWfh^/cMi4DZtk3;f;:]-QKmP##oD>`;KilN>6f&\?Yd-QmLoZs*7[A&UE1h*KCl02W)R#/c>>E!8TiNCY[NLh_aXo M_.7E9g9o]PCS`/)Vs4P9;fXR'3!XTO8*"LI37$RbVf8qYC]Dqp%BdUNX]RO;=OGd:\icQ)i )XP#,C3( 6_S9ksX7Ar[760bhT/R:r`Y-.\cr,Q1A9/38#YJe%L!rlC4mO;KCPMm2@p>C aQe(;9LdA.M .N\*A3,Xkk3p>HU,'f>J(m+&eRi`,.10dWkf#rJUAW!Mf$-6O""@g f1[Sm@@]d[nmR#hENkFb_J^QQBo@g+@2:e0Z2A:^^C5io&\?;+nC#RYC?-I*e[Pk3iA^\P]AB'q5)_ _C0h7r^mbr(VpO^>?0K(ATS5Rah[k j%@Z`[!Nb J3jAkf_S(\>jb-bYke>_@]4A#QW(M='_pm3FVqkBG1Yem83gB!E\XfR*!19aXN.P&@`V$b^+6PV/Ql1@Z(>`dhXh48@JClL=aFea=?dfo?V532QCAKYXbUlg8;_Ubm,!j+OSg?MJEMMX/M%[(\WdK :)ibP?LHj5)ai.pRQ"dt<=mA#E-`t7C5]DOVN!!mlLfC\\9&oj%AX]@1M"BB*bm\ >L.sAJpoI]m"IOMoRRmgD,Rh/k>_KT.m"8``%f`:2\bn1]!!B9Me5\@,?8]59]rrR>GeEJi$knYBNcJ7Ht4&TWEg-[end5AZi>8"WI!LEFTjp#e&jOIJtQh'%c^g14TmCH ^"`A1]Y*JU1JU>TU<#Lb4)lVVo1Lf%mJkS.g>VD1MTjo)-P&g^iL5YI8Li,n_!;3F3/e.\I<@;C3E"BIW:X\<%ULnr#W33Zq]KRYjGXCoU\mK!l.B7 7,/!_XK/jQ4qebJ/F9jh8IU.8hJ8V>]B$6_8NFc-bWtA`f.f,66;1o"QkD`1<# 2@HcgshmE,p&cm!Q_n'oWB'RlMl<9"DBtC;"D[P1:b^8gc!%-e(=?T2'_ZoiqWiA9&:57Y"PXrTU_'!UAfYA]H21M(lR57/e=AO'9SEUFG 5_^"^k>IhTkL<7Gq/gaFldm\F=.* (PA;n,QE/q@N9^$Vsedg+ar;;&AK\V'!7>1#:_E??M\l",@4da:][-dr!I6.'lrarP!TA06=8*k-Am%osAr;G]9MdLjSj1>ThQ^Q.8JGN-YT;3=C*a9>#[B5NnablrMirPbjlD65!$Of:@[I25EWGM[X \nsIXF=qc`Z-\]^Vq2kSX=G;$5@LQ1>9_4*"4Vi"QmAkDm_ST*7;drHQ3if`J7ng5ne`%8aL4,f:Q5GS`LRcp7Z(4XVd^Iko=$]@V/ta'o -9hdlF@Tn]%86a p$R7Z.7bWcpgT,87=ZQHX:KN"6a^*0A/ibL"U%:E$&= )bjRo.+g`%JtkiVXN(o 52Q]K,XJ8JLf=T=$'B1;JI^5*Al'A$$!*PB/%b/5s[M=77C3BWb?Y\hb$ceQ[pm+\:IL`Zc1MT3\a_o_T5603tl?dg?pr6&\8QkeVih6QD%-3,oT!$bc1[+] 2I"dh+QA1jrB>79Ud78"mnif$jMJ5qH>lr`ck 6[fmh?%2%9F8eCPJ/T7<0P%kP DFG!V4.N9IG"&-T%p,5PLA6PTA5`_6Ibc4lb9)#eLH("Q=jOq),ZD$.'55&rl;`54' ]&%5W0HV[_/=WQs7b3>7[I $j;SDo&!c-=P@cQ].GPN3D7coM=Q!#SZP09*d,7:WjsF9[6<k!N-/?QAfK<&.1$<-dO30G6tV_h5T(45a"Hgbse"TXr:W1XDcnUp"f*R],61TVIHW+0L$YUS[h1A=c".(D:^eM@^\&UI30.aURP?P72(17NmiVi)LGWON0BU\45;oaHcUOhhrT;T17Qcg6O@H(#4r`C65*m0R4Z1WpeM:nEjHZ)sennKseA;)h@)a0f1@91A:r8Re_p[CJ9[o8f>^2kLA=3"kN4Kc0al_W+MeIk"MhrUT>X":0tOfo"U[A?h"AWa8Hd9Cn_>ULQY"fj>[:]EBAQB-9YW4\nbKj:aNm9(Dpbc[jiVb".Y,A^,F@".G=iF6"$G R0[;L547[.g(A+I`+8!]d=$4IY< .b4K3&+0-H7eWgKL^34^bQ]*I:eC%qFtmrF11[jIQo-QPG>_XTraYIT#+T#bc]D,Y[nf7-l.d9JO%jq+=Zd91c]3/N%r-H=A)T;SMRde\KaV`lXS184CL.7LW4S+<^*2hA`PBFIUVXm3Ngfn;jCjt+VCOF(04T()pTfY*n]S^c0"!O5<Am+_b)*8*p[QDj:;/d+WeQYf^5b3^$CnK5MFBV'Q00JlLm_>d-6F/M9d.p+V1_AMJS>1(PWBZXG`hQCQ1]\7MS'im!Y$N\B%cJ*("f^Qn-XHj)$ehjA?TmM!rLA7c9N**Oq> DK5Rm@[jes$PclOsE9EmDG:)5[0Ct`5_,Y/,/dbc\:ZG4K&0DbM.<]d`YWcPqbnQFYb]cC#\JL:^n\'s6A^GJVA*.8.k)Q##HI+&P*AldtSe%O=5V-U+`&SDbB8iKa4"'1MA7*>/BA&m=W%U5"U!$M]l+mm93_Bs.&%VqA9%>UL'?l1CH'\#5D';FF?ia-pi2A$P=Eq+R[$\3c&%![H60R^2+/Dq8m6^rk.0`YeU.X@2LM_j-.ZN%An&EHGc4qO5/ZqXLU4OgKnr0AH8YDn*Q"o&YQhsEY'^KI&d@sCZqq%#UE?tNA,9_E8laO%Se\R8LW?HA:JA&qsFB2_HI]k?'4$-@-GrNisQ>$gaAALde9n?Qt+&L%1R)4)^Tar\fW(Z9f@%D,=K).sVO^W"WVP[X/-M.aN'.hQfO,N 7o"2`5Qfg3RLhkNjW#,qWaM@:\_=OGg]fSKrh=[\B=9C(t>DDr(geZF_l`,'&"*Ifp?N)cmT,6bOTRCr=A6,s]1sB3n,5PpRDC@m,,'jEo&:=@%Mdg:<^p=d:`8a<_D=bD`f/,([?%n2e\YK]"D*5Zc@\`3lnF5jLjKcG'A4RJI>J#(':t<rG9Z%&_FF[fj'q>LlO\$/L=/>\0^B&W+RG.iIhaJ8rJH5 sI9-$*o=@LKY0@c\8oVO9_OZK]eDqm]7!9";e9iTo0^XZb% 8gIpesVHaLrgR?`B\!40b:@j'Io>8&$fKts7%c\>8WkhB$/@It$:oAlR40A2&b(4"/d5+/'-k H4f=2UZi/QWjF QBX<"/ Cfa7:JNN&<E4a-`b=;^^G\'BTG8R)oCOc_@H,IIG<&3hMr'*(<a.&DhY5U(Qi&j[D]>qPeg<QN/o,!FJW@-0ZHG>5?cBiMK$l>D;mCQSJC? dYN:Q8rhGa4&9A>dtLGUkiYAL(N5C-/,NE;^lq#%c-GWh[A+f;20+i*BZ:+9=BrO),&(L`N^s!@e:WDD#fWY8i_^dYReFT4? _"9hh>)k,oE["p-)2b_j:)o$TRU3_4X@Tf-E2`1$&i[Ar)*s'-AZdQU9V(^_mW0sT1V*/W[m75A(_4jOjRAc+\Y9i%fH7$4DoZNO3r#^=`s;6(1-Hf#\'@&R-TGYKTNG-gn&"(jWpA_,a2`tFkM=aAPAt7)Xh\]g9P&S*qiO=+b&*Wh`OL[(g3CU3!d@."+<%?DN#5^YXg,^b+%b=@sA'-i"TZc6l0flWAGJF#pL':>)`_(baUeiis+5q4"s!VaH+X4I@e_8>^OnTMMEaJ7Aa4SY42kjoR _d66kF6iHA%eK&s',ib[G:>2 70/dLeZJhlsLba%R+9f1/XosAdmAZWbC[\g#_c.cJ0VA6gAB:o(`2>O*$NO_E7^1Eh!in[dM!Y8r>j@dtFcqZ"la>,d]49+e!Tf_J&A[QUCr,c;?HO%ji7g_9J)$6kd)ai-P[^C?Wm)M^ \K,RVU1)iZP9lmC2(Hod:#@$9cj6+-X3r)Sr9`97JWA::m;rl[9J*2XLE#F0U*IB$P]+\Fn>[%cWjdk._ tc1"2eWIR9#K9Y^5&%jZ$L,LB_K+19gB:AWdR!g%9?e>W/Emc26++H.\6F<':j#P9_kH_KGT88=4TmVGm[[N_)C5>;O3+>i=1F1UAE# \"J07pp!oq8d..g(((deH1[)^[,= ((s_9p*%(M_^7 l"rJT?l6n:iU*dgfaM r#e-_*+ADo%N`>Abj9'"FoLZ#db$&7Y_U^?4*SS>dG;K#O's7lFWA=6qH'rC:0aeXFB<^K(DV i%3)I*JAX3NNL jgeG7Q[XHVTa4\2OA@*5B[AIF26I]:,Bla4,I*ecIY.I9Z?8*)k`=#]88N;rHN\R_9414grVceT'LM[6IF]qaa;:NHd@W!`EAX-D5Z?gU5?bZ_TLR!llZkUaiB?iD8cjVZX9B^'(/OVNm0I_0&6NS0OD;;bK;',UX-GlB'gpj-n[fKaEn>sUb05NM^$HNR-<3V((RDpGKA-PdUA]s<)lV@r&7(n$A>M;D`0LM\ekE\Qjd.';qdO7 9KC6g`Y[N`.$1`raN?o;qR'r Vm@_'JF59($l21"`=A[Y%\(GAG\qIf5 )N'C%">WGA,Q>!-#RTW/?XRB:_n)^(RWBA]r^GF$U@A=oI''fAZ+RY;!EOV6E#sr<iH44G+hZ;`hR_Nj.CWM(Ns+_$a $-mrSr5nt;(0Y)fI)S4GEjX=`Y0n$B(q%%cb1 An;1nAi&-3\#Aa3jU!N`!4"^IqAU)[p$Us9q&"WLp:@Pe:Q?cLY(:Q\Hf"-V9?>akg=f$,Dcj&7AM5s-t3`N#Al<:"UVLG+c&,\k>ejl_qK?j6`&Or=Vd"%Np"b7q$8Od1:;*dfnp[^UJ[,6t)YsVkC@aU$>]3S/LKp<#40TGfNP*+8K*NUl!!]piG]O4A5#HQ@mE2<rXNH"K[jE*5g^(5R9!Pi?L3N[:3AWOUkH@(%kZr7EMbnRn395W/B57o7d*pN`iHQ hWbkC$j%ge:%dT#6LcPK81jRcAd[%s_$c+q>8hO)l.bbY&l%>Z^c6i>\Cr.GY^eU/rq2C"mai_W?,@ JTTS*lHpL.DD.\BBEe<:*W1db#%+*,Ql6?+X=M_nb7%,%lh[Q,['nTHTgdT7j?*ls;GT;;"%7+bnB>EK43GV(j"DQQs l<0A,/o (+G71o"@McZ%>0c'Uc.]PXt\>X@kjXWqP,,,V`^l*L&6(d\<*cc4L),GbBo.TmE6/@7OA^/^gA;!pPs`Wjk!RGG2\nG7aa>C\W@o64tKl7SMAX>k&L,0V19b.YK_:P[DGZEPLHX-/`*-n\AO'CjV+&Sr/!>)8r>&diAJN)I0aWj4m=&&&=Q^Wp#pU_-3Y13Q/g#"EQMpBS_1YP&9\ABL6Z6d)f#arHa!Hj?*X+W0:'WWOGV/1All"Qa"Xk\Oc UC>\AqRtCVbD)X<+9pXrR&`"Q<.0-M.Q'c(XYRF0^%>#TN-V1g>Gik I@1.R.4@"HA;hWF@Kh+X4kt$8*&N`;m7UefMH)W6p]ap'J)fQ;)<`BCa@iqjGCDNlQ&-A@^+H)q0CEYsfBs^9+$b!A?ifH`4e`5YcN4WR$q?i;hOgQTJZ%^tZ^3bV>;+FGPDO;Vd^"l,TA/^&.UI-A]979L&'/4bQ&Y==om?pZAVf8;@A(B.FUY4Ao3rcKMJi8&V6pjTW9 1L-$M^@?Xo=Efmp,!#2B0 iT?%d\^Zeej-I+,Etdlo;GeXtq5Ei;N+QHKEa>:p70G6Ah0t$DC[:IgmKiSg7/3hl#Vp0B[;2dKL'SW%pG1PVQ>U_N)0^D[ALc/QTOaA])brkR5&Kk)K8WAUkhpSEj5nB]MLc#(T9Je#LOR$=gn>EdiskF\p `roU>)7C<G$L2gPH`rmc-AE$3=D]UZ@:UQ`q`=sO)18I9L!pDZ&nNoiOftb^1l(KBi9k#Ek`SmF&_d0(@t$Ybj^jnnXCVAOft4TD_s\%K_IcT'C","lpJjjtl7fGG1;J*@]BZUl54j6VFW=+QjTO[1ne*GO@RsX=j4F /^nFZWSPS=VE=RJ[?V$21hQYLS[c<1)jMEQSj3p;s)_?D_+s9I!jokC8[3Npbd+kW fo)kBat,qpW_YspA_A!fE/7g@YVTODlV?f+9LKMVI mW-7Ueks6oe4AF4]Qe6I6W!J8M+?IGr$&/r@EA,d4-hU$]bU-bAapk6/*_ 9k(1)<,P']K-_?KtcGg>rm/YDhjO!3lpL,t*D4j"Z63)kB1_A17LJ+B?#(?9*:q=X)VQc\pR,o:J7O"gRi#Dk18$\Mr!:"m*_dh9,8g0YIX`Zd0XjB!S+-Pft(n.?'kD%%`K>'",Oircg1L^\+iJE]!QEf$J5l&_nGWLGI8[B:k\qpJV1N3(/'/HRLb3G57Hfn25*[:*\E`^< ,rr/oRh ##dl`7>i5"= K&;;2-8gsF"=(*FkCoFTd=_,7\^R]SKoRlkF8]sLMXG%Y[+im6_^`7fLgk;lC-)BpohMn0?p"6`ebR\'h"%UqBC:?A0-YHU%[^K.=pPMhB2K'q'oYgfnhsdH3:(LTqpV6;'q9pBsQR?X9^6W:F<5IQW#Sih2J=D"( A0CT9W_nKmV2,EH0$JWV*6D\s?!:8`4$)Q_366,!c(ga+Jd;lpk5gIE\k+&f]o"^m-R)A(M#8%rj"NWKf"NcE$%l"!;&lkQ nB!cpgJ5hBh@Be7go+o8fd= ZelUGrT)o@.,EQ8Z>@=elER?'\DEN'iJrTYV*7&EQXk2kLI`CJDZ^,!dK!U1o1 N=*qq8[>t"sJn9 r].E0b*>+S'Y`s;hpAZTDZHX+.DA6^0L;cA=B!12p#P=Nk8V@[7e7"9+YFsD[$F/TKo=>C8K<[,T$JZYs(k+cK?ZXgNtQ/H*9'h9@f%Ih>G%/U]V]VYXE_^o1h=a:lkC4Pb.L^eA4CXn>st4+jakA@NS4O#gD1V?5kOHNC heP&X6<>2UkP5J0Z&J?/[8ZElsB@[TMI^N3-85UZ /mUYZfSjGL]0@si:nj6;9;I)C20)BO?W;F$!G?<Y.:s%e5Ze3=7b8I#TbITfnK8nOrLs;*(GqG8P"HX(67Q&0I?8`DD;N9k<_(r0p#=P:FV^W,#& [H!tVq#g)rbj69M[;_aQiSN%r0.Q]$jAiIU7Eb\PEJK[(:CHjkg!U'>\?b #k`'>t"C-C'+YJ`@#Y 61KEb K?Z)5FsC>IIfH+RpL2>W"Q$JZg/2Bk;%Hs6(#a,_S%9qQ6_\;N_Dh"BGrOGN049+fbDSANG=*P"RoDQk91S'nQCIBeng42;,>&GA**j?edh,:>Aq\]5q)c[$E?('Wd-Z:TC5DS$BO PTUELG`jLS7_N> bGiU 76%\QC)5FQSdDf\D>T#"^"9J] n/$aA^8n#t$a]%-fW_j#%fH:JTF0=l3?oHUVZIpJoHlnM:ponE:,;">)l:Hnhg:@bUq's#DbK`L(,MU$,N+% r@@4W?cc[I,_)daC_?T"tSQd9^%`N__pZC:O[gWgdhG'b\^0ltg'O"koJB)J-V!iI3(1fjq7H;BrMlc0Vc"YKo(C/Wco2YTaU?s:YE2rFqB81/df5\W3[#]'0IYYp/8qQ0[_*tN!3KeAI5-4`d'G=&Z)hpqPfLVJUG_>>>-AeHW&9Mmt,l1T^hPoML&N@T[[deLkgBa^pGoh3rE66BW"?%K))Nn2X*=5FA_6^bT2hnC7/H%cMkZ-&MV'0JFf#_HRNV* .@j6eU`&l2"W=R)_EE0h[-,="/m2='J2>KF[Nk['@K_,\%BHY4]P"STZ@-Aea<&'BE;]t8No8RVf',M@34\/G<3jI`A(T0"@b,Fc0;,AfqSb0=o:a"I*5`'>ep4#4D&nQ6\=Lloe5Qn-ed&$4W.KN"!i03QP9DW+:smc2_$gO*T2MV6;';sd-06W:'ne-fpapE'j1,f2ieqam>mJVD0Km\24 _\ApdeB&@gq4%fJ3oq`.&tiR-(A bYiC([QPaT6].XVe'[Z-6j14_K3is p!1t_l^;?@SMJC;pJ=_6LaUer7ZpDO"@3R:lqT_(ac:bSd!EK*,sD^s8R0]as0lG17)r.(W%lA(q!b=J:E!rM8^dA1?Zk^ab^"c,Zd(@tD8 sM.[E96p.DKRG?Xl)oWB tD)(>REQCj(OlNi(gC]=!1ajYA0AHo[%2cpmW#=YIga?,f1E*W>9Vk(0DS[spBF,]+a8NWn2f3A)kOs$eG;5 *LGGH:3ZDK!B5BZ+bX][I,Jc47T7;#i2Re7tJK&]_N(e;qSY2l#.bU9mebC:8EE"U F+B.-o3GRnEtA%NM]7ICk(+h;KO`I&\LDE. B\VO+0T!-OiiOkh+.]RE3DDda0Mj:L^id\d#PdKc!Qt/W`:m-aH+8*gq\Zd)0HoGG(T:'8LH\Oj0`oJ(YU^_6ZKrjZ*t(S2d!8qMTUn 8Wi38sSCkKcZ"/_5n%fUZ!HRiaMYF'g^EXj93.-=(/oHe'!B,LGG9?cF[?X[WcE5\?=7% ]OQs6nJnRJ/':A6UGZGm7g/Ke%F[7p]Bs"J+>CCigJ(T%bZ"jnPIU@G$(++1S_@b5%mREh&2TbH5II@A,jS.[MH\1-b<"?Ak'6,(CjbRG94=qV%8 TJ6Z6&3(o?hYfKn95Wb=(=m8.IF?JS`Qh*R?@IEp,o7U-J4qZGjLnW aaf[VF(AD>YDU>0@ZreJ0L)(&F)-U$F@j5msJn)t6K-SGr:Td+9$PJ2j-s9EU6\:N'$=7BfT)bcHS)5AeDqbeVO6r@":i09:':jY_-2'ZY5['(PYtgge0LB(n/fK"i6?9]4)C9(;g= G;" AZlZW0t3bPYs^?t$OtdRVn:nV/m[@A"p.%9!p&AP@G&S^)g="qA>AVTb^=6T-HAJ@j+Tc;GU 3pDNba3iS3[$*FE<$UE(pF&@9a>)k&1MOK1MTY#1?df*dn2C>hH$;dK5>1b)=j"CNaV-atWE_"-\'\OPdRk;b1U^eIA4e=7k)U9rDASSEhs;H[*,Vef3PhO@&?,Ri,>BAqmEZ^tm._A#[@[9%jb!G#ft"Bn?:^0G4-Y`fMSLdelJrVb3:"KDAlPH#@m1!MX#.VDA6ZLIdnF(6Flqgd[GUtN:YDReU`>pUBBQlGhQbC:`b)A]:'AfM86]'K[A1G3[Yb"4oD.V=NhSl3JH)qA7TTW?)`2A[(.i=S0N0%!J1D:#";lcAWp>,#d+7MgM&[8%'>% P* kIrG4,JZh6ArHLiW<30`[U[`n0X":Z57 [N*HgZ$I7otWr54/Ok\NEQTXVZKt8D6,q.R3mp>&_IPAI(%?e!5?A/Qbe@ g5aGG(ni3aQ%8;=R7B4TgE=cNBq+FW\An6k@VSnE<(EC-dYOXi5P[Tii;s=l&'p1UFmJO[#pNbt8/q8Mq:I.Kl7[5+g8)\XkA7=1"7GT.4kFYob70WpJIM/7`^?rOW"*C\'\[Ot%I@a\dc?'cjQPlh\h5R/M@DqMap%_lgJ\f!Fn(UQJHGTlr?>6mA,VAb3793AjHbXFg`E"d-kr59p,"q.g1FgFVB?%[V&V2T:?02JO!OEQ8?_GKU!:6^lAL7C;Mb@2b o_s\1j:e]df*LQ79TSjDhM;AOd/9Amf--]#c?4Z4DA*h&/?MH0(=W[H>U,j'AQ5=Z84qS_]io5sdC/Y!)Ro/#1-8eahG<=VGleBq$GtMgJ'iaA&!0>IGh<Ar[[r(DdF1mRYX(:Ah^8=<_HA:&X:*+ra(p/_Dh_,i)B7 WFq+ZfD1/-rZ#rM-i\)%3a@Ud]n*+O;b0j3c7:&A,T=<273+Ib2EmD[`=N&`99S8??o&/@qoP?$"H#EL ER[h^aK(iFGP%TAeefT$Eib^ "eH`n!A5\Tl.DjW:'CC!8/rt;Xi`S_Cj$Z=H490!0#9:$A!52\G@WG =]X`K9CI4)gYNKW0]=OP;HJ/%pakp c>":0rPlQsSSUKaEQY2iD/7.]oCP"omV(OO5WnrAI[&&A`EL>R_/"r8.O/6cV Z$JsGlfKOZ:6t!G\[[;\Yjb42^6ROJ[TA=jbf9AG>t9_6pnNXioVqA=2<]-;[t7LX58k`<*K?\p8IQ0At;LEW0+H6+*fd3SaI'$abi7rAfNh/,V!@M^H@_i&]O,^,hNt"(mg!7jji^R\ 5WC=]M[q_[Mb9.nl!"BTOBj&Zkp:0X],&nJ$\]]S1?Ra^#V#X3](Q9qUlM2FqQefOt`oLUd=2`-ILq'kl';P-$m&dbNq4_Xmcam,pA6ZI^Z&eX3jLk'W0^hf('1^&b:oT=nOhOTQA!oh'^#R>P?3+L:XM@anPUHL8pEW+.d*,t`Q423Ea'3*,\8?[_7i8SQ,Z8-EeA(or+LtA^)r,Qdf!13HT>+l>jp'qK'!5\S+\1R[T(lAWG@*@WXWjiJ(-C,:$Q*g;ZAs$K+Hf3f,l'(.`2+Ltg=LlUj]A)h_.D4AVThb_:o"E,Ac[$r=`6CM WM85D/Sa&]RgDY7Q%1/8AP\-`Lla-5N?aXpkcrB7VV`E!E8ClT8gsmJb'3W`?C9rUFac[X^gUQ9TDjZ"(jmU54^H*-E?/q?8cIS:dL0@ b]9#DoU)^p5b8X$*I51q^WsA'd%2O*N$0gEfr(ZTj5]CgAC2n@"p0tBEHN1mYX"?InEGR7A0T>VMD`$`9?cmc+SA!/^SHKc6PB@7-/P'NLQ)s%@ (7\Eh$-;DE*hDtr/PG[]J69FRXG2K(MJRMkOrO(Z`KnNC<)o[<;`1hDl#((g:W$CrPUn(FVC =a9A-p&SQ-.Z9I o(1,pIadRJHa3ZLTVh].bH;#MkK<-en/H^=(/"fsg&B*bOAQE_X[??,*N/ ,7=',iAYKN OnML3[P^e;$Xq/Y-%i@[)P9cim"-8t<=^bh!srU3cB\&^^>O8IjQm5HNC/dnKsYf:Bj0dN_)i26qR\k8k@Q0]_tO[dGBL4Prgl'n@/>Uq32\"I/pFTG&X`QZDM/,O t]LC\nSP'mjQ:'NA=&ln^;D\nlQL&M;kAniTD](c28,8,18:6!M7n$&RVZce8TeHW#o\G^F%2_XM-/U5UZ9q4lg"St_'MSKisb"#e#NfZ,Ce(=nU] h/$U.Spq*hc+e[@1ZC^=2J\P3bp8$c58j3_O:0k6WC##3=jW!& .f!B,H^\e0S;adAUOo;6ekIP$>Rh[\-nN+,ph ]3C1"AntH(F?`s_SB6CLBsh7D@7 ]SAJd$j'.-aoYTsN)r:=>*Gf:U/! -03/6n&B$JBQ'70?@&G8eDUk:-tPpsa=-lYS'G6,^t+WNDdb06]"EpeqtZ"fq=P'"pUgVY*r#D"JNmJXs1t$;P0;%$ORIhWYeAbL@ZSB&G'n4QD*L/nS/^GS_9?9>N]3fFnAGr!neR5=_cYH7$)Pcf<Vf[rh+C"(2A?.m,SQ+:A-I-BU-Kk6prA&+><'ls^\6#l5#gEl0o5l784M_U3.=W_qGAmQ*%%^^]6j$/S,O0"1e5/YmQMqj?<-TR!*0lOrtSkQA99kNQh.%r"dOm+eGSXYY8- )FeVXEH:P@Sa##kM\2&7EY$WsDC30'l"h>%Ar#"]CrI`Y2\8o#-\A+qnB[3Nqq!a+'Cab&_3WC@]2?kr66f$mXoJHVQb1L;/"E/[_i"2A#O_@8!_onZ:KfIm25I;qhK"A3L@W2?$7>_J%UAKVto3lMX$-(b7s#nZRWJ C8^J.dqq^X+f;:nS.j'7',)boQ07P:be3Jja&_SjlSF/KCf]MlAj\q8MYh@X?E9PZEAhdOI9`bB0)DN3M[)i!`5iE&/6cP,K8fd$Z;6g0ZR&MA+m"ikA`$A2.0e5!2g==^N`#'j#rqt:\ _q.1dcbKhVo5QdUjl=<^Q%pF.J[KsmE/p<.0(?j=(@bU7 V`Q%*Q-\pdr%W@>etp(Y+?H+WbnN;JBNA)3Vh91?M<9/f7_j,B =E28rLFmb9C64o?NB1Tf]a4#GU:!(3o?;79.Ij^jkY+e7Q^4?[f:@sFiqGiP%`n/f*IHLa0CepA>VB3hJgZe32-'2hf$1) BHM#5PtgK/B'5D_/qY1=%*GQ40 `k-S D!DtVCL"a9kLRr;^Z\S5?4S4abC^_Ji.9=:kR\r=)D7H=.-1r.OZa.N"T7(U\snk_BLVsX%0AJ0_%V'jK_.e;o,A=ercfJTZRlB:js__+O%m9/`Z]`[CSU4%e<4T=F3NGa83EIc^MZtk;J[Yt=&hJ'$PTA#8 F?B]XWF(CAKpLX_Iq5FWSe5._?it'%Bh7EAbZA"95NAo;_[WE/Z/0bGIP'FkIK*/Ie&la!C\nR&'>'c'n2C(t-ZcodJ" %s04ZBVLT1OpehGq-lKmTD1(1"Ds^"^Oq(P?^66F9X\HT/&MUTcM 0OA;\<[A=d\TRPmia>:qdh@qi.IOBj]HO#"0.h%nSlXOGY[$mrSVp[Y0NICa8RL-.!ClD,90Hk^'k6a6cin/Zb!&je^@+[00bfcGFG(LY81#7tpAeR6Lb=qT_H("eb:YOiiI6hV*SF3:9iQ\d qs2h->dl6OT#PDQEbJX66i)]FtpBF -g/J^S\sl6n=G'Jr2:#B8)KM./9:S]Br[&7qh*'hl6L;"4f'[e8njR^#S@J6]4DAJST!XpW>?UcZp.d64.E#fAR#AQ"CFqY2BZc+AOK2VqA6I'YgjrfqW1rL?F[BD.fRm6+@2nsc3/liS%:$83NB]RUFI5I; M14H'Nik4^<'eaTB(=6L E*d$(CG@ >mUikAR:"3Pqd7$''eK1^GU`>aMY*;?gnmc_E_1ct+b6LWJpR_AJG$b&?iCaD.R"S7VkB*8&"h`YciIiHg_3%54DpD51IWl=V:5@t\EJ5I^8K3%8#@l85N#[C#<7]!*1MpRCS44&TfRhG_?BH 5;)CoIJsT&m9KBB;C<;WK$?9r(h$W0X5=W:_B+@W>O@dJL cU' fH,8;M!O(08I?W8S [oN8c\,Cc&'bP.;Bh&(+$P*Xq,DmW)Tt t/(Q(EtlLC:fCY&XD0d[BZO0^ht[APo#Egl^c<\Z"FUY_A!K=j8?9#/N30Kc)n78ib8?b^7cU^(fT@q:%(W-k-FdA4Q\_8r9VB]%SP]?(:>DYF2H@);(A:!2$'QhpD:B40!K.BBlUk-,W5T;#QD7=Q;k5,$:!,OF>XA/N#+ia]dUIF:!i"9tl:a]$e2=CE&KdWFBC0mA/(%d$qgD#5=e?R=S]\$M5jm)EJE4McR!Y`olVI#D%AAe[?*KXS,b":;275`hGb7QpHA5/'sqb,m@pXtWq#WC",L35mH[FD`P@mTP8-m=nQ5lOpVobKa##,I^iK=Wj8SN@^^sK(]2\<@W8oKs:<Ur8%E?i(4?H5(,5GiqX]A4:"rD*\cg!*$*(DN[2IaG:l7S+(K@%G%XGLW`5ld VRXkrEIJXk@,6RB4RBbrm%i9rYsE`]&^' $FpBbgjj8[a*F/,7*_Q0"3V"e2_&NW_Q2nM?E@(hjd1lm4O94'_6 IAJeXbp;m,!(J?H6I$k;(n]H1a*p@P:1+hdYQbTi.8>:j.H]q*N'cZ1a,a.IsC@c.rl"*q[s8K,kg:3PM?:t #s81l&,"5]]Q%N1H`D\WUS+AA!'\2;4@Xt*2b:JI2F@ERF@rem +O2.!&L#sAsZ[U]B\O$p^=;_WUPcp $-W/#_@jmh-kiq*5-LC*i>Q1)>7N;k[_jqJ!p^%sYC^*h)k tMUVh7E%P&TgZP\B_^1/SS](B=e7C3?%C=f$$?D+R-R2W)[ln`(Zn?\/k\;%j*+_;/AK9iJ Zb&Ic7UW&GU"b"*sU_@D 3Q"oHbX5;P3`UAAqF,keZ`8 "j6_fld7YUI94*YMRE*K99rnd$o78=?O>:Zh_ LpQ9F_L#^A3QCQ$Pmt8>N^W.)QBB#b/fefCTOO\/C[DbqdJN;iQc)_2K)i>tEN!t#Eo7EFcDQM*/Q$DVq73A>3q"?rs,DC^<@Xa*UNT)3eJ`p,0@eB-^MdL]-+AW?+k'TT"=*QA_6N#0QOFGW\J +CDa"d]!*[O+l[\"D)aLG*\Uqo /lpZS'`25':Se#*7@QG@>i1.@tN\l0)48QCp,Be"c7Vd8C!NOj7,,GA03+k\JAPm6'EkqMBeqlI`0o=jW2AD#Jr"eLF#K#DMXTA?)p\WG.+)@aT5$rEkal[sh#f)7D1:N@J.hLlbZ5gld*A%!]Nj+93+Mdh;e8oRR@(OQdp$:KHVG"_>S+"/0$AKK"iET>q4-g$g`'GQA#O`iA Qa AP+lgoob, QXf&Bm!5/(8N (/Ht#*%2/dPin7^G+o0+$6<8RAVppX4`\eo>*RtAe7)'dO9B[GH:)cl<Aic(Z-4gZeOn1Bf]g 9epr`)8M;m#ftY:ZEMI_8UJdaqj)q ,h\piI:L:%#+*+7o.GkgkrmKBU"`WMJ8$XMWK=hU/AR ZC4IUaT'24[l.XLM,/.K,qtV(2cf:]Y#G0O_92(ALUY:.'q79aqZ4CV%P? VF8qc#^Ss3fGdSA>8SQdK?;MTW_UK"kj2,F#_OA/objAB^k_BZ%re/blK+3Rt lrAJ#ZeACaIA(jh \(Ne]R_`BNQ>b8A\P-"/ABZ[KA38!pWd00d"FSX/]S=CB=,)FO0QioNX76k`K:9,YD5HX(arVUq_-Y0co*V)Z?h`C+Tt1o0e"@m7SVai']@hMG\*)P9M7S">c+bEkkCS>Hlot<dEmi4$KCat_n#)QhYAUUKX-ZU*4O;D=/4-OkOYdbVm)Ng S:Ia5MJ),E33_<^dHQ%j,t*#?M6SZNUT#CH<\a82m22`@NpdTH>(1[6)^ZVlAKE5i2o(s)rskb3MfU6lYlss3&96[M, .fSc`*OrF'.Y#MpkH/pde%<7m:LtYY&V)miFbqegR7Q ACrslZO^J@J*#V.H"r5m]5j.A.U7#82lN*]3'4mC2fQ]*n*`M>JZYCoAr6m[s7=V9Jfb3U3o77(9XYT;A!MY>ke"ni<TYVJ$6k.#. PMphNC_J*bi:DS"BTb[CZc92qjomnC;Xd*iHA3@F*C^Yp?Fa6>S2[0 r*ch2+bA U@j\VAZrA<6[4b08g*:-c&ke ?fU9+5$ bkkDB#9?FP_C5aTLiHaY%D7#empaDa4W%`KV$<"tD,H>GSLPNO'TEj./\m,jt6TWP:*hT'eP[?V]-Sr_AbFZhABkt1n?t0*Es"WQI1i',F#/=?Cd<.?!LhStaQbW0,1DS"<A:Y]5rIq'R<[j<!tYP8^mf=,n[J"]>V<@dCam7\A-[<&3qo:RSSHB8\8qVEAlG8n#$fbnV$5RHEtbDJ-6QA%J,OQ47n@#mO1'2Xt)>_^ocfoAT>Q`>GkdZ$$aM-Y"6acopBLJI!N`qA96bBoap9c5FR&(T;as,B9.D)"6n6A#-Ikf8YJML?$N?eT@_]@Y!R*B!J&`0!P#IW6I`eUO>qm-NA/W#hJjN!M\>=%iXX)Ik6;G`Rl.BJF7b4+Sd7;q-Etb0Smtp`7/02B^]@7>GHJn9XdWE1LL'bon0j)f7=9-I9'5gi)-RHhV?Y+gWL .W2*XAT-qg6VW,)3>(86YA\cIc6%s(/M8FM`/3>#akaIC>"I__#?ls`7PJ*Q@RZK/.-%%9toT/m/V'"YQaV1kf-Pg+$;\*grK1KD2aQM1tLp`T -V+qXm%=$@/%'k(!f?'HY"9")?KZ]<13,lPL A.CXOJN_h5$m`%a[S)fi,2j"C(aAsK#?db:m2EG\ Bhq>Yn:VVQB`VMLIK'P&n$- Scm&j=ilONY6qSNS?@j)'s,(K;K%\1m\A$Y'GHCPG_sJ U?+S`cXCrDAM0_jq3.q#R/FMf2JekA0bWY%UPQF>E3g&TmJZPY1 8bj\Gj^`q@#!DMA+`1rhm:]n!D!V#.\kA485=ACZNRP]m"]fhcJA.@&14C25=Iq]FdO7+XWe+ )S*qre%GN[ 9=$t8,g! $l.1$[MO+FUXqq8o$[dpAA()4[8^> 5p-9i]L(Y=g:M%.EM:nCF6[O&"B4;MQQq;\E@t'/1,NZ>:iXc6 *QXIbbUMA"[jV`iAVA4i%HCStaApU?fs(_(&c-`?C6W(TD:QAABR;-=p1VhDKoQC=Gj_DQg@j?;_"Vm,8Bk#OZG8sCYkii2AHa7'-Eet/>Z`(hFCN ]Sa';LE>#qn5:!a#-WGAQt!r'BAFI:B'r>6nqngBVHlNK5Zf>9VQ9o\*Xi(1t4lJT p#YQ]1c37h`mP-8J ?qRg['1UY2!KB./E,`BP#Ca-RNbR5+#o,npPUNdCp]@0Yk\D1*X/+cog&LS9?O12P-:.9gk`)K#=SWI0]RV\Hi]-b\^N&F;tUQWBTY3"[94O!8mc`?__6,[ATkf-X"-h?Qs1hs\1&AP:d9R\!Q]Ul&r-NgC;&D'_ gdX%j hX[hk:p6khM#7'8s'/AfS1.;FFji7):shg-1?LcP\*0cVT^/g.4WU45eMOms'FX8+ihJ!\ip/>)Frb$pXtIYY;U.]q`XC8'->lm2?0l/_9d$1R#Q "MCPLgc9t M/hASnmMmK[nMXJ5-Usj5^I?Ut$1:O@FYsRm*V<@2W8EhOA,g_Cto"2b#p_"m[_^`Yr%O?g);KE,/C4+\;drM)$*$UZ)7_.:DCA+k2eAk!sB5[I@5m$Or_+:#^`M#L%Mlj&P$XtBA1Z>4S[rf) o;'?;E>+$k38#JNNke[RO*!XBKMq$RaMB%a#]FgtKLWndl3d"OF;/OTY'2a56Q.TpOnBT'c#52Po"N jpRV YaZd6\4/R0E/ZY8@G*epS7ja&_M4W&OI=UjQFmR:]kma"f_3CrNdepp6O_-k&+Vg4-A)H/d,@ZZ;41X]XB`;3))Af12R8d%nqj"9g"%XJiKUWM3'l`:-9<(cc8/OAUK,G[f^iOMoI>t.At&n[(+Q0@pq; l4ket*a10XhApT`(0H@Mtp:UP=5M<$SJFm%r!/J+2h4?:e36P[]54Ajm^#+*R*=eW19S[$&(psdMZqX.P5:'G5'@\-&NEk+(Ptk/t;b7O"'H<+Mg4*Kh7(c!nZNQ=;i_)3iE:gDgIl;a^f/l/Z!7j$;p16Z4rqp5]88j[[>1\?psffh;Yq6DBt7joW#+T0E$b:i]L?&"LR7`(N1cS^a57>O-!LOG^M'bH3VqY];-:dCetc4UIM`ciab,_Ek18dYU"g';'"HKbF ;>fLTPi7@sQ-&er``/-X5C/A.G%q:e/I(I]dWTV/BAj\HjVtZ>aO,gi#o=(;1D%tds3@\T;ZDC^qLV:Wl[N9i'=VWD!j9P0hBZmE>1dDqS][[ABO)H(%E:'R][551":,UD$*U^`lU&9WD=@eD!]R74X#qo']*FEO3tkId2eEb"=cea?@04l ME%QZ7oji'B/l`r+.F>9@/c@dh:W]E9T?e2S?W"i>l/F;f9jF9/do%]S1-9Y:sn[8B.!ss^bHB7[9>TQt_n7W]2f&IK3KZBLAR5M`-:SQG=Nm!^2O=oXjQmN**Bbg82=,?%1 ZRb;4:-tt1RM5T`%)5X6Yd'3`0c"UT$-$$ ipE;cs9ng;KA&- 2 p\0#/YI/D2S=p7qF%W8kD9.T&E>4[d_;s=(*H>p,ReVWnLW-U)X!.A.pI'=Zf*SapAW5/$+fak%QqgRL`_U"CA!@LAAfjE-Cj>A,`<?m+,,W3XOVQr[kTQHY>@1$PE:LSf!'FjLjR;;g%j?P0?LiC!fU[AY>TQnp6[*!Pf60],b_%DI/%`CqMgDp[?3;P`M#8U2BRAm_^PQ_8,cFB!O8*ng9o#^::F^AU_JTUH(IiNs3]a9V;01;<7Bf-WaN`)F^"Be0RQ7LX)oAFlTL9krLkY`V;_8qOj>k#1;Qg=@sNr)I&/gAgX lVbhF.FCEGo2ChEgGH0:&@TBik&Tb7[``d7T>L7-_%:Xf2n.ldtlj>@Bd= j&N[s[R@5cQA*o^WAB:%A=kbN?pS14eFM#Y3Ls[b](spXdn>7[1"(8XY91\g"8jdkQ_)P[FE`O9A?,!ZGs&l8>%1%6EMTA_qEqsEZcH!ic:.=[IP^7/q0"JXId2 8Hs+2AtK5l5ZW^%h8([?A38LIPT`PAshLUs,''dC.6i0j^l.'U%9Z!"YEal*$6s2(N$nM21&T')KNc];JP,K1AZ&HgQ5g0i;@Alof@02jOWXa(mdOktRImheaBTF"+_G9S$6RSn';FoDmm?QeSKHkA7.DfA]b.Fi1k1LBMXk'>K&Al..qA1daLmIQAgD =bl(WW rKQ^kg!0_HL08,_&coL3"L)8Zp(cm;K#J5-)#V*._78W_AR($ZKHP4-:fPm0@/k1!8^[BXSoQD!o:Yrn2"2T^"Jb9s=UDLX5W@Nr@'SmXd'1c'VspfP#7b4@btdUBJN3!^Ye@n\;)Sf#HeATK9mrVQ;='!-::"IJk[^1n2Akm>Gi,e,aIAZ783dI&Ns93`,i)Ml@%l^Z J-sqj"b*a$$9Wj?h)>a6(0a4@^a`NoF>EA2Z"%6O@'9%.2PaXIDk-MB^h`RTrFG"Ki-]4k,[2kB63/da"r,g)*cH;HC-daTZ_,Bk] W:? ?`,e2`=TCLJ@knRUkoM*i`_Ah9PKTTIatn#:pp0;T_kfn+$c?Mq\S$_^Yj/?fOK^&Q$-94\0iF%'8D/C*3@@XfcGZ;K]E*)T%llg]b^SLSt Vrdt4)Q>?k0SQQ6:Xeg@pm0]1>,TnkC s&LKP5n:EHp2")g='d@s)2;-Y(Ud!A-'AE4R dVZL>MT)q4<'9Ymfs*9?Q`d)b2H]Om:]r+Kn`gt"_>:)t7!GA;&6'h'-.\lr'erd(b?#9?9Yk?T%;AXE?=09Y[DSUh4)8HltINi0J#b]Bdt"k,Fb ]NBR2/8_AtKDN06M,(Q*0IVE:pG[%)2l@A`(R$%8frtGF^i!6c*[)*Mc%?+6q[0@Zq=V^]`#/U&BT_'6FD*mS,AHh["]`N(QVo'7Z-f,1_^s&)nG!,A4j53m`k,%Yl0i]A2S6"DHDUN_,kR.66#dN];A$\_ggOGpVsS"p9]cN)rL#C511GK*j9H(K(0dqSJ]Gdb5A!Gmn+hFB2]jA>'@8iscCUTqIJ@^Sk-GT'pR9<P_Wql2^,(O&'An3QidAhi-0VS=^@dbe%;!On(OYba(j[*dJ>5b16&<;>3DZ2G L0,]6V$0)Q(fK9o6g&439WHT?C/W&Mkc&&&7g2V/Kq"_LqJeGEJA,U%Z`^$eT reZ34p^FaPAKF>]3RJZ_,)>=r\E1 I-K)$b+ -@[&ZT,mc0b;C4A@T3,]Q97>AC% ZHN b"f8D *a(! YCXb+^Q8j4V6+*:<]j+De"ZeR(fL(/@Njn5'&JG`?@f.$AL%Ht-:iLUCa*hl17k([ZY\MB kDRh#JS]J.jt@S?LBh0SVG`AN.?!gqAH,4DjnOmK&iG#[P2X"H!fb(35A[cr$HLcY`cp^Sd_7N[]@o2i9,N9Z7:STafZ@E>,"oXL>W""!IsW`n'9%>O9 .]!-O``>qCK02AHnPOAYDK:f][ZX;^E.mF-#JpSNM45q;7Npc;JsgQVtD@dnT9n,SN4Z_8V3ML .Bd1brK:0]9[-'!?gqOl^$g9#he@F/#0AFi44-GFOmX;1Y:ot=40rm%G)rZAp*;A#$]bXcR)FL.ot!/ HGcOY6eboK>T;c`Q@YZ2)E95k0(Q]Qk2mG!lA;3=?"f+s>Z9gOJe:`%EA]IsP^bL%a0'Qns/V/oqN*X\A*SWV1 7H.;U)V,f?6l26J)'r9%S8DHKYBSA'6>d#Y5bHErPHIH)h ; dcmLG9=WNP^dV2+N;./c>/.'Yg,G!Z ^"c6S3H+AJWf =i\^@CX$IFJnC(,AkAGfY;jttXd;0K+,#j 74DomGDbk'5OeaYs;*0R0b]$N4L+#f"s?8$`t9;OG%Ya@kQfAANhdLr=qRH:2e"T)/b`Bjg(gD( 6Pc+^[&VdH@`B>"qJ8NAa]8A@t%qd>[l]RHQ]pZp2\In6]5?]l%j`&A)5r2IQM:;Y9rN+PP*lL`ZCP_@tq:r%T?B_$39l r\hehLm38iF,_7?jQ"=.\Hs^+nEs0Jp3[d.3mjc1]OH#`oM#1ikiAL`]8p&>Y>.AKBB4KGA2r%(Z0K1\QW7!X- =.BLhN=d3as/*B^#MY7W>5hH,55H1,tMY9]Cs?H4/6da 2JSJa/t.(Ms+LPPirD0MXP0!NF6 =`!+`A`RfU,&d3Q+lK`,e)6$IcpA]r0mMfncKc[1WetLAXiV7]U0AHB3/"nBr'kYZU_/3:joQ-*(OE.2,@L`K cM;WT3sF>(s3=-i`o!-XdtHROf@RQKdIh<+\b,GY!d$r.8ho5%KDtFok?`?bP6:T+D?(qj_=htP0r*[6B'WEt"m',f^<\`noMW!_e!c3Gq")i?spm/#Yp BAQ2jmc9G "]FA`L@8h2aSZ9X!Ym`fKQg%ViTALaF&-3%q/BE(s/%`A7q_lf8DJrfgT,'o_(dKBR7j=o'G2Y6"O`<-OCWTGRV/=f8HPB:d_/tg)@'" DjV?mI%[4fE^MtHE8eeH"h2pS./3#@Rt0%T"-"X'aLPgmk&1WC7^$e,Sq%Zm;%.+=c)2MMg2@k1JfBNFJO20-$D=@abC+kKf5`\-g9L:tll4(mq\6X9jH(?dUVK#t>9J]H0?EtAO&:BW_pV(mCX1qoP1&ArT[oU_NWphc14NNs60UO9]gbTH` >n!IH%IO*(FaeHm-ePb(>t'beip%>6(FHP-)+JGN`C>D4ffmfcYsWcmJXBpOVON4``0Q SHQG?@!cW/hoZ ']MH'^0T!5"(i)h]Y\(9FTfJV:4Q&ac[Z*f:,@(pL'T@0:ooO73t*S.S R?@3gc+=bcCM%M[$P:K<;o$J='rX9Sr h(fI^fR\'E/#][^@Y$OZBe;-88NUnS._L,N\$5cs atk#T3A$ffIU;''(A$%rrsBGD;)f.Ar(>3/\BQr\Tp@LX^_71-\)@q"5U+dG\m45Z[RWI,RY]=UE=nSh4\4*(F4K?&Y-XSFAP-irK]<">lYQ-?o.j_N5>#L:^aaA?%Vn8VQ3'@m*sF#2Cr^CNV!f"S_WMCICaMih:_?p]%MLTPB6C3o^&L!<13?gm_qY)o9;2hGRSJoD;Dt-#Yn#e;<1=OL7LD74Srmp5&UAq(t2;"bQ/\5n.@$kZ5VR*(Pd -Uq%T`9j[S4J@*g14fA-LLted[D.m7f?"#0olA3Q8%m4KIoI("&Ks,.d@5.m%7S.D*M"XSC<iUQRKUHa%e%8LWNS#]I6]](9""8pJL'd'ba\l%9Rcq%n^hZ6'=pF7^rYsoBnGcg_T+MFV<k0-h'*YjT[-#DfD/L`6gqp<4M^M?<`Dt9NU^!=UXV*Y7'P=jA.:-^ _hP5oYKAgO/-VA];+43=cTaOg"(G`@$6M-J*C2.jPo9)Z%IOq7K'5",U#XK(WTc:D*s0oSK%(pEl.Do3Qof+P9A"Gs &o-20FR_;G3Ab:KV!q>'JBX,2'^>->L`,,8odNI"\<&PEk%E99kZB'#\R:.bgbgUj5**>=NE ok7F-:0.&DXk1Y_h(3SI4ki"GTe@%(rc=t4>jk#o!@rTC97+bJtVnc^[*tVpW*6NIZC* ;kAf*))ghWh+T`47Y^6h?s<P*0ds(h*"8Cd$ ()W&_95S)U9>t\MZHTgTBZ01;3;TQIMbjC\PA]r0$D8Oj3>n=O ?N\)E e>a@\+AS77?%N1K[qjLVAgob#IUGIFa8lQ%tCBIYXCjf?iH.5]j5+*!k&DsG_E_H+Z"(PJ$+l'PRmA XO>5BpmN(MqiNP*A,@?9Wi44tbi4'0'W55LNmM2AZfU;DGU^l,g-XENS,rh"ZU$E3\=S&DAEm9r;iK^N-]cF?I>n*ZLbA`2<5[7KBDLZlA1r1%ls9R;oNZJ.9R,]eQCnhBnF)bUL&L.?RYSbFONNqAka]OVF*#biD75m(&]@k6d5%dNiCs#NN=e\=^itmKL*UX )q\j=hb'J=.s`QV2hFD1K r(oZ(lmdXR7kK9`j?MN7,ghZ`r0N:_>A Z#kS(V*C Y7bAeYGTpK%;tl6P!>Q1W!SKT\FS8hq4MV*:leK^H;N>pFkI0)F9K7MZ1Jpi8Mp2T\_(sjO!b-Eq2r1:[4%3V%gC)pmecS,cs0GP(/(l?X260AgGL9:&)hbAUX0q7Wl!Vk9$D3.X8#,COLJ^a"B.KbmT.*%eJLl'HM'i81@)>>qfq"HJ4IZ*e[&CF_FgnM]WT%;Y.H2br/ir>G-]="3TJ]/Z9&1i5a_DArr$d6ST?+ 606gF.trN;AQg?2TXfUmfNE0P*Tt&AGpK"*,,]\k':dVcTY:GPXXW=6\cf>C$F@-KJ$B6n2ZR6U tYkl-'1D\A<l=2E9TBINsjp1(&tsc>Z $"%O+e(QUcGiXAO8JtZ8 !K-O]NEbc&R*G)_:D^nfU7p->OA(Td05*?\`A#D1&$Z,L7 3Qh9i)b=L737;!*a8$%j?Snd3\tr>gd\5tXUWs$!aB*-67+&l*TL/`G;c:^\L j=pV5:[,pE`tKNIm:"r%`b&^61IJ)$2Af86;=AFkQ'4H<`L/S'X.3[?VXa7@WiOQl'oV?Eg"j;m4Zj@$][-.4Ak+3DqADc8+<9rZ+h/%:6+OQ=4-(^Om*s"6hnAW_3tb=?H5>"f5k$bD]a1ULOWdf7I$/j6YeaFq+5rrJXWkAGL!;Cq.P&KD@IJR1 ah[nI- kM"l5=bj 3O4F%P8s\M4T:#aZB 0"dgA.V3*9L[n s>F+RW35/TO<.5iX!P;X@OVeZC=p&]LO1P!aGRn\!MiYF>n`ORkFbOenKAD!FKg.RNAl2jiE t;,;,i#k]n;SD$c+1b9'j471C!/0I RFm?:h,Ac_Pl8orLp4&A@oUX65JFZ7,;?$ZF$c)!Li9Lh/bLr]gCRKA#U)ZiE>g?jIrAR-d^Jom7ON9Y?^kaokCpR'QhF8M86-4g<TF8\clNT =K?Y',qiqE&3F4,T VU8f`K57\j@!sO(Lbrm$c`GYK%Q$fn0P/,telXc->@[Bn!UB+l')=]A54'PjY3$-4870FO^0+/8_BDHd.2^4.`(/I.dOY98T0NA>)t^h;5*:+KJ-6#@`=B/t@hHR#p^m&k!;4K9B^4FMr &70R(ErANQ^7U 7E123;pZtT+72f69F>4;HDg`kAg<Pp0IBJU1]+cpM9Pl,Ae8X5Fo[Z9[r(hEd(>hLH@: slgm+_4Q@. =qXge<."NP!0A5]frD]s%/;TTUDfZ]*\p\c"HW$=&-#,MA_VE".&+o%3*P+O?E$oE>2o/&R.ce-ST6kE<U.G^PPZG#;,8:E?b<`3QWMa>!X6NOT5CtIc9D9\h&YbD%0WAPh@#3KK;UgB'XOp0SP9/6T"mA`>CaBeebX4eCKBWtOc"'HjS6[.*YMZ5'm'R)_88g?P.cEnRBb+C7q>Q@TVX]a-DfE,;Z4n[0ZV:TGQF4>cc\IeJAlhNJ3`m4A.4;fOtMI]E/1C,%>UrO,spXDX^7pZe/B5@='S7ChLD1DiY]U6"VJ3"pUPJC!`A"2Whb4]c:.]4B3"#O+Z*4*%aJ8BkP+7E/jDcH!naD+iDmS`3QS%OBM>Q'cZAaZ!a#Hh?A(=H%k!;]/:AnH5o&JrV8.sZ%c=S0)oA-lG[4_Y2TT/KW@:^gtt$eq?q]R?)ZEC`Y!^O&/k,I?A3:]<`2:As186Y0PPBfDm34gtctp$8@F;BVd(,4h4[QAY-tH!TA*nY []?mQMIe^R"jrNMqs*?KF$q*00tT.l7t0M9;S>]MOf=]62.RG`arrBH.`(ZP5&3POn%=,aSEW >Cb&Zq51r/^MqQeX!a4U`H2]$$4OhKag8jdpk-JALjcp8M^J7*ga7J0!jTBPa AfR1_1aD"4@CUe9) k#T(*3WG?j2%-m8$3>.A02XQ$(P3>IC7AL:kO$7kJ'pdWi]A-)tlA&3 9dh@ L-!oa0r%7fg4i<\TejfAKt?FVHV9b&3Kc;fmBi`TF9f'\Sqo-J%`F8,;-&i3=B+F+>qWglV;!\T52SeM0X^D7nYjm<@1i4]j/X2Sj[L[5-8]r*^h2_Ega6##!9Jpr`a%>+1RDg/9"G"@><97=!nW>cg,r=HP2j:8Z%bM,3)&^R+=dqhRmLgL*p%Qd4cDnTJA_\kT@E=_^t<3 TbBON/N4p+ohs=)8d0AT&[[GU6rQ)U=@AS3!O.:ae%$^a:eF$E-B*)NC+I]RMb(OP:DcGh$/kmKC^Fa*(aQUa%aIhe@fTj`SO3p2hf^cXp],Pr+?^N?qi7.+PdZ.Mc7gKP".^,^M^>)Tkg,15F*OZebWqLVtmjP_'tX "dJgUs^=('a99?t%3is^Xc=b?$+R.TVfX7LQ_4ZsSs* V<E%#6d69WI>:bQRrr<="DSFR;h[*=Aj4j:3:3:&n$LA'="tGLIqr>Ho4k0[/k;$_abW0=ne4`NlXo1!VN.sA'5'eZ&;%9kq)#s!IAfo(KD+?ds*nYSVcOrhn%PFM%hQ*Zh&ArDNHq3p7TS&Ans>Z:;@:a3:8-T#rQfUdad/nX&B/1%4SK\2H[]k(42sTnPa-om6ofNB52NMl('Wf\R;G!h^WjmtRS%`R's ?A^KUf<>E)aHs)mUo/U_-,1A(MS]C,0,3Hkk6QKWYOCBhMp"o.T/mi]3Xd8e9%296>X3>Kd):Fr41"T::Fg&<ht[WAFrshW4"bL+TmSsj."XRSW9gV:hBk&/'c.K_&G8tf.$o(W^'EjdR=m>k#S'JBX4p`d+5[V'T!rHTV!fbSRST$kr8^*s_4,n_HRXCOUb:Qh<:f.^A*6T@nb!eiPa$77Q;:-2lE=FC9"Qg<9>8API'1:-B=\_X=)8'UrRgU"'4>V7Jr9k+lPGT*tZ((i.OfYj_N\PPQHXA23G5pC6NgFAYJs0#+'Ha`1hVf/>td- ]8T[c:qm^IkKp1*!c1)m1lYmKj@V"GcI?^ss;ZJAk%SnNfbPPI^>t:Bh-BaWK.l>W!ChHrtKEZ>ee_\MC^\C6]<:C$]Aa=PnMq(l%LsV`b&A/?iCoX;oXsj2Eh-NEX_'"$p`1SsA+Y;@/U3R"4TmTtRS1PX2-N(p(tE%E[!f54H X:=RX]04.tMH>kd"_qmXao4"PhQN [)2E3X5^KFGUs^*6nbXPPB>`*m_X"bPRr_j09<9&MUXsHee&m=pR[d4; GIhr[^A-m5:MN 0BfKb"V.72m`$R[rbZAk)o r%KqQXP;kG6AS9oUk`rt#i\T4@'EhXWqDk)s2%VVKYrf]>lZf;4CrH&LMT-4_(AX"amL?UeerlB:f&+"ko?:K e4m2!=LI55i;jg,-;NXPU3gAhbO_7Ga$,1FG<)lKK27]2468]I9NKi>c"&B4E%Ga!qWcc>A0Rl\EtN!dkfkBM@.+dS^`+nEAiaE jP^7"k5do[g*R"eZ!NM1_oeq+?E95+SRZbZW#mq/-p#jL65sA[TfB+V_+8YpG%CjS/R=eX]F@hf-H8cARJP-s2/A'A[s%+% _d_roE_7!J] qm>F1&7,=@0c%0o6NGP%BA*Fc9@jmKL_"Y9PSG"'FJs#Ki+T'cSb2 8ZA?:kYUQ[UTY_Cl)%9.'YjB c%[-c0/h!S>fOFV`7pFcXEo$/.k^JA:XAPqg@\ ?tl A(;C,llcO%HbKGJiM7);(PK#*6"df'QK@7>%_ils n(J=\(=2mLPK4#@.k_RRKX8qAeoR%-'4(#cF!Aa9^kiF8gInAM@1J#cHN)D]eUSh%.U=4K#<:R;]ApDS!N/UAA[@KPPQG?j'-5HoMK"a"P+=6E\#a)\/'$XH:f9AK6lAPk=HH6)&a=,[L\[00iK8Jbgj-lqA2jX#fp^Vn+D"'fWg%pGM0L;eLW-]]k5a/fhh,#7`75hhR/a*L0;3pQ7P8$+le8YQ0$lGoObrc=N@fA`_m`^S-C-:e"!/GZ@"g2;(+*7AJ*K8E''4_Bh(K0;,)3, g't>enZq/"VbTGnJ.r`9Zm\P@MV2Pg6b82'$X5%C*ccs,o8>G'2Vnmrf%7- Y<^>TL#be(V*ALae<3r30r\^=a#^o!OA"@F9=CAgO^nUC+*_%b:VZ<0ka>XB#,t;4]S'Lf[3j)7,Yl=TrK KmJ1@%QebB.J7 ^F=g)"QP,LH>45bAF*l @Jh!ObUpj;;eH](mN#gAiYNW5VrcfCc6GV*aGnPh'S@0@0;K\it@r`lsn`hWXa!mQ"Km gtp-:^;>O-4kHE`*MrSq)F^0RI<8mBbo$=0e%;)YT&2+?(!jjaT=2Qh+nr=#078':9DA9m7 jH3gh5YM\]XBls%gibpM;bm(T)ResJ$LGs;W`!GNs7R387UL3@CoMX^,BaUT-Xaj'6$,30i/VlT08Ftl^R M>`ltK`/?.N,MLGN]?T:<Hl):)U/dG@X:Ap'k16(AM-KPd3]KQ%/=eGFLi`UUr\:?>A+JMa=C^?&(5GchU!AG]GlO<`(qinQg/2t7;E[Q4>8^(A[>$MNj4=/K;S53Kj1_[(7%aL$.t^XltDja#<0,.#b0lYG%$9SAALMIcSoa7Gl:`G#W)4\mH5"MH+WL7FF0EtR6K'.^0Qbbb6pkdB>]6/Fk#`MPG5BC,V6BfQA`gpEEs(*M?rl>-RI"'b=jEAtl9J5Fhr,BS?EN5#83F<").-s^i<G(pF/=BbrD.o;hgGmbSC"0Yog9B8i,??ddI#/FD(WZkI^?(G6,$2[nE?QF+THAUsc*SRE2QaA;Z&'d5QFW/F/K*HB]%VeNK6_'XQ>">GXVQC] 0cAL$p01/sK\ !gR23"/_nA g5\"'Q,(mW@hMd`;-S^A\d_d=PP2AP'VC48n=&[(jA\Y0DRiID>6$hAN@ M9=;=Do7=MipjH\DMefN/7Yt/h/e]AZr'6XQhPVL5b/.?Y;S6h-cMK`-Znal'^>.E>BSW"<*!)h]TgMVSBeV<-0X&olt*fk^3T1otA@N>Gb,Hm*"MY/%e5[j6g5PFUo+.qO$i_1=s8mf]I4dRSW:4da'CG%"H@m$<_cC>*#@V\k<CUit>TW6+6i1&Fqa5Kmd0LQH7[EV``MZnlDDoTjQfU[eXQ3RN=SF+pVc5o1Q:EH4gojn2$Eo&Mf3D._j(`fcM;'gQI>6Ec&qO%55jKt^'5AF=]$a".(A_Q(p_KhMeD(mJ2H)=gm$L"`ED1hb.FY`kR2>FcS6Wl4(7*=F9l,4`TKEB=(5Rr5"P ?h4$f.@p"gQO[C>n(gPR&l>gU/I;.PU1dF4DO?%^m?AM,aUCGaP@8_>ABJ>/jW)m4,'jUWTFga=LA9A6GnIr[*r9NDRPd,8\S%JV:b?8J"Af8(tf*6LS3^`_sh86/FZD0h'.OXjmoOOipn_5@6EhHgg3Em/k9Z>C< jP;[EN4iLRPa$\="`RLH/7NS?OA /kCX/:Kl6A[qZUrl]dgBfYB^WjFj[Ho&`9:s8a8ik/ ]d-=[6F[*>30 )c0"JQ&!n1pde8*2Ug?0"E>S_1+lL,eV_>16D%8iWW%?^\cbNC?hQ/mNla l;fbt_!NqG!!2rO\=pH  fs`.=XdqGr!AA)H7H0lsAhj;O[I*F^[T"Nj <,8'1F?U\': ;JB=E @L0B&&4E>k^=oC;(ARWB>RME.iU,nrF G_U-IM!MjZC:5h4?tfT_GFe??DS07>U0RJ(r6&RtPR]GSi ` L!aebX\<#;-L9ZbAR3f\cs0aXj=/I(57(P27:)?i,%[9WC##2I@l/MNB Tq4g^@PX"f1R3`)c(G?AWG9]UUE\G9&s&05dOAJt"nmF7I0rTe\U"eUm;H&]Nb*J ;k2?fLYAetX7.FH;qhPO34e;dq?_6 4W\pQ[-b0]q]f@8rSkAhb,[0)N3t\CM$%I]T@J&1McJ*QQbK_%:tH`2AAGo/nAN_Jms5N<P>f2Y0Qs3k`<9p5Lm/C1[N#OGK?42e(7Zg>J%"jT"LE]pJ&fMAA,Up+Jogd#?A+HI[8m75=C5/g.SpQC3bkVMlA-ne\9Z%^Mb:G_*P>s9*?l'NU_OTLIQ3lgp$`T-AhF?Q8W,]t;j?m^1"C0%L`]9l`WA%A?AEhEqagE]l*c6;AK7HBsZ!O ]!BSebksPB,p7T@Q>5CIsRh[:1Z-*(g,s\I8o;ZFbE[R)QO>&.1fXW;XUG#7,ibDMQh$QA#,cO\pa&G]c*"2!rZ//k0Z':#"mt&!)[(./8VSA\X8%teD@itpI6 8lQ/1^_]a cKtH6o%*C=AOC*G+Zh,7K,);9iVc?bm:VAHT?/_*U\mAfAm)oGOA2q!6!QJi4"`hsjR36p4K+LA'pt[J;1tEZTs!h\V>G<,pVpA0B0"D&ckk,QCRX]K2]*BU>8![4U:o7K#F3$H4mI"t?r=%3rj7_I._+CBYa]V_"% n%9cN\)+FH2^cl3mE\=`)OLeEKs0AFIFBlGtd> kT`s4Ql9A@m54)'DpL5J:Qc3:gK/`>1AfWHcA(+6e>P&]9'/0U`(NpFd)A$MIFPM'ansaARG*TH$dHp@@j$&T+]A75M7)+gbBDI]ACmr"E8kDqA$JqXpEtH3Va?QOY&!A_=/=7p.&cG5_K8Z?+H$rdV5p?3ATY+.ea+k[8-Q;]!V2\AAc5g24:,^MW?hc= 7tAeqM='\hjSp.?p:O2BF8$TkH>#=6:Ddd9,RDqm61SIQ(+_d4">YB9et:P[4s>6>ZYeL*E415.\=PJ;eWJ+kJ3':`s^H,/7:iY1=Ek5UK^8CnXV[@^ dEACT^^;0^H\GUFTa@oRb-LEcKo33\Zl]0*`lWW4:"SbaDkO5)"+3X_,_!J5c*Qfb%X#Va^6oV_/V^[%IVlYI>r)@,*D%dY;U+B[`\L&J/XBhMg9CrTl7FrJBJ_$sE**8i2ae:E68aGQVX+Om^q\GM6q2F[m[[B6'h"lQ.Xejf,5`H%[Rh Dhg59IPkQg[@UG6l->.YJ0PchkF.jU69ia*L]NBA^MLliPJO*UI&AZNDf%qX?5UXW_1:AOFkC$I$Q6/"RMZ?' K;#b[7IZA:;)'mn9oAc'1"'QM?#!IfT!tq+<\A-51sS^s97deem-.JT]q)7S`(N]6,,j#8G8TCC/M6'tjhLIs!N?7k`F5jsXQ/^YV<1l,#![c`mT6F',B4 ZRb:=m>!Fq;jfLX:;9%tQI]&NDA7U1a8k=)"AY5I-tPH#$tCOEC,->'se."W%R"\hAiVcnMr[[;,RP8#+g;.1TYIEK`&NRt^MoF7f+?>8`k 4Vckq,7.AJ*%U5nZ&1<8B6d 7U#aK^NeRQbBDWDhSD!?q ;AH0#[b/M$0Stjd?p[*rM-PR8I=rT,U(/E;gP/\@Q$ZO.ec:)bfK^189OANN'iYO=PEe!99Gek=2BAq\ctHAfK"A9B/Qr#"=YSY$N$;OE"Q*Hs<;N_OkJ>U:(BSS[NALge&RO5^]XqCJqGoq5MX)b,eBV,6i]Q)a.GcMpK#E8ZEALQj`VT"nA_VCjINfki8V1#KOMYVs@6*$nt". s^KA(4B-A%>H]`[Z732#CRNFEZX0*XmWcr`V$/#DNc(a. N 9NY&-i!D&]ET:/pB1AFsBQZ0>.U!7f4pAn_rgO8VDWY7ThT)H&3C5:T%@AqIK50Bn2:f' oG]8^$Q7VQ^N=TQPrEm)^IIbDB\oA;AXk&F;*rPl=CM6-5fB(ZJ>#l[+(=0[HXjC='iaOHfO"^BFjN7YB'o[,p:Ei%HM7&kZp9"403BHU#?GPN m+r\2j`,T*XL-*d LabS7 Ke. AtPe+9h5A:rBbLDU&MYk,Qg.V;l30V@jM(ZsZ1.Ic2A[oYE/Hl`8'1s.AOC$* 0q(^1At6LA.7Pb1*'ElHDN"CZknM&pK@+MG;2r8SCWF3g'YRb"!CcY!+$rc]Fs3W,jO'dFE_7Bs;W2`SK&qLYo=?N<A%<VD!nAo[Hj?bAf_A*Af*PpIfE4Qo*9RH)RKTI-gdD6/Rl:G&gGG.\t"DeGGm`.7oJ?#?3>8q8<`CE$>p0h0pk&E8!17`N7?XmSEZ4jA[5]&99$PaNUH(-biCJc.IGrEP*0"Y;J%/Vm*A`mmT2KN)iS%BG 64Qk?@P/a-Oa6f5@0W4*I>"eM`q>X)_-L[\mmm9Zqbd+#rYi&%@\doT:s^nMTa5]].d?< _,r"D(E5HYdk4GdYYbN]h%QZDi7]oc+l&b`Ld>o;]40]V"V.FtPF`(E`nE.]c)=NfAN0<&+cRhi?>[e1/i9m4=RM&<;GW:VYO,$8gb.M;4>_7<+DM+.9/C_[F`DC8iQ@p;:ji-n94iBF-D8o'pO%9%ANb>4($nEgT@k2bGKXUNp=V"Y!ZKfPr3BjT&cOLLA!/Ne`o^+W02Hl3J]_9q)AEqE)MdYf;1tQoA#N`jb"*A2FiY!-E#Y(OArJI+8?#$?Jre6gmP=R#bc>m"/[U0N+l# k.5IN%FrnJ`qIerjU(:D/\ZF5l4`3qYppHj?q9A9M rVrM5M!ng9>Z .$^2Fs Y:tr/AgR_]^6^FRi+8#kss[PBAcW#KGe@m8?PVRq1A#nkFNiT`_QfJtM'M-sBDdDS*D9b57SBX/e4hR+b45<5<+X6i22k3LP`.X1:gOVH>#mjAcq-jU&f$30$II3Jpl76qKf42O7t,s_%NRVQhmQ2Zfh/?bX!S+f6:A2O1OLM4-o+KJrA1d>2B*\F@o2g25^LYfP>r,!gB.DbCs>dfAn?p:LZ2V2o+&$XaGhB&MBZhZUH)oXgD6:pn*(0j6K=rH;6??\Qn7Qd-XmqlA.$YE]`54cOA3(["9-*\#t&jd,6eaDA6"D,\2D8"mCM9$S*!YB8A! \<1P9MVXgVjp$V*ELGEY*>2%EXTrDO]^.9m:mmh^nV#,o5)$2.!["@N5PF`:(ljL[^ES^"1V5g,*%\UfYJAlssgLlT-+b%kqJ hifHUKKTc1`hB&3@Xf/Sj;((5HM%j hd-i>k\4(d\@8t1gY!Q2SF>t*O&Z[?QYdoI_K%NG3"-dLTco&-,A\LY9s8SX(K_S86Q[I E0*;!HU-)Nr* d1Dhll_G_O[c6^"3U_6^`O#]8.6lF[1AZ=8&lF-TSp9N^9Cm'rR_dfblH%KZlFl!Q1ZM]`oBi*YA>"dJSO2AU[5/R+`-QI+cl(08btkfVY^$)TL'7W`#,[*Xg%.=sgDW:D-$!97NarD.k"Ya@XWOA:Bjb<B%6I4p7cb6q(*D]0+\Fk%g-2Jfif1pkcs(!ahc.+EQE_e"?=H<`[Tk<ts^=K4bX;5lMB.D%jIGc6AHBc\gUP#:f!89g-%ato` h>TT;Ne>bo=?cSkQ/ n^lSUMn6k^+;@]n`0&"V9tqlOi>9ZCjNr#bof6(12\^@fEqP?F3U!W;6D%WUd[>.SQN@,*j:g;g.hL==7YMI4$[g\8 cW<.:8gQgI$n$=+kT F 0`"e+-mp9Nk52!"srFN-hh9ft2 =[q7YDdknBcb(_??0o] K\+35LFQ+SKUl*f^8G`b1 R4NKb\4Rfj4HN8V7>"Fp-9t`<R*H-*O^2QTEh6ScZ#oB AnS(7Y/40ohoYI`+!Q[2(s5aSOOQ;0gA5-M_SEF=0O/4FE\!C")m:SC"]@^6=%6,BPGNM2mc'Qf\8<=.sKAM)Cqp="[(7`U(QL*+JjMnVo-d-J"'0,gWsff6[3/<;=j@^Sp? 47p3P<&HU;2G0;G[QhJV.(m8Bi!DA&GXQdZ4>kr9$Q?+%4ho=WMFE&B4Q5=AT6Yr9%?[4]&6<elV0,,p[GMo.1o(gj#>W>]m6g:`_DC`B3!kD\-/FO_5/iI+5Ls[p2A_b,8g_aXt^g7ST!"U\a&AfN=UF CG^X7I^5/VL&T7pD]A:E0PQg;0R\Hg m&jW:= ;tQ.A6=F=%:02SI"9 ^EZg11\e0=2eF^/ZSZ#h&bje9%.H4q@'p4*YrB4+ .ZbA-CdN\30^(JNk6cKJ\Y"EKH+STS;Z:UVSA1mtd MXd>*hfa'(A]?p3'?ZNC4p82 fn*eZLC8Kp:)0@mIj2)";9SeqtBB^+42=Nd3Gr^Vns3<-"+WF%7$ge94WS"+%[;^#8Ug%R&spIBgUX/HJ(^K@BJTeFYGI:jdSNX1Qo&a.OgOt70s])D ?S`\<#-[S[W"aQkA0m,FaN+4:_%F +m)a%BHkXB@Y61/0 YsS2>.NlnYZm3&n:rQEVZ'h<4^/M[@$qaXM#X(O7j/_iekr,*7M#><$o:f-3D:mUO2gTK82A5,a.IP&ScI+tIdM$)E%T]WnEooPL&$JqoPY fb^D^&.?\.c:_tm0AE+MB_B.'pnltbInSb[.o8!2)I(XA3_+a?#DA4o[k7]2%,B]I['0eoZ]t,,sXd?D+AGN@-9c/2Q9'p(e:,hh=5JZjZMg6\_.n$#mr9f[-A^kY%@s(@Z [8m24'C!,q)=9*Wk$,,,W:#\?HmrlG];sRATTY!29P`MR3B0Di&b+_h_,jrA0:E54>js>bs%8).Al9_(?6Zn)JLa]S9JIApaomLeo0$sDEe0V0,WVe(WR>Gb5#^J$n+7_c=V$:l([4G*eX=2b3pJ<*j.l='>A5OhP\;D1nY%91q)!>*^J0G&1&k#*3Spm^]3r.rHZEki),`@4CI,2>mJ"QXYP&k^nI4K8:G/2Lc!36TC$%:0 AAgP_D']j.)sQ =80_XNqYt?E#S59#CR`B]rG';Q#tj^LJi'SQ&od9WnN]CrNf&h?n1lMD[nHA>3FV%=Jrh\kj'$&$"YrQ0k$2I:8#.!07cL1#Y8a)K[r:eAXSOJK/aW8WAd8Xd>hWLfrDk_BPN XW44E]h:#ai*4)k%*638_nj^;grgpV&H%"4Wti8lG"J@>J+M)#hdtZ0E7^?7`PacX48dPYEk<#TPH)$_Q#,d8qi`IA$!ZmYB/rXIS];mFSI6VUAr`om't&oa2g`th1F]?4\G,o%>t3b:4UgqbtAqHbS$#cD8I8k([]Me3Gm@)Fq\H"$V(s1h?>_^Vc;a9]kg+5\)^+MjVj07]=JY6mlk9qZ_:g+Jre%+T fQ.cJ9TK%YG,71(:kV74(Yir%i$,`g#?sM2Q1a<]VZ07FX/A=qb[?1KH!\nSq:kLTXVBmW?WY"c])sTX<\6rGL3FiRU3.sB<60=/,h's3N=>qs5Jit;O?nEam,7757l=6LA-.mGbk3:q]=#oC8S_$c>mGLEio1K^'/h1.=9pBB!9a(-&VgPglM A8c14j1O/'8M\M3UoBUccC8roZbLOep$ND=bjQ(2%.1C"M$L?m$3W\n6K4&7S!g !4,`pEJ4F5jAY$E),dU&jUiiC4><&!rs<)#?JoWcc6IY0qtb9%NF\/p89FWK>WH.Jq&HTdgddl3*T%N]0p !;"2GWLf[O9KWhs(h@Ac[oj5t@$P2M.:A>PfFi;3*Pq?%MX0Lt)hLh5 N?D!si%hn_Btp2Qagn>T\hU4gbMiqO1.'gaJ"ioTbn_T+M%hgGPmU$<0Q*4rnt3bqR3)d3kTnN0m\;a^W<#@MtdscIR'HZjl)01*Zae(Viob5FC?O[#UKK^Z']$CjtT8B[O/p)h4Jm`k=2c*B=R$6EX*8I*[jgd,>)sp:AT\fAZL?G7!fBimJ6+:O(j/4o+CX A")c4B:8=Qk1V-WJ.kDOYK8th[#Rmk&=f4c_f-R#K*?U9%,pNKDeL+SHmbcL(6]Ti<S4;i5NKcJ2&lm$C%?QgT141 iPob=k&RYraoEj [n_gdRDGnc^qW2srXg"s")HY AAD_97N+XYql<$@6]1?Ksb@$='?!RMK;IAHH_k R`lWbJP\B;XAH%gWptjHrN['tc6h!$b@ l,?-JU3M\WNQ/M\Z.k"c3m#R@]gP ,WAa/Aj=JCg2egdf cA`_K1nrn40JM+[OFk:2.3J5A<71USti8Hg*%TtdXPj4"RH9m]K?kR<pcZtGHA8ID/I8fRBQj]kB&\mU25<"DTp#G.1N?54i4bX;(kH17'r[7]VUrNnnN! H$&;>I#oD*&2EKF5.44;Y1j0[08Mp[n$+/eg;Xs\sfm\YU+.XcP>?sGfKd3QqC\JRS]ndgoko$'JYSq_/QDfAQK?9fT2BW83L*1E8Hf%"@(]Q Q)2=g47THjh*p(_#o29^/g7`/'==eRQ0[Af0`?&^D]DM\!?:+J X2bG>AiJL#kjd0_1"IB%)P'5o2Vb!s`6ASOobS=GadjR1q:MJAAdtIV:lL8eXF4K;^\iS;f>5fF!TD.tGSJo9qp,]!)YsSn3VsiUtqRq!01`QG he7)E-sBRXgM67Y%rACGSM1EXn\R7$7I__*kr0A8"3F?17i%4?@(lQNCm)acGB;G3I+i3rO)+2"T`J>A8I_B=*Q2:Qk-mdJL^3]8Fj0t0COl^Ln )YtroDj?J_cJ*%".F=Wh$=tO-9p#="/Hr3n<`b)03;iOXGGdDNAEFA/s40;X@9jrk4=Y>7^V4s4e/]-2%cL`/%H.#C/66h0aNi8W+6BPLi![ n_OcGFibhZ1c=sO^BRO8JrpE8n\15]l3;9Ra?;2X;c=dTZAkjJ`sc@SIAkoBIl$QaJS&,o"B#)(ec*[ehJ&?ksoSn0RGC#ad\@WCe,&pDS0fmJ`KE.iod_8cQYgO6p'-G4?"\-5`_bjs2V)t)3-Cf:SqBh+r_Sl[8FJ+sl:NIOL*E)/P0 9\H)Z<$c+2fk,<)$+=5UK 3_>]QWK,b3X_k9EI2Zn1.OAJ_+Kjc:.>iLGEUFV#U;DX";n!SG16@3fcP?[6JMlPs"-j0J/:i+1m":VsTss7E-M\Q(VR!;R3#SHSZl%JM Y[@,-(n /;"h]WIIPk+ UMD1P]gobmSKsdM.J4&#P3M9:ErT8%A/A+><`oO<"0=LK;c2Md""n]o_TbOoESkPN>Fr1PdB1j\?5*.V,)RAJWW`@csFaSWE>cT^PO3EL(=K%]=3ld;$fISk^0@40)o,P"W__$Z&Mhg6=.RDj?hB`''9""+8jeI5,O:s4.[ODpEbr7cL8YA#*0l[0orYp?I]ld!98YXkL)XQTDp:?Q"b<(gY-L*I#f,]4l_PO$&o29Jh3)5Bo^FLs`mbH[F@kNNAnIR:aR.E7 !2U9\1RiE+ml!J?ZTWK88Y=gAoqE$[iG^2&#SPp!+_)iRrjUBm&`!e@]b.d^iP2eiVIQgQSWJa]2Ik^mQMPJDO?q?7"ONnK*4$n*jG"/pK*bUBHWoM#\YQ1D1a[t3_s8N"$[!)'ifH Z.DAaiX7e_Ub`\l2a!Jnk0'!Tl]1OpfsO]jdcX?PbXMN4#_DE=,V<]kWX\ba6#V:GRH,*>BYKS!0ome=EtQ^Q^#[kW]&%e5bkeSY:p&'=J+EW=iRQl%3# Ar36ir:$M0tNsm3O;i0LSj,@JcK@KQ5F$#?0;p N817&,m^s7aMrdbsCph_d\pEqLjrJ$\73G`Z_janham:U)L\f1O;^-= rS0pMF57Y-fXA$,-rp01<PLIpiQ;h``1rlTF.)t#Cf8*:Nb<#kTYfM..W&r<`pa>>)B?%3H`VmpcV^>TXRi9]mbnb5Z7mR=H_CbK[:aAbaNpJ2n\M40n>nOe' XG/Wk!-'+MU"d-:?kQYh0it<#n):+ Q+km?m1kCs,^Ui2\WlA*#ODMPfKHEG]("XQR)?Ohc4YPr?t?_>aP>TFgo)c>`Q;jokC1t=Qq%#&=\6kp/sA8+"MrD>apNL%`Y@; ZLsPb4_"FkgoQ8*kNfU(l[8$= "er0G1Fd'B:AZfAlo$@$O\Gmnjm$P$=f.Y5Cep(jc1\:5@?9pnn9MmqSoN&WQ.L!5FsR 3Wa#E!7_fD+mq?OK%#=JUaH0)BE&;]Bs780&ptA YMLt_ptb\8f)/AM of6QC?#hmUEem4MR"IE]0:CT]s5o[OZ$soO!:7I+!LAeCGH&?00pMA/Et)ip8&[%@Pa&^?a'F,*DEe:=i9)UlD] OH@+55;U_%VAPCQkVGk5;7' +4^W.=OP2SEB@?(.Bk)ii:+&^LB9cKgj8Btg8b@=B5K5idP;n%C;N)*:^'H_9aHLmU":r&d Ff_OWB5/g;M4L@X:D/2JNE0dAj"Ceg-WQ]*7I:D?BW+#?_FoSUs*9hCUWe`lK9P^fP KGGI%)"sNAQG-Xr:opbQ7IO3^#GY\Xs@+:0qKBI2+isSbG+W7O8dm%7hbllcY sA(d]Q:io--%h*4Ge$cAgr`6bh0Z8siL`>Kb=BO_*&ld;k%B+5d@AlW_DBI" <':R#Qci-7Mis#?=D#9S5^jn]EHXgp*H_HALM4!&L)N.IKDrXkQbNTYV)LaJot?O6htE%^OE+mIrGUKKGXL:R7Ji:g\UT(*dMpVf\:a0co7H2"6qUnb0o=.B3rI:@pKXMA+_UHaMp^>*>Rmt9m]La!GGAP%0,"%MEF\JXr<%n^OH!c_BdM?NOq[DKqdBL_WC'$D`\qa["]D'c_[AB9Q\AO]c4ad7P-_U"paLAQ#L"_"\-U5b4HnsjOsV8ARl4fi&q=q.(JO:iVZ!8sle$0D&_Y'dG/oO>\R>t4-?kUmH2- =N(;="ShBU9hGEVK P'b/T4-9:`'`cT2'_jTU(,)`p"=@)8"qg4C2hh"A*'3nJJ0]V*89-4t[SPOrkbN?KEJ&#4k3pUV=irI&8gAt]`4iM`r>A`3LiIA'E`'V<^!3mRn$sA*Ci.ahto%Nd8rn*gast/>8)GANspk69PoA5G&>;:9!,SO"0OMa8r`Vbl9B+M>!>1!f"+:9-ctYqdg1fW0d(_#/te4N/b%*DZ%b1OU9sr)G9Z9eGT*aMKiTGY65&8*N35siCZ=:W1GRK7HmAXCUF*_`S4g 6Y43V>rf:rAEV<0[/,UZ\q5?E20A_OZ25!9T!@5 lm4S"[NjK lC:[(P?V/if]#;Ie^k7gdO$mTDH.m4[5>YIi$hgA#*!]k\rO1U5"J`$N1''Y(Kjdj>Za8.12gsSMk)XY99k8_f1GYUFfn!--Z'0I$hLUKQA_t@W@Un%C;NrqX;@%M"DZ(ZV3UB'B<#Y@,$.OZaKAsmQb]^Qep+OCC:Tj-.W?P`Naoo\W&9T2IL$BH\*W_%Oo:G=Jlr:fiW+S^PhWmSog;i&lO0A09jhl69Fb_,Ghn5TP^4Uh$i"%;Fa)P;>TPj;W#r\%=:H\q`*A)/EZ=eZ Y?'E75_`*pL6)H6#ed&3\r:Ug1t*E eT-_$IOsA8!#$b5m$(O$bO$(6kWG@\Y5jl4R-98lt\Y\[tA)IJ a`ALi%)Q*%j,!tWYi3[oSc+HO6oZ>;a>BH&[@=kh(g)?1%s36gf2;7DcC\9)n/([6BQIOB8UFV;K2Ad%8E+6MgNeCff4G3?cFN?-_joN,$<=X+m%YsA;OU8%?/.Ub$fFtQ:(AN9m70K2XEL%[XA-L0Q)>4(OIWAp]qO[cqL>N9&X&qk]]&)?r&UGZPQfj4["I,1Z#QPq\p%_J 2b'nn@p[<1M9K@Tc!<3D,ESNOYoK<+gV\<(ADKc#Z+:MJs8hj_=ae/2m5S5.9<#$hbTNo"^G6=]e&2J3F]$=hS;\Q"]Akt4hj+MlcfdCWL64MR@-^oj"HY=,FeRtbD\[S0P:fo 0R3O t"*#k#&aq.5bbOf8Lfq\f^=[6AN)&oXctr\mNAJ.dt\F7a>GV pnj2+.Br\&:0:_S+Xr7IQ`bU?Vf[:asH.!W6`<_(?BUIGe014HDKZnIDsY/K6`hq1jA["gY^DH02R7#cXmWYh!s^_ A?@E44Z.cEr*b;cgY4.FRT%28's"b/@6,7-c1.kHnb2$ZjHd'F#E-ir?g/Zf\_#AdeSl#0YD4C##4Gj>$D#dbF9;n/Q)a&cNlM;]&=Yk6k(DQk(=4@'RNh+=*e+kj1AcpC%N8=r2;G+<So 63NJON+Q*aX-+)PL!0%k(:j@.5n(/)2o][O]45X8-Ai_NQISKY$(&r!3:5MM6e"8tED@6FADKQP+JB!oFsAZ@D"39`glmmmR:UW@'8"[QH/g4tr'Uep[+Hg$l*,8,ZLn)s#I(3WPLa.1j(3\_DKW!\BIj#+1N[GAk'KZl0f#(cc=)?9Xc^FG*h[516XRZ3-bpie-0>$=9,4J$0XL!6D0)'Ob"dgmP[20BtQp>aB7D+-B\%4P%\_9Uc:bimEB4od&b!@7k@V\UXltEis6.R,&'; U(]P>&XCp-;XQ\-cU5]9&n)qKZpfC0jEA^++9MA@%LEqS/7Es`Jco=Kf@,Xi.4_p-j+=5eqP\C#qp'rKebkWK6ij!b?V=4-dr#dgXF`9qYWA.nsn)Cf1/0Ag;VC<m6E*i )_)+X:Er\=dg$;L8m +WECs%3=O[+hH'h"Q>>e>E%m27a1"Q.#ng['MR+o;03mp_%#9QlAGKak/A/"Cf+5,Ic)+!*IA,h&jG9(A8"[YMVMCO6m)? V/hN]_c1BkFTF3Sso7pGQ19;m>iCqXEr8:Z@6!eiepA.8K^h2_?Q5@r_8H.5)*d_gH;41/__#gnT8%KE+dqqV cpKtJIF C9^Maq*,]P=Ct/Z-c&E^;M%rlA1"t8Ji42gR\c*EoR)J9.6?e3]_^G+K$:)[6!Rn>9\;O7(`8)jBj[+4>AH*Ei@fUD^A;gbla\d7MaQtH#Q"`qF:"04oiKV=^Q?PEI%9eq$7"-2pMH3<\X5L5LfhiojbbZWd?#7m4VESC&=K=5,6Zje@e(58Tl?mmh;Y)T%EPk1r/`H4j%.\p0s%X!Lp2m:L$7KO:B4F/qi0[Wp!O_lO$^*k-lY@QfIDV)sWY*5aD.&ctt)=l-s-l4KTHGR]FM?g?P3s"o2[lh[/Y_!K3gIUTiKfQ5^!pX`md#$hL*/S3=hVT/B(P^%8&l7l"'hprAqWCl]c[O=.2#8oJc#A4]F:%\_0K,>1MUd4=;I9k2/Dg.Fo3AJ\q"JZs%XdL7UXGPNmSO![L7acm_XG3cLP886lr]p0N]dI99IKZDEHU9:oMAj&Q/NH+3,28S`g<>RDo\CtZsGaF.m&d,H>*aA`l/.q6d3T3[r(Zi_EoVf?q"UfN\;S7n,Fm4es"OkbE3X71]T tMn(/iQEP>EBM'M@8pa2f`>@VODBO&66T>.3F;^2P?7B%!V%R3#1n$>a,PC5.s'me%T$igaenhZ/';-o&YA+7g]'?9R0 HP)q`g&.N"$%3a0d^B01.p*oAV*A#_9D2iY.Y:n#kT7N?XMp%6(HC@??ABt^H$%ABY(nZ!<"'Y#!$qC9>mr9/3fdl,8rl[ rD_fBHJ8?oKsd\3hbU7*dB7g:RHIg5lO(/Q?m1&Pjh#B_^i?ZC!3+W6O/PE$ZKKbnVHed4A9aePnRZ4_X02CShsUb`4W7CK4iB0,!2iE2(1 gHgQ(JAAn25(1T/g8d*I+*lY5YG?:.0j[5iUAjmA5>\U"&Y%>A47N8,M\)4B(iobO%XGHK^Sp$:o,BtCTsOp?%cnFK4Z'D-f'4&g;5r>GB1)HApnC?DOCYj*eF]N]1Grg[3+LTKZEj*3S,d]MUsrX+U>EEDJ"%K8lPT\hWM\VDa# 2m&VY&SMB)L2Ot0>2P)Mt-j,UYn"ei>WE%g30n*I@@Y@L.P/'&t">8Cp1',b4*h0pXQ-TQ[_!m>P&>H,Z8V;-[OMTS.:O\+0ipF%P3m]#k?%IJADme'c<9Li(0rHN76C&pg1kA7!G-,.+83dAE*MN1e57FCNkkN0Y"J69C\k_88)+NC`Al_o[G?XQ1VAiMS!0.]*39J&P^+:D"4VUN)A\Fg-0TpC6j))C2\>;/gP%;C_%NTk^Q^2EJ7Pod8Ia/758r)aF!V'i%Kb)MGGg-Zd#.HHc6^h/^2nE #WQDEKkJmP/7AE'pT?RMRN(>?jId//^M8\D5A-rDDNqn9m=Ok^%CSZ1V^6SZ<9=Wa?B_Q9>lJ#isoZ5-aS-BOdILmhWf*cih9fqn4n)/9V-le Uo-'=@Y%>p1qcQPPM63TP^nQ iZpQM;6kfIl&o[6_MWA$I3*V&nS.tt',OLKtnrCS7Lf.'p Gb1W3RJ[V]7^e8UV_T)_d\/d f+`a6t&dTjV,AC*c1E\[f(FM?B4[3IAWIH]=K;n&rK5_Ts7.T->+;2QEL^^Of`[mY3\Gmo)kRD?`hFU:XkOL."K:a)<-qK+e3^`32^7^Ah>-V.?]07A&m['DG7SslHD97<>@rPA^$fE;st ;UK1]8)<,qSAOS(jtr!sh&0MC0Bp8:dMq)7d<G;mJ&to"t"g;%)M'2dPe!)*2^mE-^AZK#Q&d!.R(LJW.^Q43d9e[O(^-G$oJAJL2%^4p>7tAO< &$=)]3r"#,XiA8T49/[C5?md_+Z9do<;Lb8s&4U5_PaJtN.,jVn^P$)<'q8QE.8V=r90QcNm@q%\kAIN!E^kCF*B0+'qMf'2>Ah(/^IkHc]fa"`JAS^$$fRX&o813E;hm'U-CS?LR54dTU82 %'^_MsNOMghCH'tQci%$WPfA,Tjkob\\,5=qAQ#&*#,h`.jDlqi&qXS#e%94D_Tfl&^R=:0he\FO!!ZLX!=d&,8oK64Ab*rT=9IQ.lHJ-gPb\-K'njG7W$`moQnl'UsIlA7Y>h3[$.50@m\UFFAbKPekPsUg2?A0*@-cRT=mP7TDER0\1gj+WAQ`i\Ts3Z*c1?;jqQ"CQ?^L4=;./Wdf[`cEsFdr6=0QD a18&gs"AW7"nh$AH08?M:NkAGRYL=q_6".6[2Q14nKtMpP'C2I^8/OR!JfrU+'#q[*O3M4L986/%E< Ao8'5X8 O[&@L._>$ZYe1PPY9-7C2# =YUqm+;/5p2_Ann]N-lL*l:tX6AjBiDc`e%!g4;SNaV)>99N!?(KPQ0Q:,]qL>;,.`EUo<&a$=PpGhXOm)t _&;8#HfSRMR? />clW,HkdXYVdjr`:9k=<[WZ7EJ^2l$\=`lM%+_bAnd[?9>jn_n8RL6kpI=kCj6Qg_!6$;,27AAe#bV>$3gXJXD`>G&VB$#H9A lhGF-[4.2?-+;VV02.1c%2Ki3;W[I2>qa0J4WM`K$;[X73`flB,t;e6GRh)NXkqRt*Z>f$fN%_o&6T@0QjL+8R1O)m?!>YI^K3tWc95Y\;5S*9?Qj>]h._Zs^EQTJk;A?YA^Q,c81pA2Kb C<*dEQ@PRtlj\A,l>W>GBA^=D/<9jZLV8pB^Qe8S#BiklO0EQdM]Y8Pq1^M1;rmMHLUP\$ Xbodoa%^'9XkE;MmRtT;!W/e/;`^&')H.sXQBQ*d%EKgop`o!(mi.EsCk0+lONOnlM+8?W't^k)L\==d=l[P5GYAqgPS7TX^C2B:p8\6B9sZQh?j7jrTk[q@!$o/G&n@5E>^7&%A=-h_Fpm&`\/)3?GSTBWjA/6W9p3bf5Pm)Wj 2M>5K('Y.V"rYkNNDVr?!G;qES[Q7)&_te dYVBJL^LUrQl"25['"`GQ[[k2>I02O^@0sOtNq#Y1:T__V('?=WI_0&TOOBe8f\Qn42^n)?8-YH7DEUq;lLLZoUh@ih'Og:-A"WAK6S8,'/[5/B TlH,%,dO@; A61b85dp[a*F-70:9d`pih`]V:_XcH\P)t k67:f)85Yh6C,pXq>#aC61*5r(agq4K=(,2btc 3CVe:>tKp&mp_;<8KCoG-I1-MgYfDArQRN@1`ds50@g_b:M\!?(4U7AHQ3'LU\=l?CG$-,VU\ii_oUnOGSY;f%[mFB]G+e&q/P*V]h!abF`R?;DLen/K;&#e/@V>qZ=cK0ja4KAZ&WlmdCDeV)BA[Z?=4SmqV&lC\%g/6kR!!H)'k<(Sl33W')p_5ko_,=q&nS7J7F.U[Phh+4f I$C'6FNtAn[@-&p"Lp(!q(r1FJYc$Zg!9FE.e0JnY"blEYo;r:'Asf(P63)8]7@!o &"?dVC\$n8@^N4GVL K6!:'E(GH E8#okq*n7>,kD%arjH:jgt@p_&6+pTO7;*=01q] Zd@D\\DN@/G3-<[Zp]#">q40K#E@LH/I(3ZQb!NA4cO0B'@+D#@@9naEr1EGW>/4bBj.`lablik#;?\Rc+":=$?MoF5Acg(TDi^ s#)R'lTA>89e.bmM;jKbJk5A(RRJN*i(`d&)5]$VcQos1/#2phBoXB_&VID` _+$V.@8AA`k@Ank9)V36/O.3Q1ikgAl$TZQl5X 83(?dTPs?F!Mo;9L?AX`Jbm[s*2bb`G45<-NM$Uc/ 'rV0!gHW7Bdb`2."U?5`[Zp%Y29@F[Qn_s&nnqKI3o@UH9:hVoH?/+eF(jk')AGn%F1dp/PA 1pstn8fRi:^AL^9sF-!")holtVOrB3f2p6^LEcG?!gmdh9tP\`YU0qc>_!$""8^)Ebf!dH#D74(H6K"e%+hNJIfqCh/3BYAPQ\Wj`-AI28K:3Y2S[]Y4B#3_N)X8C I.h!P)f84RgSPCq5B3^J@Y^E.WnAC\sFJ;!E!/bEhsFFSb^JsGAA7E;&%P]c+P:1N3`X5?:A,]%L1IPV]H@Lclptin_V&%3YCo_#q`k,*ZRgL PJ[UWm;C8gkl?c-N(qRHO/pSq>ZOjA8&'bm5e?Eh]9j-slrO.(WA0>"?pMKO`$3MdSGlj_kr4#0<#Mjd_bff'0]O?'gC-dAFK2YKrA%MUDn /=g>K%$mIpkWb-oTWY33@42n(*PNQ:rcKA./AOFI)o '-12j,gQj_&fAH42)VeIR#"]>^B::]DQgZDLTG_9s#`\4\s[BH6gM(k: +2n2QFZ1!clKpAjG7hLn.F$XE^L_SVO*bU+t ?[QX:-cgYH]Fk_?:/sKq22<6L!0hnU-m`la2"Se[s3TOG\U1i`>8]*,j+A^l 33gKkB,l)a );aoOlC<#nf?hf)6g[58_'A(N`> t2f2/X]ZAS6JhqllB!h2"Qe483 !ne;)2$:jbp0G0gC\t3/&b2nRoa;`lW@p']OIIBK&Y)'l@$I2kDEMD:*@:M* )tCf ^:JUa+9,r+FG<;;R*klWW=7O?J2"(4>UUJ:=ismVp!o!.Z6_4aM7\op$0YAK\34V-LR*2ISSKr*+Z/j^L4c!'>%mW%QU"PVbHEcE^=A@B:#L3g)N'e9*m]B8T%m#p[hCQO"k`8,B^j4&Z&qHa-EVlGbn,^J&hG9'9AI=Y3P$tE_4AW4Y^T.p@<9d;9*658d$aS'5f3lXJ'3!_U3M`8JBC-G(FeeG[Od%he_"%Zo(,qo(c33 .m;:psTHUiPU;^lGUshP%5%,l?(]Mff;n=[1Wgb^Jf6Q,jIGqAGSTVHpWL5bLj'.sf.-UBjlJKfqd_d4rKEL,i2\/Xciq_f>44PRpROh<#^&H[$(RYW*^,/Ol I;l^9&fj'DtNl[(CdED]'QdET6dAei#G=#f,sqR@AQT-&1Pc)]Q_O&6#i7$iP@>lFZ4],&-MfTCg"*'`Rq\Hh5i ,L#+6$:V6SW[Tsi^5iG-t3Bf^FahQCOd=q*[R45bc=?GfJMY[cR"R"j9,I=EK;bh:l/^S2b=[8+JK;tZp0p+V%:D/Ck,gN'E,_%DkBeg)a$nf!!-2=! >d7j=:l\pIc!A'I$p/]c"nP/),.nt@/,7;+KVsRO-acIj`g;m[^#BkIZq_?TA990PGc\.ACkK/orpm:'/jT9[jn=L8C^-f>DhN?YX:AF&q`t/)=g?2[Y%A-2+0:Z`Qo`fH81%/d[s9oqo\P)=Fh`Wr:ANZ$1\@RYHcJ<:'He lQsoo]rJONQJ"3(f\YqO@HF!(=U*]\1Y9a''A;,IIPeHPFJ%2=*1FsmnZ[ANmVXNPRgJ]B3=g)37Grhd_#mF15;O&8<#?(W96;ImlG6EaI pY8AASA02NtR^I!7^f9k#.=R=cV`-,_&QqIFaI%oTn7an-!pO;)N >JTTeO.)6'C"AoK9RnLJ@+hHRj=[Nb!(JY4*rrE'R0)qSWPb?C;Rl(F9l?7:XL[/DNS#+QI^B1Z7b);nIVsoOl9CAh-d-- \\PIN!S*>-JL/&-RGcC1/ aU([@nG*4AN<(.7Di6cLgX4qq\D?M6.@Fmod%de_DD)&'9-_m&?nrGVEFnk.M)UW$i%kPAKUZ%!^+,2@b'Fk?4skJGKNdUgZdokFE" -7']_m. YO>beJ?g[Y#A5ARiT(U.KVe4;:QBgOM2^OZ(GK# li9G+rD>P*5o,H/O1I&+jtt\Hl:Ogn4p@@`-"Q/jcmS_at&C8lp-c`DMh!4JXYN$XKYP(Z#%gHI EV$qpVP_Q/Q:#5j\=bi]bbPUH6]sV::AK)HT^O)P P"+AR+S1OTDd$[Dl^!]if4?&HP ITD;-/KhdmBaANA#$Ll4<&rOIA#[H583h$0C##K"tCp'n^_>s4=lrM\5SED,/AF^Gn#Q,P38AD+([Ka);gF43.fV#2iYG]9m,Rn$t[;<4kC:7DAf,R*bZQE P;5MqT$M?_HfD9@];\?U5qsqL8-88l6d_8Y+ntTHYEc21Cdaa@Ak=]3$2?CN8Y)qY;H?XY p+*;IUdr]/5^P0r\_335Ek6K7Ftb$?Zbht\C9[<4)^5]HpA$T]DKTes\6aiW9S+^+LnGOqBN,Wg=L7pC:;h@o5WU`lZ^s]aNsHJ2$n-?LF5.a.]4,r45grfiGJM:>[c?PqFrm:C6*gC4[MB244"jJ=>KV*h@IAR:sA!poW,4m r.VEq5lgo](gE3$>d\r<_.U[WQ4[OmeY2jZYaF!2TDolY'\K;S_!L><t312rDS>Y9@p:D2kGjCdA\IA_I##qQ:Vmf:dS?O?=][Lh?OQ50S*nTHOoq%co`Eg$&7<=0f^J\24O@[Wl%p8P,E&oQ+S9Z^m7k.`Hpr ]cCLnZkS+V:&NHM(drJmnra+7SHMDS FVt=aB$XD% HqbAg]"BgL*!lGngo-!DW qI)=A[(jM:YV+jsZ!/Pd>d,6&'^$cDn(U)lDLN\V(@Js+kDN0DcRR\%(@:o32!p#PP6dDP!],@[>N7A VY[eOWZ*@^lWXZm)*+P[B]1+%oY1h[hma#L@#_LJT5>e[Y[&)RH7D^()tHOMCQ-p-k>f-XppYP7a2E>9,b4$Y3N1CFWr'He.?;DDHNqAO83oNqlFR@A[?HJM>4r(QJKfM;Ma-++]'D<^G.E+A;Y5]eVl>'t?S9%-)`3LDd-g''5nUQa^`#a'HA;d;:Nnl1p+SJ"(c !$27gl@pHI(gSSa0*9&ggk6BJj^o\!oV(h>oSbg%/BHeO-mQc#q/G?cGdN(T/1&>JML>@Fl0=I4)'?9pA&\anPs=2+Eo9c7=i\psA?5!5%Zg5,-9n^jsb/cU,N^3LL(hi #9lYqB,ma6+F]j+jtnHme!nd!'i-- >eBc/8nsP,PmfHT2ROo'dMQJp%6j]RdBfS:^IEY'b,*PqV!Dg"4($Y:^Pc"Ta!(k5SR[YS#Fr6JpGWALb:JGc__UGiAeXIoYAE`7( :YX?cH/Mt"c-WXD '@Wc:$s^Bod0RiiQqI4@ANe@aY]:+0XHq*c(p=sW*%tP'=K##Zo>CmpFq8H S3^L4`<0^mFrnM&[[`p:+38A*s1/CT%GU'qQnsTs7B_2@Ab`NNa:a@9AatSl(BMNC<,914O<14R(V*W[VCsJfjVJ;4<<_f@`9bIV&LBHY]RN2T nIVn-7_Re;1OkUg+XUoY8NsK26]>c%eaq*C@'>K4JS9Q@^`Ik!aso]nLZ05%(dtNH3t<6Z/ZLP@Vm911nMb't,d,.\\4Iq9[(tUT\/:[jO7PQ1(p>%/ Z2q8][fT0^:dq]J8Dndps8(WdVSpi;o+loBSpA<(KW[_B)[S(B3fK\&0eG8_^mOX:@_MiD%%YTeDg"M0+#e"nZ&o^VLJG'nrU+1K.^c(OZj8c^IH;%5?A';=sO%fYJ#mkknh`O\.`&nO]g"-^1%d7!;EBsje\tgXg@ 1LbF7(B)H<K?`$r=#j"F(0rM6ga`%#Q`P>ndn)UAU-SpX?.IVRBm)hC5^3XSJQMYo+L9f%QkYrg;:JBrkrB@op(;oXJj03j1[:'@VIN*5)*#&O#T\nA/-UGM-)_AVo/m4N,U0lg>cTBs"X*AKp1L7qfZ3(Q/7N2B5kb1!B_.*3^1cq#]Z'^r>JcR(Toc]XZ6l+6@&A_PFjDGs!Xs+V& $=kNhG!de10LY(<3B$L6Ng%,O+1KMe7j]qCD##blsi:D6^hT0L2E/XC1##jJ53>:[m*!<@8smWH`ohme=Ej QOc4*4[ S'?Jq000Hj)nS&C-hjpM%OdL"L93iNbhBl]69Oem:CEF4@QoJJaca\+sg'#F:=fgU\e7Uo$11jKI!)&1H,'8EWA+-*eRP2j,-oBCf98A@$6+pnajZo7oaPX:`NCbtfL-<ZDiG`$i@78m\E#8sRD0rLr2aN?)>/G6bo=(o&[V6e<7B=! 5@JO_J`Q.>DT'hVtM8V-OeUSi?MF&]--F*c,kS@&;4e:S_\VRka?EWj+;*aOEtCpgL$r`@fA:i#O\@p`htpaOk@h-4,DULE>%!-0k`DDB,,'^(GhA'^8"$8-kZN5/32%YDANP=eUi\$pB62fL",W%.lSaQTa3.?1"Ye54\9RtZB+l_e%>RT5bE;RcbmS+e%0 &&eg/UnRGIHB"]6 ZiA(hHW18NSP40lcp.BkhpC\44KA3 G][Jk(YFR]t-c9\17nV;XI?4l_>IsZR3Ko9-WNm7*fV=5i#8FE9f; sq7tdJ9(W-WBbl+s0-F#h>H8K/Z_[B\Y>%5i&VUIT&T<62^%cH6D&r%U]9>0M^OC1\P gd.4?^H/mp[A^TmW<0L4W>1EfDOG:M6r#/+TTi*of>6k5BTlGm[)UIJ"=8]s@s=G9;^!=7?4'KI$"9'R%l`lpGhUBJ]8ncn>D[?'`"fCLit50"Yd^Xt^Q!Xs!>8=j]fn#=Ff9F^b`Q7p*$!)Yk\=hps2(4"sVC"o]k51ro)`1_6[,@<1DnsYa ncRro!mM!?$n5/,?'rnO@gUMmaW:Bj%MbI/2NVWgJ)-W^_#93Fc35fm"M*&H;"HY;A85+eKZQ&o#'%^QUID!nsAm2+IRWJ78+-Unb/<=bpZrO";8mC5$j5q=qcmg)WJH`$D?>l+0k<.+-YmXZ(,T6"6h1QA,8>D1p'!(N=!:3&gO:C$9o\>95oW'Q*FC-iK>`IW0:[. 4?FYIM[@%EO;legl" 1F?,GoqD[B5*3NhfAj[a5oOk#dWAq4!qhpi=67X&-N+J9 ia@d.VYOe.M`K@,"""fE2sa]I=-1o$ U88DcaJX,X(FTXOb87#\W1@='4"3#.BsP Qm@s>$I5+cn@>DAn_RB.Q!>[q:p-c_Ebt-Y4leG0)8nOQJ7"5Fb7N(*+)9WtJ1a[=j4A@CJ!T_r/[-!gL[JrT,t@k^iPAX=roY%)G=W:mjl4-rZ7bK+(B[R>6LmlF]]nb6m;".rfrZAHWoZ_bO)b6#?lNc^ 9.[UV+M1Kgap<)9>],RN9(3MF[Z.Ro5a ^bfm,09"iFK 9S37-<=A-2n1Dmrq4rAYbF;LJ++UXR_E[jk`tdmUEaEB\TR`^ZZ5+A0i_?gHjfS^c!t&pHFc73YsNVI[)_Ut-6'e9U%2N&&r>\HX`'GPo716A8R3C#rN[<2,V_lZ[?QkL4>R>f%EB5_*Y\2Yn2q6K@"7pIlen0cG=dC$hen\dj.ho-0'Ik. c:8(+lT$Agg/`LIt/<2PH3>$oW!Y+DAo1T-"YJf"_`nWT_)-F0-0#TV"\*,/Ai5VT@iTnbAI0ornM+k;QZ7hkX*m=LeIHtLUPD!i=f4E0$h3^C/s+".a0/jgoGb0d/?:ID0jt)T%EL4PLgpqkWU&;d2"]Op#Or@7c#p1r3K&KKUs!3^q:W-B3eAfc[A_=nR3lN\hG5![te4+Ealfg517GpXQ*cZs]US@No>\OtkFUXqs`e-7#3TYYX;;p= G`kGU6JJQjAChM9^P+S>qb%ZVL*a5LrMqGjB.h lTo@_H8AlHXl1s_LHZTj6TDPX#KjrO1Ph,rBN* 3 m]dQ(#QU#5s3shF,*rZAW$6Sr9T;4WAQhtZ%3+ r.$%pDG8 <VB>M7AEZ*m'k-3N@(KnjQJ3"A*EF/h/qst?U:Jfjd!)MmP1!#PGL9:J'$sE M.Hf]]Frld-%*HUVWsUrD%?K"F/gXPe!LjmKNSM1tJC$NK*o5Le#ors`6iLUg1=2MaD02aaZH[geljDkU'qc(tg&nL'102,0V>W?pZ-CB!:$H\(:dsB@b=$R+"Z_*ZFTDkp"TAD9bs.88&8?BG0oA`/6_9:Xfeo3J+[BYcc&Dk!DAhQn/HO&mEGsZ1A1\%+HmZ8AO6`J T!3:Ggj/R4V"?gW2sXh.2G``LIHD`N5lC8-4X4-9nBoZfAH!;Fg(mq!EO!#i%Gc(1ZE05MaV>"b"OT%F[U?YB.to1!4S!WG#g>I-YU"s9\s*H!RTr]jS0Z)4[9ig)'"brRKb[pb7 7M[k8.B]i.*)oHiFnK/Cb.qr*OkY@jc5>^K8g;gaf;Eb %"#?EZM"6[H,7a+s(XFiP)>dd%(lLHTUK#4pZ]&sJOa,&MRZ!$2oGO&=7Rj7R8\pA/p)0a?d6htHH19G)ej6sGfjWsS2@*1^c"$'0LEI5*!X8CdC%j-99XcPs8X+s7H#H06$*4h\^KfW.U$r#Tb+EG@Vf6sphpDc:A5]9hkD7`ijZd5^00%_N0B$5,RMN7M>Aa;*Y5.F;rFnK;E'):kMST!r\G=^DjsGF>!^\4L8>VY4$VJ\WUpegjJb5ArjLWkJ8@W'a#p(VW%7S*YSI;IH@A\O9)Y(`5jb]F )5S?,I,F$./qc@SFmHfnFf!$bW+erR:4Y99,OB;caB.E:G/B>AnN)jF^75Y)Mh'<<\1PSGUta0&WVn>&c]ShG#qb+)fNmE(tX/13]n!'l:EM7@M9VX_AT$\[IsHA#NQ+0:gZq'@W"\XP,<*tJKl#E$*0O[M1$ii3;CA.>bT8(1pp4+Z&mlV5lspqsJ)?P0eXGmV%CqZ:P9`KJc9TQJDqa_AqVgGKJQW`\<%>&@"2W+Gg:akVgpl1><:,N[K(d3H[;d$L8)!9tn7 >P,YPND1Ij%bJ""!hm!>VK"AoY8[)gG\@ F1^G[m6=5Y]r$knf'G)e20=.Kd;\c*^*;"Ds*O$K/kVOp%PE33M8C8-3]Fs=HH L](7Xi;BBRDW<`p<&^(IXmlpmT#oQtY>:T[?W`Ze^_' %2.93Mt. $`@c`k=h/nPPf\Gl655MMb//13lmfahEaDQ(+47_f6g)I?ok6C3DmAbbj@Erg&S7[eK\[C2-oTtY<`7AU+?tAllfsA9AL^+5!EU?bD ftpGZD(COq/dchiOg;]F7b2-Y1_mcq"-d^ 4d75YdVN9U%AZV:99,YIPrG'a2-Atnt!<_^nER.*g\cp, QW=?8AnA(A+eLrOJ9Ea4UeLi6NAWJJD[Ai$+E?>R*o(WHjq1?"+n?`",]k3kX;'^SeI)]2."\9>EqQo2K?^iG)TmRKp?=Q\DZ"__Pf^MW#&+Zpj=/B11Wa'Pk[-.:pr_1.L9YfmM2NT/X(6-NEnK'Fl>t\__fN- ;baPoO<4E8tNq8UpS.(W8t[_B]oSl/A:& %(Fbi7t55lf3LigGUo$s.I-_=4,^I;^)$d&92Y$_5McBg`]bD0npl#ILcRXjMdP<&@H8HQ:%W'!p-b@PjasM$c!tKpg`J-dJ-1sjS5+cAVplC@Cf^F(k%PSj4/Y6h+!:2pXa#55p?s0)oMCTgq+mZdX*%,g:L)MPG`qi(PmY8V=9:DOa]`H\MeX2BUd%GYRWha;j8kkdDkb!o6%.c!^o=L,U/Pnd[Bm35ED] @N&;,!'_laMA8k44iGQlM?S'F1\a[qAlX:$4@Q/^jMojWh1jTBTF@$SDRlP,%"W7X.-RSkeK*KV;:tDILZ5tQUB!%\P.HA5D>m!q,qVD@r1+lOFE<>n*7D0.F`HHhn0q d_0nFK,1*b^^40GoR@1lSKZV&N3FQ(BDcl^B>3!PHCY *E1bHs*Sr[j=BXR-k/6V0#6_R>VYs:VoaBVCNA5,&r#;c#F@A1$tH/V@4HTFTHA>%IJHFV_=g2_Ue;-b?)pM&0BA`(`h,f.XL8U2CB9Pt#]HNdPKsQ"CXQ6MhQ )poA[s&c F"RZq;i!=DE[Xl2MH"DYV`D8<*UcPWP&i dbA[((MNLT>hFpROb'7W9*&m,`%@"40b>aJMl! 1gD&sDRtAd3I2llc41."H37l5N;$hj,qI.M0KO/:Q3.f\hobc1^e?4CTh/HL]9[A)-c d8OZG J>eR#Y/EIhlP`22ce&C-S>c'f=_mS5m39X&(JL0B?>B`4;1`nR$DhTHFQ=*UdSa3:BA63T/D5-Uho >6iZAH.[.q$jVZslOnD)T,=(''GYSAA]t"M+)H>"k8; U4BWgsni\beh.YDfrY(,LqTUA:K.OlE^Q8f8%Fg_+eZFZfn`XqhQ]?%@,X>,nd.V<$]KLbA1k^[M'?,ZNBrEiS7s4to=(bAJ6;O7C/arKE$qk5>2KkO)ic&hPmV,@!Q"2Xi.rZ-i-tT:t^t,V9%rP8I^/nRIR-H^bKP Un)CRl&BYVMc>Qf?tN]8'`,-j"!["F%"/P5:QcTgZVlMXJ']t2A,Y?(lkdTZHnio,ta4J`QQ-Ro;)0[.=D*qSFa!KUsM n.A[VN3FqG:J7%THcciT20Z$-.Og+It']r7]meY3A$`*)UN;Ep9h3hEULe"i a:'^bR"q-J-1\V>CmA2liB.fQ\.>`oNB!l5Af<[7_;5Veg]JS3MUq.t2j19N[kMZIkodDDhXNNl@Lk['\(\#Is_V%M,li?I]V*EI@\sJQWRe6/QH:k>9[pf^+[C71lGU<@Vh>5Br&3Ss9&,9M?QXKL0Am&*VJAAs>pIUjNE"-/T'@gFoAt"*d;]qj gU-/lRArHsq]5q =UkR6(Rm'(++,o;3[Oo;WM6U;'$2X)/qY?JG+&1Y7;EGl"E%!rk,:]A@j8*]A!3'-rBrKlpBjX[&KS[\@0oKa%/@F aGFpV+Ak1$@"YBk/,e-Fh"S@JP]IX[@ZRCkVb9[_ks`jDFpC26A\>A"lg.q_q/?BVN(PrBgJ.(RGYArD'Sa.1 UAC]P=_1_Qs6%bm$UgJ)..gWeGilHJSqjhYAd+'8jYZ)[YelNG2%T5F#."W:S; m_Jm`#) E';U(]\\hosFM&ib[@OdZj,mdF-MHs"mI"0]JST6n=e>s^]>*A"P/a)#n+t9,V-aI3Djm(FQ70R4E:g@CJ##3IgOW!qe:hNGW.m`0._f":9&ZmoaYX`e@*eC9isRL^iesY#gjoFR0K?$!\Xl8_11k&;+!%V/QN/;G"g"7]4*BX(.F'#[ET0[b8sO>:A:daV2\OL8nIQ6PVqcVmTFb)qs%$D]-:Am>re,n6>MI,4DZ%;CPf%51m?BcB%"]=snZ9BU9[ X/d8-Vc=tqI&P*pCTrS8=VW2qQ[_o'*'AENb$ac$nTZ^6oMUl>_EH)S(8>Bn6K);0Wr(cfhGpI=8& on-C)Re4A%Z9&L*XsAAWH=5:tXD-)ApKHW;AM5X;dd`R)3<85dG>KD fF+`oDgsgL$knXJn!(`Vs o#5mg=J*@DKNeAgTgPEQp[(]me.4H=`:\HnM*j!eg*ZIb+EfU_op"/FWl.i&TI]gU<&aBmh5:/HG7ct`aFABOhS);p$q(M(%85[[$X(Ab>=%rAZ^?!>D#kmq[OA;W*^Z*R#O^Q@]HnV(7T.\@XpomAO!o2fP#nsdcZnIl=%eA*YoA>W?^J+Xt>ZMeAcHLs`D_1JkBtWt>F;06h5#4O[4+p.tC5K)L1D/(0:^d(lmalVL[Elc)cR06B^%J>^s3DhVi^Zo*?C+>T/"J4-6'J%#A(o/?N4*lc5mOfS3N,$F4AfNMj8f)l8p iYFiO@2e"7/nE,GCblomBE7AJ9!p3:AMPme &Y`o_Ork6`XNEMo_otZa2N3h4.+c$!+4dT5C1os+jGG@pom5=sbo+'2TtjigZKr5m/pMP3@/+#%HSt=)SfU\329H^*NA+,J\OAZId;&EP_j'j<#/@a,%r=L'1BPiH+.LgHOA%'%?W+lO"RgJ)e`o.[WPo@$2)GEF1BG5%lZC2N7JCB,L5h!3bIX@AMj5%W2LI%;Zf;fH1`PTIQD'-r@48"V;p$iP3KJ.U!*E!n76L64O(oW7?CV7<8:ZhPPZ\E)AL W@5e%8Oe2a9@BqA;>k%Xq&ocVJb,+UBig5<$7d6P&[ \-oMN(V$L9-Zh:Ad5:BX,MA;DXKIfk/^N*$=Jk.aH`0@J[!j$2=:"n`MBMQ9i7^=3*,1C>(CCb:d>D$E:=+H^Ap.th9KA]j*FQ%\FkMeNiq9+?D"mZS<[Qi(O'Ra"22/:)']K/@NJ)pTdka:"5kfC$/ljl"[[G6A,o(r_eKjHPWiJt0iJ@3FS!^'rcg2:]^t/(6BJ[trtWG+DP,b6;l?K:[]/RDo?>!a%e'*NOcmqj #^3N#A?N^M49AQ%-cZoMAm)a"F2EM3;Aa`_\:D+(c137HS3F-2T7VYJ)U6'Gf_i-NG89'R'hg+GX`j<r:K$VK6I,SdL/giQc$E\Hf[^C%C k!7"lZo8@^"*Y[\X\lI(pd>-B[5PPFK3rC2Zt\[q->#*e"$f,dN$[k5k&V6:C6KI8fNAD_SIW>@!k*o Bf@&m;H<jhQ+U;+gACds(8qTm2#CQ7J?.CWAVq?7Jce5H@(CQ$IX"7$mATFZC@i>r8C]IjVF_#Zc>q'5P*H6iARNP1B&)$oqWLG#en5kT,em!Q"c1J / hZP _b*6-pp-0CNBP#?^K?\&\a:`T1Y.k:hh:eangGB8K"HY?n 5Hg6^8:oo>=8tKoIPkWsZUg<L5jc/AZ,:A$]K%oM@"MBBY=\P6:;V`!to2CFRDeh6No1/R@n$7rI+2!]F!;VpFaY#)f%#4\<-r6CKbfohI+sMZ Gp/"8(4_WJ>SjN,NIY\nhf\S$rl<#WmAf%j8rFg,K4F3`]8$H=8N';0n+D$oGnVNKU.F-Y7r0Hd*&`K7A7E5X2;OMSf9,LO0Wl]h8U/FW_d ?Upf>?XjPaO.iN9:DQKA&M>t60_t)/;(,>^LK&eIknR/^DW#U/.m13+4a"V?>#ABV.>*^;#k9&^ZC2.sSo:2aH%=iaA;*TdSZ+?NK:O:LS.[&+_?>`W&7Y**P56Xsd-gE3rO_b=qHI"%^]X76o3 Q )2^(Y^@ZsHYJsq@A]&J4l+E]HO=T7p(`Vs#/bAsTCLE2^mdoZR(,.A8pshE(kWn=EtMh?_h2d/=-bUH^F<'q4.f%H;Ia-BYA_q0jfH3i=C+jmYk0+CYEhH&&^D+0 (X9_NUfNDd.*PIHHhL;pma#bRED'W#D2f!P1^k9,#<32j+ Yk&UMl,tgAG]Q79kf^s1IpK'1b9?P`:agbT!eLS@+IiIHI6asRAAf,`4WaiXtZ+A<BdQIq/%UH2CCiQN%BaDrAc5pa(OZmb5!fBsO>i8 Rdj/D8UgIo6=g7fc`*YoXU*L[>H*lBtQTA)=Z.OA'f-F8:jTsoDYLr?B<OC0djT0Fq4$qR$rFha3?4HTMIL+0EcXa3iL2;3YWgee]qGV^4J*:h",BA\>]/-ns9,F>^<"F(lH4KmOV8I_M_#ioPU#Wi;;2r*h)a#tr[">j-Abb!>13#]!WK53-A368__:9$hC9h7P?tnB.'O4D*9>7/(nU#\pAGQ9'/ N"H<_f.XbTYln786*;mFsQ.0hP9X'27a8047@Qd%E>a^s>L$:M!Ej07sZ[/IOOAiU,;[9FdG%Xpcnh,\:qc3:WS^JBH[S>AR;bM$OTP)2'QUo1.7i5Ucl?C#p6^btCI0) qAl#l&]p(00.8W\at&1CUAa)Dj ^^!IY?d#.K20Q\rAhXnj1b;Bm\")io*SSVTd_P*$+>' jQP*#]re`4@FL)M2!i;HYZ_k pN US1gq*%UBX1fpgiM'+7KGXF4o`-RYY9O.; "g>`g,Vg?NZ3kgA90(#Q1aqkD9.MG&4DFnhr/3Fb:T0`GfgoXL T'S$/X4_8nb1I>SY@9E)6?7M)iS>QfQC*;r&lRCG,Kleps"JCo&T003jGAU.(#"]WnmAG^rHh\h>6qcUC#ldB4DHa(T$^$*rO5[hlhLS@q@ZAOlaid]-O['(8o3=.8>?gA>jM=tPW'pX!aX#IgNAX,@)]!e;Pk^"\-:mbU*gdLFt-CmZ@3W_567]2V.I3ntMIYBen5YbQVaAX9] rc.Q#K&gC`Q%b`NaH1FAIe]A0%qlG3WhTE13oHrOs0(A,[X/q6G8VAT.%gk>+>;;Y#B1,1?s]sWa`'/gmT_+Dd+lVGCLskmrf;T]FXDjit@=b.`mC(LIiY mK&YFUAi$Ka(,,JTH!)9p^-NkGm1HlQG/"%r@@@c)>]7TDL*G$_1l]&=_('hJ2VpX&NE7$(etCjPf"nHDiN/%>KM\@e/;8C#LJHBX,XKl0$tKE4.:KL;DHF52IVY-aAmsZFX_&7=_Lr;VDip[UA2D36E[P=^GPJC(:N_[?qZjrI_)ttY9rF(F9 #h"(<@k%A8%"@ktM.$)>cSd.1KlK7WkQZr[TQ]MK+rZ35A5il]IMnqMJb-U92HRGsAXbF_&[hAV4]02&;Vr;l=Z(I4cG*0f/91;r/1d*QRY//(WV J_tY,EY+_9eaYE>@tGN=[ ;K0#E3OeCP1UfSMH14#P;(A&JCod>`_qB9H!kDG,\GPVr.>*OS?  Bg>,m@0r f7&GXIsjJ?]cK2?/^#)snGVDjB*hmgik?/SpPL<]$*,HkGbmPJa7Z,H<;l_"-//L$Df25%(g +G`X>HiIam< [A%dkdB1856D3P#dGQg1?_a[Q8bnRAmskmAkH=p;?WMKgsGB9HB"YDEZN/=Eb[]C&!+Vp@^lGRH1p$G_FG;O:AA*hGoe=4>6:C)ABX5!;/o2M+X? 1t&>8^FmUO\s.UmMO(>a@mR08HJA4)@dEP2mn`/'&+]k!e8L2Q32*'r,Ad;D?ACnc&*o9p@rEV^D7JG$SZLS1i2q51:sgrDtWXI?4Km1c,NHe&P2rUlhea.f"*o+ksBL<_F\pf+sD`n8](PWH$h/G4df`THCo7-6,&4d,C";%*UFQoWOMWrG#T_a+[dQH&[1,\#!Freo'D1">W)d[=bh6YD/@YURLi]GDU0EX1f!Nj(f'^Kea5K1+UO#f1"O!q,hA`]ior/]BZ(iQd#H_2jj.*kcAtq[Bk@hhCpB.Hb+Ud%@A]NBY,^Uh4^m)?2ORP,C$q#pNBkU6NBB#_YV"_,GeZU-'VSU.RRPn5r3'rm3^mXr*&%$"diWq&[RM$G7(+PjT/plUcS\Q*UA-YWn\4;e),MoMYMXV3Q/r$MoHnhrnpqn/)#InrT8:G\JRA>GRfk@t(FTpr!OcjJ_=K8(,`_FoU[-A<4@Ip3c'M36V+2EmLU/2sb?Ad9];d>t&_NEGhdbs_<#['6:N;tnY%Uk#-8;t;VmFEms(!&07?`?2"0VR"7Xg%/?A;k>A\,(1,Aj,srR9)%qJdji<+M*5M+pU9H"eW?3jrE`apa!;qV0UKIT6R?\TY,a3oWBl9k<pXr;.*r&[MmmQAA%$oLI` GEkfsTPN-%5r,"]B=Y[fd39P`"HnPA7lAGsHW@NP&oN!>34;P49"mtO/RK EP6mMmi9HYi%TG$AslA@=M]cN8A'M>#=-[bGdLh9cOXh1.N)?H_kHo4nH\6II>Lq5'VWI&56#\'%qn,L[EGALMb<q#4nB+NralWhAE\]fTQpVrbO'((nJG.^]=bS]'A3_YL^(HM%V-GZS@"B[UtH1\%)-eN9=R:Bn6S+se&9M9:gP81lj*h(8RWj`E\Lq"L2$W/rUCCI:Ylb'2XWA?c&=C8_5/P86_fhg05B<=NLpDcR ;rg' SE8'L%mUI-9Xa**8@6'WJ,TTYjO66V`8A#olMgs$2_b".Q23Ai"nNI"4ECibgbEnr$8OD 4]3b=#;A@G-.VYKM"PKmq0P7,-0eSZgl>=Op60pU6=;A%U'LW4 MI;KR#qa;"ILAqjM000Gkq9KkH+;(:*.!c8<1tjH$A=c@Y./ikk)r;ZV*fJ]<(JA$teH/'Eg"Pfo"+8`/TB-r(% l2K'E:_Wf;5t!rcUpA%Fr3#5(\+PV0Jl;;Z'+D''@FS%Sr^Pi'=sGE'&;ATs`;GiaSBTjPkdiEce?k/a6+16dKP.?n5h3SXOa,c@.48=gqN/!sRpJ5G$)J2Y#.8no8d^:fVo\Q30HaWP1+l/]"K.oG;H_4AE,rd]L'G5(:CgAqFsoC:2DtH94<,D\=!CiYV8d0(j9rt-CaR*$#'pL_kZm????VMfoN?tIlB=cJ>HOVH:$]P-1mHoXXZ"I00Wdq5j]E!)&#S9n=%VV67\@B*9?CjlV>AD:J8/o%PG9[lBV'3)!"]%Z-p, -B#[a9MkZNTQ(V>Oh1+L!q6?]jc()`?20W"6I8HA\%4'q9J1S]rAb`Pas.Ts%7lWog6XQ\ *S6dMc,-Rd^C?\@bIFq` 3jO+o,j-29Wp!mN%e3P8_La[A!*UbM+mhJri`a!$#8=\,J.(->;/%$%L<^MRThi"s%oPQ,=?'4\1;SF3b@/$HeC]P&,(^;Sg0V6ZJ/O%k_qF:H+!q<)b(]3>^VC(@e,FT1l6!j=Q\"rVSSZjR9N]_<\s*@15N#06gt:J%8%4EFbktD1BZWA`RK/l@K43K#1.W:;jQE)cN1Cp@A?@RM;<lHd)q!oq9[W O5UKpC`#88Aja0i.fn">`%>+]5[oDL;N(+Bitm"Vk^6VJB-[rJ#6#GMH*je^)pM).U9lZGQXE?h?jkXoZ .G:T'E<\3#0apXS(#()fj@^0A8l3S"e?r3E/A2]hbSU\Y%JY$<&Zd)"cHs`jNf_8)*K75EGXaG02T4GY42/?X>#HNEHP?]ntgZ'l=I2CTa"TJ#fELgaMTZ@X/0%?s3%c&#Xd"$Zgo[oG?)?TBSoC9^%"\5)4Ccs$l"k(skSq`+C;D9pCgi$PkmfV,sBPInTf[s) #"q=KbP\lE$Et\pfaepfX@<=qHrj1) E!A2W:oFRZUed;2ZF4V9NqmU$>/e$2h]rHJ2bl.1H61)5bZ@H4I/e?T.3cN=YA3<fpigZ"fJ$$!$n&tQ2N:fO'Gi(CHMe0L2H(Q8M"7Q\<#n?gHFi)# Vk+^pp:rfc`cAqarbFsQY+;Ms_0/m&d$l-.+SaG#GPR0\K/;H/E9S-9llAZ0Ge&3-[X>B3m[^;$r\NlKb=ZgkVl0P?OrNR(F^^NDQgV0\N_K$8h&.1?QAE/ada%f\"NL&VYpfk_Ah%k.g$VrU%15WYcA"bdAKY<KP:fs9a6db@*h/<&O5t` 2dUJD@Ai. [nKs:3.U9iKp4ANWJEMZN8n?CrqG_Cr/q+h#3L%\)HkT6)OP4o([CsG9@L;-0#f8JNGYFc %o]n@IjLJCg>af8B89D0`mmRsTD6QPP'2EUOdV02/23/07NX]dBAC^CHln(7b&DGV4GdSVE>5MT@:g'<(I%E@Eoih:L"D@)2[rg)3@Ctrb'2()Oe1/7MpO"2A!57c_[-A;*]N_"2&;A/k9=!Ha7BYAq+'1(N;t_DA32ml09.J4RXaI4#NK'=8>H2P8g]9g;_#E'H\7R?1'%l3RUl;WT[i>.YkaKU#1IH4?YI,,CLSHVBVr=S@Xk4TA?%K`q#\YjT$Bq:Sb#U;R;%WZANs+Wf/eWHj*.,ZRi>mh7j$[Sn7m8H_&gH+-!e(Z7TLDOqI;pbJYA,aF<Its&KI5Q?;_E@hONF:Pq(rr`smD9UoHEaqdoj7 qm3G(c+P7Qcm[o&:+LC7]p/GXXH80F33??MYp l_8q5s,)VkZeJ?#s)cq(/fAh"g\n`j$jm;afp.&SqD$&]X,EAK^8D[Ag>MX#t*/ASaW#+)o9gr:/]9>XE_es6dO3RUPQC>]HS%)#b_%[Z^g0rm^q5W>[Y424TcF,mi0<'JU3o_eGcqKE%)Vj8+1MM7HFt5.Z2YcZ?WW4W*m$U@(O1-"imf_%1kgAVHRJ(:GptA!1id\<;'3mV][Q,bqEk%8 L/[KbsDk\h`pirL5\pp/?to+NK=Q= .s[OHR. 3>*\Yt4=6G5&2U1Oqq+bm8dZEH.Qd_Gc)(Ze;&Zn?:jC(3^2-W6*m*5:GrPS(JE&#MDIL(Td&3nrl-ge87?mtq )"(3$r_JCWcj'VRmd-24+.j3I4&X5fMb[sntUDWci$*K 3U:[]/YZLn08 %hb6GRFRW2U(p56 /Nq-Z]3r81kDG#p+E'T-Hhq$"5G"e)irQd0J9"&QB`ZffD&5!e]$];IfWsQU?gLS+9U08.4XroA+;s?0-k2d2R8`.m/UlS])l7$J)j`1:I-tffj$DSX)t#U;KkO/P'0^o@Sj+MO^lF!tAs>m&%XS'RYdC4Z<1_FY'[H".-;[&NP^ ]2nHOm!^RO:V9GEm'8sifqpcZ>l6Z1OiJkCGse2B!IL7\YP'cJ_6!CEg.J)fCi <5.UfrRlDY'&""3e`O"?sD7e:YrWai>;a_Bn#fZF)#8h_G5$Bisde?Jomn^@o'1>5LO`NbpW6?NJ!S5'iVQqi1862S_)o7><'O+ p4$/d!dZR(.&iplrrV7Kr@Vi ^G8?P8sn)XZ4<T^qU .j6tQ@a'n(%*?Grc[>)1L`^F/K1Q?`'8lA;DLDDmp5VMbpi+7GOd2$:pD<6%AM(Mh0kg?jD?NBSFW,6L&[PXNo$YgY//Ac[2+A7X7R7ZP#1')sAEN]_A2[K:M9h9lVE#\=;+Do&cnCp?3"'S$0YsF!7Dt><V:!X%lT?orUNR)A4#N:Wr'FMKc7_fD(e1g_hkV^'-Sa_MIp4BAFOHZBni2f$(1jQ1@C#no]N#j)LV*p6MT_)Ze9rF9ql89QBsGj2>3%2<_@#.W(\G+mcm'+[q'*Oc4a%E/A]MSncGaf;B(',QCGP2eL@%7D+g0%!FSLl]]L*.F;o)qZ@63<&F\).cDE<&2e -(5O<;2G8X5e[j:U]G-5U.WM)5#40mQAUSr)E":a*l7I&W[@*ZlT1ESJ3OQZ1@1cL*Ac<]MJd+%.USp+(=CAcI)_hnADV^s-GW6Fm+r,?$S28i^PJ'GsY<>)7<+b$PWq c'jtT#nr#AXVBFX,pcM`%OeGKWT7/!SqaqH9@X57F#JI*FKA_/1:*s&H#XO;-sOOS&G0i`]P"^1jo5W6>$%Bs:HgZ.9,WK3DcQ`W,aP+4:s5AWjM35_1)dks,7`f-VJOsE;D:c)H=7FZ/VC,t'csDfF%/Fp*T?@ie*VKUWkGTsa<9Ud,l;kR>/7jjs-eH4^j=VF.l@Tl7a,ApLbj,?PmL*t37#R)TVNE>9'LjZl^+@ha;WR'X9FjOU*Ot?k+#YE:7G>nW+<AT'8p!TUpZ,+]V>rDPR(L9MJY>ap?'1 A\EZK$bliYn&5&oT<Yl>P!D!K%BS[U!j;b0pY2 L*gBClCjlt*&<1Ko`FXB\:*ZbD]9K#`-YKZ&+g5h)F/^=97iE!ApL^rdR?1".l(e)t!h<0lg^;6!4@#1jn\Q<^$LBt\;  8`9V<`g4LC(so`<% sAY*a.P'Y=M>q-C?;k!?knDk!pZ%%$5K`XW,b8H1k9,)sEbWjs4*AC;!&H6fafG:Al,0c,eWQ4>,lDnFSf.DK;*`F7`b$WmhO_ZdOa01Uo#A?,RVD=,@H-%;/\CBD/-Jb")HH!(0XgSnIhK[%b5-/h^?Wq0Q'n!d.NHig]\K`5c"X^b"h&t,Pg- W"[X(gqPQF4W/$GtB;%AJ6[#VaHTgV8HNNV2^rKR%R_"MU:Y+-Ms4nB,1#ArtADMSY=\dYXeQ])g\M!2cJg#SPCHqh711ObJk&HV"qQ^od<LfK@:FV'm;$t^k:qE>*Jh2f/+m9;\Q"@IG$0JE/Sis9XS_2T!;K [nL+VWJG!s0&:@klHsX@(f*4R/`sPYR'>8og.[LK-Bb cq+Zt6JFbdaM\n;o,ohqe<mOA$3@5dfO-)pI,e#[QOo.k"Wl2h[Q'jk0[:4p!LVWA.+l\,1cRTL.oogstQ#6:.1=.4)9q92c1]LcaJ-K'n=W!^^Mpg`5/<(6>1r 2p&'i)&bEGE.ftQfZIsRh\C4H=>3M]d5@c+3?F`]MNZeKh:/[(JWbXNa]q`?F4jl8OJEQFI\>#B-t1r?1m_[I= 5:BHcP@3$d+aG"8;Mg#TL4.lT2A"pmGo@a"&nbID9)DCW_SVJeZBCClsPG/03gddPG7D@!A\Y&j5s93d:6kT'LX$Yt7gEP_L?(p.#r=*b-'sc@SE6F[(>4nn(ZoC<8AJ*k@(Ua(mCNt,N@b>qm,o^LQ9W&V^9A5I%Qh;RJ\E+\BQ%IoG(!3GO>l>CAi(a%mmB*\4V9(lAI2J%?7dS^3/b0--0g25foi="!]`r3B`ist5eWDsqF'GNI9q%#TmbQf.L#ReEont*o+oebK/OH=B+;*tiAsbQsnUFeLIQ?j]kr1rjM2TWiEbkmP1]eKPmR9/A]t!Te=W>9A57.dQP^mn2Vob'5jY,5orT*p5*`'@'^GEG[C`A-saaa#cQUo^#>i+4H6tEkHi4@6(]#W.HQT0FQ0IL%=-(!r9^!k2MWXTN-dt^BU/'"0f4tZ>gQ^4/6>3:kb!8h gZ#`[kD7QBPK8AH9/loBF`d+&(.72#=JC!egf 95%>9#IF]0.T-&Y%IUD+tLR1:C\&R!rZ9Uf2>LjOMn%Xn; YMQ5C[f(UhZ3nAb,CO7LW7$^!o,bB5VRhSt"i4i::S=7J5X[ .Rp!-E5#FQN;+qI]7,R(:SX1%qCWK,m\9="cesMOMHp$pS1T0 \C^,?Jt;_Mm4]=i1XCD!spSN?1KInk`qiFiWF.]NS(HN]_bh:VgO7'\etNMBrm,/4>&o`W+tf4 -FUmm5\r3[ALm9[dUJ').^8);Y^`3P'A^iVSjaXGN/sQhOITrQaU"p&6?$4!q6CE)>Glm2pGe-)AX@4V,XDT $`)7npm8=e%*!>2FF^aXQYV_[2d5C7I_-[j]DE^\J#Q&AMW!$W]G3+N,.\?h>%o0s0o\gqVHL:%N]iL=]9,j(m/Ap5moYVK^T"Sc(\^qk1pe33N=`j(<*V:b,(#h;6rS8iq1A)RBW@!G7O&V]l9?B;Mm+8<-fWe]Zo5d%VXW\h9a4%4o`NKq0B/n]i1@%9GQ^2^Q5k*.$=LJQ8kXREg(8RK8c#.^FYVT@_$.N,j'sOiLfPX4ePXH;)c3jd-[9Te2f;dqhqs=S1Xcl&KmS%I(;Nrp,*7Z58NA/4OXlQ?[%3.2co(`#KCT;3SJejOR')!?]^^1^-UYY/.8 823gU]>h=#BjfAn=*&mDcSKpPsL(G4KgA.5%@acdimWp?ef:eiQ*@X)Z)MZ-pe72V)P]e l-A!=/Z<%80KA5*$0F@:Tt%qDNs4^e.Z]CFA^S"JhaB7r?A-n=otK*Vi#)<58lo/R4l).aDAeLSFsno`1Z#P3t2GC3FAal78/hoK,>'/'Z>h`:8[-`^7G-#Q7d.Vp.O^b-\#E:q86[UP@32gn-R4$-dN'48YiPh=Wj/H.K[^>0e],)7j6tnNq=G9(lHZd=*24"@WP!\.rC_R3V>W f0CF;SKZTE1ZgZc?$p&`.eE]:5^?<`]T")RtQJiXFI%U$Y]+cc[ 33SM^_RGC<;&B^XnoL>"4g)6RaHjX:)!P%EA_91FCViV7)"lR3HYXWpet\#r>+f`X&g[tAHI9iZ+RB*!4/jP:Wn?`*A5Y$b!eWe_[Z$M\<`@OQm4&(RWRNg4@k^D(KhZ.*?K#=On8L5sGd?::5C67$Aa[.t)9S\1"(id(R)-O5 GIcCO;05;l4;MQ4)K^-i;UHS ^Y2]!ac8r=K9#i0(YVENL_>WO`dk'?[m0AQOSqX_UDGWBkhS,.@W)J6s0aAdj3Tk>I' $ghFc!V[+,SS!:sAIg*lao;?1Ule(YLR*M5hgS0sRY-ULD%8"6"Y*CFA(V6hW%KE\=V2D%:,63r^g08WZV:OD'?-pdNq7Xs i$aSa^,'saNZ.?M+g!YO(Qs]>N?IUY?TSA)=5QmS!@%U6W!MQ#Q3rS[tnb._ab&BM,OnhAE$QlJXT*H3MH$jKa.1sV+aEY5p:[5LgFE[+n01)l/B6iA'4kB6NV!#.,^LAK]r9Yi?mG?VoM9RkW6j96cnWCLG`4EGS+b)'_!4tAfYJN)H,'[:^'7G02\eEZVFkL^b1C5VW5%-HC5 Rb8"E%5!fJ#@l51_4a+j>&\36@h;AW;GpNcg)QVBS:SJn.CE*(5p'FqT_fe$8=ILSaA]KqU-'S-51i*AQU5d\m<5'VZt_nJFYYPa$h1NWY^[2Pn8rm[^A$K5!86p8g@_m@i6oAIE4ScABg2^@1#5c&V$G%b6qXMEWFP=hZ1I4@2,Z9OE6AjkPDrgAWXS!Qk]M<*%H0ck/5Q\[B/%)R`\]%?/8K-\VM3NF$W1s@Dp=6+bk#H2KV`b989I@RUiQ2[\5LJkcA#MD/ah$-g4GFC2&/>F][OmO0nT'ATVfl+JtK?5OeOlmXOsmW_]2:a-*#!EDefH(RA&d3hBVH51b`JNNcZjFmZW8LhhCfRdsX_;[LPk0^Amr'Y]MaFM>&"Ah@5oag&U>0sgOh4mqCk96t-5CDAAIrtBjMt6!'K(j/!Y (h/'9m3N8:?B".D<&37kX3Vd?kdMId!r2N VO :#/M9pebF+)s8_`k-jZ KhD<2Qi; ]"&.X8Yh=`_iN84L^>.,okJOs#e\:V9)_As;W7&fsW\9M9A?bpeq4[BAJj)^GanF;dRBATt!MoskAbDbjmkS7)(,J#<3n-$hfAM lP\F0Go-'khS`KU^>%d>-ROR%t?Jst90nsR3`9OO+mE6X\japPR"54,(bhMjc$";$h-e_H5=tp,[YicH^1Y`<AXO_"0M`/Mda?f4A2.oYt0CKf]+2D$h@C<>#K5%o%)D>QD: scf`r2dgX">cHlTH:>O@ZHq=r1MS^$gGN'Q'_MHD5n%7m9At6WGIAXS'%V*C%I(Hc@=aKUe]sWo LZG9-?USAg,kG:bZNZ\Q2Z@-aM^l5CFCQKa%(M=APehR>Q;-8-0P/!-'q 3#apC":a*D'E*a9[*!Q^"l-Bf=@@Llb6AtdX@D]E)T@rUe^+CUqm:o'']Tc>hSVnI0*mTmJ@r5`k9@Fk`R)2 ?`!FIV[Km(<W:a`+GdRnS^/q]o<>Ps)aAdN?*,Qk!,[^72@"0Fc!?'pr2jVr;W,Sc6>C*Ttp33,+@[p,/0^N]>b")p*3^c:p1UULHW'`Be"Q]%:>>!lJb:/f`j-Gisba?UA#G)FA^tE[=KQFMt-s-NVI\03s>h;`@E-D6t_6L @ Hq(Yf[.O(@;"R2i)7l/>4_`_NaT19i26)Jr_+d_$s X:\&;O%@[( :%Z-,$!9Ee@r5MHL6G8&?^!Adb]e@oD+9ghjPrk8-A&1KfVNA+1Yf1;04dqhb-<>5[#LJU#;t1K/!e;]$c_eMG0s+F%Y'6$A/5GJ;U])jA/JK4Si03G$`^7A0J@g10a;Z*B3IjG4@@R$G&oYI0W=!m6CaZ96WZSC7"=QM=FKpoGA)m`Md7:.amAMa5BToXgk@PAYXElF[]A@U\>AAU]t>MALHRkqRZ<(*o8coNQks[i(rlXl1>/#Nn2`GSaAE=ab>6Rt_` +=p'e9f#9QVU[#UgLV7IM*&6lRf8(.'-DNK>ZTA;/hkV`1&k+A8n9!6JO(3fb_;O3.[ QX4+o^09RMK0-'bi']\J\g+#04UmYei)g]%=#-ZG&PYQbY34(8D$6Q!PKT$+U2CrpR"[K6,\XAL'El-h&TJ%VJ'-qsL=qVdGNJo`V0bn[)oeX7S"qqLl50T=h*(d]Yo@@C)+)(6QDJ_[O&I=[:(O6ABIPAg"jFg+gm0=kl,GMtT<#L@ !sjU%S85O.iG`1SptR!Bks[AQ':h,\FM_#p69ZCI:VR6M1M/?ASYkm \ng;kEZ"<+31"U@(`*ar^?jd&M5Aie`T.RNs2$H;0BZqep.33K $CsM-4)9Af16*)TE>rZ+5b0;-"' &edIKN(`N7A8)8qsrW>)_s%d4f3o)lsG9jMBG ;1nS^#QE#YkA?,R6R>JfK=%&j]0*(&6p3icNN$h.:P1_t=!00#0l!SXlAPP?>03)\99)GUBkPlAWf`6&?@!l.BZqq8D n6sCeXg%M:EK2`%m1C$_kF+PW%IS@.%9s/CF(Og_:hT5 MJR6W<-:S99' d!:PgHA=.RG6-bUAcd1.5eY7&g]Ca1,;U?XLD]J)\l\rkG=Q4ML#9;HD$> i:;On'i:k4G:%F_6i[FG'2V<>k?^b6.lF;leO!GN>`T]$\mH.J9*mdF^0kNC:24 !5(S@X[AJ7 Q2h[K:1^Ab*J"56tmB%7$Rln"q&[h&=,BYh_At:?asAr#-fM)n]lK@%lA)h=%.%-X+LM8b=K9`6&;$0D,5X$QHS`hNP3m9tZN=s#:5kd6!Tc=&LW7br/$?6YN@L0E4h/Y&:DeAB64,D!osg%\Ij0A W(0A:QVGh*ne^n$m%K0tPW969Gqf85jH[*=2;8V%gpHV3KH'bqZj#i]QImc!'!rKVP5AP6l1K9^T:&DmQla*='?X1SgmA>;@'>K!n7mL%]]L+L_)NE*c36S6pRk.&P,#AFhISXq1d:(E@)ltEIq2Ik&KN[.Ln(AH\qqX/[87\(P]rM3Q[F 8hE:![%M/*2V3U.Ncn$8eT20-@NA*RNt%p_-"W]/fsC(Nop\Am"f.VW[0,jQfLCPm#XBBE2U^sV] GasoT^9Q (HDl.MMKbU,fNR>.[N28U;d>QHeeg?RrMJ5diRlXW4OdOO'YSL[Tj0KE2k1A;g,+3da@N>X&iR*DVB$hgOrB.0q%iA[/LU!#f-s.1gh/nd,8cK<B0p-.p')jE[X`VR6-2V9*0":](e*6!p7sFhgmi0a*q-g(t]^eOQCrO"-[SH0#0o0Z^pJZXOO`Z9EaV`C?^m#Iog#sYVgm-hfNIBGUR3tebZtKE'aN#Mr<QcE@'<M_Qo6<1k,s(8#k-p4spe`o#\eUG?- .;tNl>H9tlP)mr3Z$!'o+jX95fDM[t2"1G?ADrG9j7EM0,;WB-FpEm$sE[&"::Pnqq3/@H(,bW,f/KJZimq(WYlJ"eRMO`TXOpSYM6-Ob&d6S+Sf&+!Yg]4+A=qH5S)3d7*\mdiP?Amt?[ANU>OW#L8teRfSZ[^67<[f: _tX'AEHnAE[W.oCg8a$Pt_g`'hUe9L]R)93.*,M<X0R&t@#q\qkOhcn23?on@ZHTU-;\qS@%<;P:?h>W!-2]Z`.hh(;BT)2V/2m(LY&)<[1I">#]<[nSVMi+"9Nf1>_(KKoG9mT&s&_k\g7%o,qZJDOtRAl[#@\AI&^*fm!No$e7*4r+i^E^T<k>s/=osO'Q.`OSr_Y,L0TdQO!Gt#A)+2t^X?Li6\p+PB-4A(eI4$GBrC47;&FdG2AB.#Mf-_fP#W@ro;\jcEr0/ct12[+N%="D"UF\qhD3nJCm ptMaZ!-bS2:;0P>&[T]k]a$b-3XT\-'P=KL]A%Xh70nX:Uaff`i#Pgf,edW'_GKg7)g5gYt_,9\L]>go,jr!tgjAOlRTI"3DnSX(mtXKlKgA9bD35!>>*1_6/"@)NkVS%mKFfHmqZ7`.LBR;,p=_Q^D63lt\Z("HjpNb\4^0<m%JoPS:ST9?D9YciCmG2iS5Zg<02U*Ai?nLJ76">-<L9\PU Pk?V7NZ'd]t-AZ'dlO+>U0cth)+ZG"<2g;Xc.n]L$btADVq.e"VWSL1rV>=4C=0;o8:9to5FBNO,nAm^Dh3fR1j,!M2*\*;0e(C_i,km\PAn/fJ_^5nfOMk8=>,d;!ZB(#TKmVTo>;U\Ckq5Y>[/b-JPf7L@tL#d6'&NBV)f],\5I-S:#ASCGF!XI3BH^=breg"m8lAAbV0k_BSC2BZQ:U5"C0Jo1GGd`1gTH&N,IhHff.UnfZTB_WfS2Zn.Gqlnj7sZS?L%R_S8m+P)f#BZ,.]jj9;Al#9I";l:4Z2-IMIZl\]4KFmiq=(t1N&BA8L[H0r[Wl; ++?AU3o.A6T)cjD()7_99M"mVd.S#"LIoicsog^EW&k?V*X_Y?j-)4AT?Jr^58IJ:!p2G/q;iNrQXTMOF=JOBfL:ZBlh"L0"PTK5Q`1p\sK0Ne9Jn[I@ P&/e<:,>J!0k0iVd( -oVhY$&PS(>6#6D0R?@"/G;cdJJZ'kpIYjE0^W;XF)@6)ebFR5 D$<WN,Fch3(1j? <0DW?a674XLcm/TTJkg(ScO[?2nlkA6iin !4D"iL!/W.>i_h?4'XgH)kK9].eX,I+d 5@IUTA#m/_>^LdkKsCGg:6%?`CO-*2AhY=cAfQE:jq/LUfKS%Oe_%Ac2571+OS^:q\+JMM#DTiK$?qs2qAD?fp6Q'!4H*<07)Q`Qq/1++o)VCNW ";j<S&+-[ois:kC)MW,Ba'35Yoh1hR#"JlLPpPTXZ@Mr:fW:PMcajPaiR,"+a_3$A%YA]j5SdVR**sM9K!(V/G!#>0_l/:*MEAiXIPP&bs6%ea@Z=[;l`TqM1!o+7mHg-YD?3m%1GS00r<P5t_Y3+jVHRR-*RLOCFA:="StiBqqsoI0fGl!CV]PeACc.%SA"gn%jmS/Fmiqq&3=X!NUBc]E%k!5nZaJ)VVX;9B+pI2fO7Fk!"Afkr05Bg&-_A;IIcQW1EAK83'=;% a.Q8sA.fk2.Qcdm`,g=$CbdABJ)[&F*n')mgl`Hst,f?QW"`rU(a9([[\2Ikeb&,_"i_"r!E5\rhS6>^EK@J'=L"Lk\"A,VSWrSAki;r<'_nj>'B4%O*TQo1D<"\8 A J;Db)5VXGp.JEDoU&cCGK8:DqAh'DJ-@Q@9QmL9"3Vb6-P!IVl_aXc_Y`6,d4W1#9P-[O^$-$XpP3a5TP9QapQA.3Y,>S\9VE-s%!'-:J3[>@E&RU!B^l`5[/]5NF#E)KN3iJDVli&(^APc=W;C\ts_-A DQI1G&DRaQ["gUk'[.-qf<_?7:DTEOcsA"WZVI!1DA?6jC*3"KF1dik<9ZsM!*!sIW9A]?1A3H`Ggn."5\R"m^cEO0nP`UXAT^:r@A=GtfQsYK QCrXn=HkrAMhY24e-qFNG/N(E?tFiAS>++fFKXh_MKkGI$_#BhA]fm7W7nL4b-3>dsLfceR=.-644QJa@%SREh[fB%lQ L2203F:Z[re0bL*j_M<nstP<:#;\VKQGLs'U:K]h&N[Vb4kQ&UYN,-D.[0S_cUkC4G1f70%nI%T&[rTG`WL'E`j:Tk.>qpjB.=$=)1F6rVgEehOOA?,8Q/AL@^'f.=D&;AFKtF1!qa38E_e4EY.Ul/.qMA-^'-L;nZ2+k_!s-*Z\f?P&D9e`+T?U;X%EpP)+m_e`WaKK*S:f%.L[9Fsng43neJVmSA5VhlEhYV<4Qk/0$?7?!OIH7/%T+k;h.d?e;,Hp,FMVjL*]ZBAjbHL8e<:)#m HZC<]:3D\!gsl P%%k+#`ep.P@V8@FE;89DnX/oW*/Qleh*]5O=#eQ,h)6^XMds1%Sc?s*DXTj/F" cJ=\WI%pj;dpFa2Dbs0!g-JcCql!(t61`Lgg s3U-4*:f)@SG&dS.P5i$9[T/^ATKIBllJS$Z9-_!Y7[/`<Ao\GJT>QWbd]X9K274$"[1K.<(j;7 h=::Sm_hEn>l;kaZAnVtEV/C*f^n&At1FDY4nqJ=f=( Jnro]cA&UqH`M+Id@9h7ABJ)2&6%@#bbRJG5reK9l3ndDB]KoBnB;)/t 7QPTpk@6g(?q,eF'"rBXXI_-LqfA/cYARq0Ot?ANt95D3*f>1e'#2o*D^->`HJ(@q5E ZE%&hM'okp0R\*\MAAMoAMje-0SAU)%$\&bJ]49!njTfPEA*?AS`%2ecd)A>j'@S(Sl8:@@?!]`;6o,$k#J,LI`T?.; DaUU9)#^nCkr,-I'/*g>QJ:Ol% [<1KRqcj"TD\'O&Y2<%X0(Am=7o#VXg[h9Y"@1tV5&#@--Sr.(QU.0nf]P,4MRAl7\_H7-f0 \M/l.UUg\t/jI:'Zs!r'a%^o[k8*/hA0g&Ht6L(^A6Z*l2HK$1*PAZCN5fM(G^nT\V^O";oobZb>;#1WeTQdB;9%t%E9PtXBsN'QkjAi_CK<1*do1HS$lVpatOaAWH4`.*)7mP%gFIAo:A37TFF?Deh)B-PF)QP<'8p>A-D)\GLG+o_>+O*YepW=P[b]n++Sbn)0J?@ehKoD?VSmHiK++E\;$,#?,j#Ks2a!c3_R=K-DJ7.N,8aJ(gIfsX3c2)r]W)=@e:!-CDW`AEM-UBa7/MCc\GVGa"C+pN=B6Tc)b-jcR)?`?ljG1'4XU/7j#qFqg8>@MmXD;,%mni&W6U-9%.#A#J1)j6S:qe:7HNrN9f00@"=@g+o'=bA(LB(#M2Q0#(15*,#hI=0ei7nsbYW?rl0Jh2_'m9.CLpb2f^DLI4'h;kDoen2D%[njMd*]Brq',GS%4Ti'&lri]L[^1,llHKBI#LA_]"5F,^ .G&,@/ATTj67<&QA;A\[C5bKT>p$*d"-I?X+RFd=Pcm8WOk-O(+j[0inG64`nWU)>UX2K+8r9]8s)NXL'5L)Tkn/i>P\UKVb H-#/$Rk`J%Sma#PO/=H+gBY"1PWQ]-$?O/Xn"k09lk-i+t$&aEV!:tgY?5>k?Q"f9#HmnZK!Tt$5Yck7V3c?ngJ7sn4L8'kW[U7CVAjhCb`F/Q<RU*3?kSQO83c!G]=76=C6OENoL"J>q/6rP6-eIQ[RNfOihrr%[ta3RXVhh2Nj4A2Wd&<;sYQZXpo+4Qgaocf]b 34B;59\?%Zp_8TBbO/`4g2lAm'H/2%9/;eP-0.U`[,SOYJ:SVE][itH,RW"PbZ!MgHV4%[&-9LQS^O\C?B_YL%W r1/\2l`r5r-eTKc7:jRFI[3k(Bdbk5$3E'NGeg#!Y),<%'`Q+$Zh>N! ?K0:2:H`P`H1mq9kG+',b]^`-TJ6!VDE kXq7ODPC'db<HTc8Y \?'3?CLLWB<58:Aa3G$!YP9>FaE6>YRi08]PTC*GQgeXpnS9djJ\/8B6\i^40"ZC=e[O:-^5'F#3B^MlD(j,SCA\OLt0@bK:_6]i^3/QrapY0OcsfO4F-h(n\FqE5JT[?s?qF._HG JiHBZ`;*b#m]=(2%96l#.!rYe4((6K>DN;40gp@=iV_4=@33s=!+%_Q"N.7W)Hb[_/Kfh_gAKBL*NtJ-_!U(ms5KnL`.37@`C"sO-R#rNf25)WKiB`CM'7FJ,!b9#&+:J-6pb52+F[XBQN4WZG1fJS!Z*s,JmA6[KV`g+q6pq4EAc*5!WA80f_Q[>0]2*[tA<G$Aci\tYO%Z?37[Xl-8)9(<'F7r'lO"^*"rf#h1Vi#6=TtDmi0@#5D3?=^Am`GiK"R:N7*]<"c4# ;gZsp:3<69dbiHc7CG=Gr1Kgr(rt$,e7;.(oA3C1AfXY`q6pO0%rB!M+a_AD4Pj46.O2mI@7n/Q<[@,n@t5C':,T?AN:^[P57m(nl+Ud4el*[,M2jn5!(?2'M\S*7n(EK$TqA?THdj*g"?.YM3F'\atVAkckL:E;CKEA0_!dMc3n)h\Or^A'YiLPW&I3=NL.Y+B@tATD6MJV]=j[F8N'W*nA'hWpm(^(,*p.[BYnF84Bk??ZfX7(/i3_Aj=fKl/N&#kIi8dIAM8Q5Z%.Q2A"KfX/or\San76C0)s&Dlc!MY_R+-f4A.H;'$H>os4rf+#>f;'9)t7KAqc4nj+cB9)%]UrV6P\pS abT$k>HB YaIYN]j3r[RM;I&#`T-ADV52bqOo->D'X,3R3:=f/$Le%Q#g7qb)2[]^mJ<7+%N%%!`#A'L!tQ-s?Ri??bX:etWR_)R:."<%g2VUQEe(&'H%/4k0eD,Q%g9+ %O9\0Jam:+d5.aE+):XrnrDCZ)J1MO&=)5G@`bQS[Hn#E)N_Y$j'^N[&!^N.KL!^YXKH6=JRr?)Qk$_c+N(38A=_BrTSJLh;s].,D^-)U]H!*80l@_XA]<'iCPF$#ZGM'2,JWo=MP'&Y?HlMKd;Q7L<1#U(3f%8"iSNFfh.iFXTSAJQFgYp6\B)[TI)]N\ZNti]8+$OKoF=eI"AhS.VcC?E+7I1IoFV+R`]dJqfrF#@?01]/QVYk!n2aiq3,RWOJ.d!VR&h.RRm5"C1-#hSAI1NdXhq'b.MAP#YF"Zs`R+Uq8tV[KQs!bOlAG35odc0aHh=3qirWAd"?Z6I^.4lb^XHM"'X4E=[YDbS%I9pR[.J"kY6H,)2^Gk-K9SiUN"o/S-;0_sgoNSsh+kp.GAX=J5,E>\l'$. LGU$=Q$Q..^_Y%gf5ft@6)hX;6SSVD(2ES,cA,i9;&9p;U`sirQZ[_n_QP/,lBIKpaEs9=#l+*n=cJ&3bto9DC9UN%ZWiW?l>TE26L`D%lcqQ:U_Cf*5d+3%Il0k9>Y7D[r`#pPm[8,.]EiKIIVY:jI*@tNioeS-plYcaZ3YKc^3rUr8kS$a1:Ulll&Kbcs8a)cCXO.n_/?DKneYMB_AlA"giW'AkkjhA$5#Fqo%4khT_2ABAA^QI 0JT>b/E`r!bNVVXXNG!.*]i!PVfh]MT q@rt@:%d3mG8*qq b<17hcTcU+Rk ]d#.Aj0:Sgh)R^:MN6o[R&2i,+GdVdj-0-QIngWG;N`$DBX]l)K0%n;3C)A6$N:Uqp^=2(XBb!]&AS;Y1-;)IAY(o*3,"JEAmOX O/R`(q>=0P(3`rSP?:`mR3N-#En].K6e/h>Qf6[>WT"*pK0=6cMAUgL/hR=e(%Gg"nED KptIn1S_8P(ab9M?RY#^]G\3s(^qcq-6E_K.]hRDiM"sEU\ UWV\4Q7h;[2V9Z+dj!(E+W/Fl//UFb\`QLN%>YdO90@4O96K;_:M/4)W*Kj2e,QZXo!Xq(l@6<'+L=c_?,B3VA2AS?AfU R`X js9,kLt3$GCS%21rQ9seO!e&@;3AVdl)&3s@HCfAj:H8l,UUE^*b!0Q-AL8l\:^#2+ $KLAh&@C[(Sit(tV27A*6rlR=>7>6dM5hHA8AXh](F(==jB"mT&mA],Z#nU(50e\=8lQj[Y3d\N/XQFsHs<bNM/_:Yd+-iY2O_$QG=EBqmg,[LGP[d0cAhd_aXZ]0+TYT4&`tY'*H)m!ZR[$T?^Vdp,RI;oJVfKp::cpH:\POOh>7Ye^I1aW_BoEl'B@cj'pk]]3EcShAoPXg7jqHI6!KlVl(kb1"]6W?7c>Gg!,;m4<]'.XQ[DcUA.9/UnWfWBf`-%DTS&g*O#NsfW9P#Ags_HW'$%0RpUZG&kK45VaCW@;7TSA4,[Zt,,-@b18*@BY< ,1.Z_nlhV;:SXo&TpqJGWb99j^lX^,qY>%dSGtf)M'FgMW,*c27@0]ACL4fH4HH4rejDXr_T@0IA+LW K2nA^0ZTG:[B.s5J`0 ih'!10=[:OtA*W>8Qin#'1K,OrS-,1GT!,5,+2EM("!k9RAD=M`+p";q!S76o79;Ii7g"WD^DOT$k4X7E&-mZj&GfkZa sl:G;(05#jSq1Fm"Ym9q 5K!U.G%_@Eh]=,M(c5G[+:l-/)U,)Sl*%A\$3rW$X;AOXhAX'sf*7DBTi>9skJ%GQiYSk');4L"tMK<\(HVF%E&,coajVoUP^V_T5?-!MIkCnGC-m(2`mBGWj7(5T?(9AQ )0tYgAo?&:U=Bm"7ia[?PC>0)_qWWUU>/jP(q)+OWn6LTW \gfa>^kXsO^qQlD33@qAUseAl> "FdoEpAY7jtf1mJNj0=!/sSpBU[Ghs\q4j0abhL,A"f,4U:]21a*5!N$p$&9 ]0A;EOf67e\04b.-+3d].\mAkfdhC=@.ZUgng!9dqF$7R;l7)&lE&mjN$/"E,MAsGAQY<4&AF'[s:lG JT&lO=[ck6$$TQl*B@ViB#gPRaNF:oKs?GHXm$91<\D+J#AScG\fPC_!D:5iHm0QoU3aUL? 3WB>`C]7QB]pQE,B#!]CGCK66p%EG6[8AW@"*Dm<8H2#(:Fgtae4#!&CAV*?!A,>/5j()QJid19Wap'025k,sB(-1NVt\KAlm;/6lnQ'=$EoDl(A!I^6?0JVOO@t5Xj6a]glpg`Kb$pAVC`$Z`%*t4Sr^+3%CT?H'Q8:_C9q$qeDB2G@&NAN?3"2ct2!R`J`_Rdk<[2?#'4I-&eWNbEcH5O^A<,45kbAJTng5cjY3a$@#"7D>DgbL_oY[>2N<37$)A1o52B\fR mdT>'igh2Ij)VtGBU\6;<?g$APIHf EQd)f%VgQ0 &cdkjm\W@4KrXW09na.=?s?6\fF8f#<A5dDVV:peYQf+2i`FH2l+5VNKe+JM2i>d6C"t`L5eqC[KAaP4XPLQKYB?Dhmo?,Ul3(f]AdVF6E,#4?N;@+d[fAH`GcpAl j %m>5q\/=_HrDnj(S=l)gqNXXt5i3tOl$/3P!5&dINtg7XbOR)ngTV^`f1!#/[-;Jp%Jf$@9VtfOQbhA%%AbJ-$@/Tgf#p9ndpjVhjT:L0e`lJABr5<-&Mo/+m9:.)>SZ*%LXfiJLOT2g)HM,+D[U=7hAO:oLej8=eg7#`TK/@FFm8/l M"oXQAgoEK(]IfTt16t]=Cc9t1RKc+1B9ZHU9B+Xi:j^Mdh;3QkL42'MUp$ke?IdFVP@'>-W[PqLNLQ>P[P8Y-,ZtJ.2rlLo:pb1AXoKt^Ql]OTo/5DMrp_DDiAi#Aj0];_#:9LB]2%Fd4ni(*BrD=7D*MfeX"aF*0o]Tb<4mN;!J"N#g.Z'8p>8AAqrY0< d*PTA_9JA6<^^cW(E2g_,.O]B8XRHc9 g_1A)f(*o^=.TQqIGp1>6[Hhbk"I"rJ'D3Gs2*IA*['9aiT%<#+UB@_Y!IL/`k: GSk7YW[">kK=YP[aj8^X<`&?;*189@+ 5A!';)=k!n@&>K 99BErIqF^-HYH(tsdRoAD,-B>2K]@SkUBhFWd7/7L>ABL-6[Ai_!!X9khq_IRcMM<_$/Y]rBa@t+ab/`maX2JBXqApHG[0>sq@o]A-"EY7f&\VPn)A(%H65WEo.?d>CJBMnB/sEDOU&6_OtY,.)QE?j-`;qF[MQN?[%l(8M6)6(50.^^!8!GPGer__c-dA:TU]Jd)K\ oC+,0tIjPR9:Y&jMEk+E'p Z?-S?>Mb6eb3(j[+8^-Il=2<#/OH2hT0k>Z0[[ssS% jc&jJDqIj05q 2H)_4:tIeX,9O#k<@3j_kI(\mG`MJRJ&lq6Rlbn(Z(iXCLs3W=D`7O=%qE/a3L@rF,2 LHMlOd/+O85Kf%FH:Z5th-l%DNoKcPk6qHA0 SR`ng%p*^tf^hl;pQaHdRsaNiPIa%H$Fj['!_2IARV6nks2EqA$2Fg)]/dGf?,7HMD)#;=[es(W=gOOrQc%Afp+'Mh<1#3mV71a0a`R(b0BEm%H1H-j-YNWd338:"\d khVYX$npa2m\'p,$/C/,iPijo\,'$+)$VA>fX(BI=5L$Aq9U3j6gQ#&A1,V]="AX["74tC$$h:@12L8BIYH#2`h>#p)8,PeYJR%Ji?f,8aH!N6oQ)I%_d[+0aE$a--fXo"o?P-J/5T4&& Q]@ZH<1hindE]&N?!fBjUs Nt6>.(*Il"`3bH2M;,X[_-tGAY-or<3jPBii^BRB6e\_]%/='Qm?YO=BmQ;\o>6CXb _jV-p9Gi32@">$<__8(mV-2onU;SI4D1 @+7H%d3Na;"0MRd( Ip'GR;Y9-U+%tN;VZVe!C ;DKo"FH69j$OM:8![&VrKWlmb`m )W_hT7m1Ki"lERR )P 7Roe/E5T+Yr6 aF/*4\VFg?),8H'0<19moRd.P:>;:37Eq)PLcE(m+c2_i`L9Et+a[%QA#dhT20^;fq4Pi.b+dYh.fnaQ`K&_s$;7+2DK=G2sBY=Q]D05AOSgkW;gMpJk]/^e_8Y'HTa@hQ_4 F4k[Q.X.gH9,Z]MBh:@O,%m1<&&%q87meWipq8,BTSRh1jn2Tg]tJPjU4(J]$PGCb!jCYjt(=e51DQ:%4ce_e#61K!brrMtO0K^)Uc+qA:"bj:P0d-9HL2oj%72HJGJ^@Q)m7A(eMC"AM3CHg-@6plUUiJ-$M]0V!>^E?\M`Apcf&@YKq33(Xm]O`:ARIe@QAfsF!.QnrZ1"11A;ioWci%j3rETcn.?8[-b!^Am39b''D _kt,;D&^\moFpEbaFQk.iL0gsh!7`g=!=Z2mIS/Xi%A,sJQnE^o"642#0$%?"&5of9d<..7 $![*BQ#DhFerH@#oL*K2[oPr=8.pr>,Y%l=Aqar\;_UVZ]YBDO[IjF*M^YB;>ecZ@OO`!t#!jV7C%;bAtf%:gnfgDhkb"B=_pYmF6%WE@_2gV9-+<$cCNL]oAaM&5)m.GrSno/+>Q:^f&POh#KblmSf`3WtZo8.\TS[.6GLB+a6"%m3m38>n@KU\K90Aqn5j+,`"\F9Ya%\@qpK=Sa<T!33fYi=[2jmA,/$ r0a.C".=aZK@q$$ Ecg_kl.5^Q'Se;=/UT.age >g3km P9- 2,^RpC[q?9r[:m GcQJ/.M$OO&b.r! /X b.[_\moe/C-kSpon'7eK.g\Apt]612!=B7BS+)h*MY.9Y5Nq'5l\?%6[Np&!o\7!B)6]O#nDP,MJ-/F4PKCL46[EXg->I`nje*+1EJQ4_Z!W?98AD0t">@J1S4" 6DnV-?T*r"MH`!$Ec6VU)2gH##7P !/.Z';K8R1Ns/$0A10KQ9RTd/nel7AndJRfEAf24+#[C/c,WeEn4/Ws ALN+QJ!Q5;ib-Ucl5>O\%0//.fFi\S,c)%,K!,Y_6n0^nD5k\;nmbSLf_l <Yf.cs"o#gAZhK'SBW1-'&q:@-p65!GQ_&Uo!mN:kRl\=8_8HQLX1TaOANa/?(8NtU#i<^T!&ABOS9:^:PULc"ghLa6<9ms-QL'E0UWUbYIQ<.hIbP]JA8qgb17+l)shX(Lt8D.8?d+tq$Ym3bGk9Ng(Jq nOlf=C#O9+Q:k^cE=,]+c^T2UY$GmPqRK:1qdH&eH\b%N#0d#%P=%5Y@pUa(m3J=^.OU97naP_H^Q6=X5VgnEB\Rc\R]_rPPF +CjPJNLVfJ(^M9:L>C:RaAblU+[7UAfQHWP+q.`rT,PLWD)<8PB LH@<*lanqM=l/.\OkXJEFFV0tA#2'o,Bt7#PZ:bb3q0To=)S%N&rL30f.Id4o,3Ie1Vt= '^'3'^i9psXE\M"MS\,?S-Z nG8[C&V5TMabH4XVi9Gb.GMCP"D*ma7(#;nIn(WfG*hp;_2HsUF#GUd#=&7XL`[sVMi%j2)/-:->AUAHiQE"GXQfp5Z^@TKQ)YJ3E,)!AFb\IW#ETD$NZ(<;)L4D#Lofa=)(G7QR MNZ'[)?*"K f3teIhHA&A+Z;gN(2Db^A,M9Ak7 92o5EOtEhe%H4AC">Bob^kO_ o2)`2'1Y81je?]k_Pn]cY&sg\pb?c]"_ERiNa(5Ih$?aj`>or.b 9ef3`lX+^WpEDP"sAK7E`R?t*R]""hf\a.5ch9@FNE/k`-d$lO4,S"PLKkFo6pmpNX?-!.fN,?rMeIA5;^:m5AKA3h=<m6>XqIRgrkS!XW/W]RtKDUVtY?/Hg% ^A_#tU`%HI7`O;:=fi;CO]t&+=cWkkO= qW<&>Gn4DbX%WG^@LMiOA:DM?F_noP0[ti4p=eb=jUlQr-%?=tI_*h;j,FGg6n'[1+/YL2e%XQ%5Za?H1 FijKT=bQnh)Y,L5jJ'i(CiWe@k V3I(3\..UG^D,1c$8'^E"d1&OPb3+b;9'"4XIGCYW"3rc@7dn!lHr2NVI#-@GlePX,B^-/%GM_?AWi>=UO42JZtbN[=hB:__5lCt+\W_,4ABdQ,*aU V]ZJ8>7g\=L>KWe>'!C?6+Z)-0jRE&CA-Rps5K(70Sl1roE&LBrla.XhSmI\UtL1mcQ8be+cl4S+-aTsWbdr#fJIVl37Ap$.$"jJ;B'nQGQWIXlTh:(\9L1\kq'h3B9nm5h?D0F6"mHe:8WfR,:FZ`?B:Ls;/A *\FIk_&W!4'B[q=eqCG O74/*A)T;>1s$\fnot$3M/YYiY]U*S2808n3Qfk!F=@lZ=D(\N6ZeFj+6"g!$.Q,J*0,IO@Xc0m+/P )6J-K_8@A,(]XdT]DQ5NdUq)2]a ARkg"jCl.Chf?;X+#Pf4UtXtT_%I$L7&;t.4dr3A^eWFCM(l0]BHnG"r<_ ]3+&RcIbb4/sFEg=Jlo ZO+@;_]qG09Pf/iN+o*njqQ*]V6NkkH=o).iL/N(eaS[;Fm37b]/hhD9e)Akf;iWg:Y@#=RI`ke$N(M8/Vh[ih9YeB/kE/]6ISo:h>t4PVNP#d/I0jN]q0-]U0)5RK/B8E\ D6.O$J"^tm">HrScj`3pl/G<h+mG%\Ki2JHQ[&VaN/R2qUiXES^'\*L5AIV9;I/Kj>@m[_tl7LZ"K_V*9_:toSt`Jb&HKZ59Jd)M.U=2L*MK#RK]D+k_1O \rN$SjGgbPH6c4q&940efHh`_6pfr<`;mZ!+'%QF #Z"NL;b2tObIKb,oX_<]5?L:4H@.:^?Yr1N0XKrflHFe08O8iAoC&%_]5 rGLQ:;+];W-d5Xd\m@cMfo]n$$nbFR$D=!*sFI9g=t:UA9pGhX;Z_"G-j[XieTA@N8=8)$VV R#seSQ/-OO1g@ho:05*ZgY?=F$L$8FZ7isK[`M[P"#r9.8ij22-VnZmCmT;Zkg]fT_D= kCt`_MU#4HfD)7#QWf8 nfIKPKFK$lS=$n!\5YB)*/2<)1iAU2"8;OGU*M*j%A `i?USbJHUGmrenT3\=<k-J23`n `r\71d3Z3qp<;*oA2Vh,rd2A5/0%BM18]8j_!QkDN#6oTX?E9E?bcPpA$A*VO!nd3?Apg60\[o"++YAJEYigSs'(p9adY[0>#]A3NM$AnIAo J9E];p^10fG?g./pNe&$.o>&o>1eI/e &n^0m'Jc8eYdG*AX4lLWg9eAJ/d5;Kh-T'O%I\0)\("66bIG"5+2D@,C*tf#)_]ElQom_j%%ndqP2i]esMMcetM<`?5+P>K\?9?A=$*OQ#UA]\b[o+diY#>"0g8S]475sOa,-^)"nRcF+)ALo_FpEA,+/j/5!/4pR l<^g,NCj)eD]OW,-T93p+T<*e++H.#Y=/HAmhBtKs!7jc`pf6kV1aEA( 5B]9KBeVop.NV(:%GT.b.Fe`RcrX$-]aYZn$m@4t`7n[GVNm=i`0sP_$[;,2q=_4QW @bTWV`dCb8<^hcrBaqNB59ERMDEP[ps"4lRM0R<50k>osK$U0s's3A_n`1]6igsA1W1PiqsF3X'ccZ/9AO,YBP%m]q7N&+Vbcbr8_b7X8&n<3mbD/."]38%>p=Y!s1PhSV5ld+qO2oK/t"D2mgS)r="TmFF0^5 49)qG-GBn/k X`[J,nI/.>Wf,Cm'mI7B9\PX=.J]00CBkj)IoSG%isn6.K`cS4.rX-c#`.IPfP:I2Zo3'F5Ybo7Q4.24%+:1Z#CiiK(Mf9,>VBh'qphp%]56afof\X;UXnqL5&qT*f?%g2RT5AL R $j!.baUTI57,H7"[m:A0g;KjN,g9X%4bZl,f=nQ6.r;$'2=('\pb5&1hAfB"A1!F2!Ig>M5`Si;dk' Larm2<:[GRk%D6WCL_%K*to=+]RhCCqb(\EZE#.XU\geYpA]Q-S\Z24Pf(.FI9NopAptQ_94Fm#:kFBj;DW'K$a3tAnF3#oY<%EEiskpRq-"q_sPeHPIZ]O7E5E40TMV q3kU MNVRlRYRWI?tLlsb!A&-ZQ2Q0:j'AnA^NC*_N#Knf%+RO6EWS5b&s+hp9n7Jjt`NBHoTa5>*$C=q5=Zt[*jhRQRYX^#NaPfE;WB>NYk'PELnsn5.a N(8QWAa@VpQYUMO."U_U'j7XFVr]T ?Pk[HDbi6$Y8)8Jm8ahPI^3]$lLeRte_fA7VA.._H-GcAtMsC%$k&Er5QY>] $eLqENb)rRA&]"L^!0p dUK!l1NUh9N\@1rS1MiGSN4r&B\Y59U38)E+C:[(=bi)ieLR?jTRY;6,f%A#^(qC%j&2:[bDN:o*thZI,HHk7`?o'WbA=$TfEnGj3&^@<MrOK8LZsF/ie %+87>agOQJcpQ-[)W?IgsXO4Yl0h;fnKaDU5oI&FdiOeC$S2=p\SPR2C.pdn M[.65Y:b",dsJQ;acF=pP P)Q=OZ3N3@kMp\GdI4a7DUF-\r=^^jJcK.V26Ul#2>=A260Y8P&,g&aYR^fIh(rV5dRt;IcInk8E\Va:++%D<+1ETI>_:#"mjF/k(SYr0 +-@.+mWLM\=p)%XBFN/#Ao5MX7>$BFYkq`<7O9[;nXPLO)Fm$h!)[O6V(/hraN_=1m4o1q6benTM+U-FWJSEtI$&UKQ69cA;Cf5qOaE\A$B$0W'ns/F1lJ3]sl"q`T#b)o6@CGfs3N+i#R@*dsA;bicGN3I`ABl0pN1[UA0HKOa(RKdS,>o`R>?r-D'hWG]iTIAA&GJ_T)!`0I$Qe9MH[]3Ar33D4nd5(g><^5 H8-U_0 5c')PJdA73oOW?I],hh3C1.m3Z?:AcWU=p&7P!<^>Es_NeEiN-!$S1=r6/4WA@`LamN!o7>Am%Z@"\fn*O8IqFGp3fr6SGN*6BC/`R?> bt\R3+3K`2"C&AbU?>pk4]+MjSTrHs(F-Y.S4[9[ZL\@$IIB[W, 5.AWBXqJ9`,9 /k2)G PXeir$/jEdp^rdN&A JfUa(;<6\4/`_^OkN91CJ*dc#bjc^31p*Idd@hkSj3)Ft^P"oI*Rf%OlZI8n):UC`R9M%Yd$>"]25-_,o9"[bNAm7!@4HeP/9@O>rR]HGHhJmqr$Wnh@:Uc6\9.bB7/-QN,3le@Zk.T"#O#;g8[lU&3J>U^G;emN)b7gHi*^i,h(^I6riL0q>V6%ON$[5 VU#k#O&KGXUBAoi":>TKBbOld8Cp7Z*QedV!)qEp;GeRmL#0L1t)Bg*SEp9ZFWDZ!pof[[tfifAtE'[_M2ODcYe8G-QP\%`JimAQM'2=bQhXtt.=]a\17:QZ]>^[KgnAgU=HPk0\Jl2\L7=c`E.=*?kij%`@&C6fFG73qHg$%KAP6r4CFOi;7G^Y`3i[2Y>Ub&rLr7mp1>Y,F"]_0G!b*/(rC$Lk5F%`'BHD%AU-s%oSq[Ti-#[&^0Hr^j4b^+d@1)J'onFnf"KL5;Ar=Eo>,"#>TGm_(Z\/M>JXZn!-i,;&[Tg\`TqnFRTTAR[7%@_C^kA_nfNXs's!f*G;-ZW=,/%mfR?p70-Q-iA`"Z4:qM0SX?tB?ao1,O%ZS4aTe4[_(P6*g&7,DPj%DKp]oDtlZn9sgcK&jaFE`TjQ[B]05&\E^n4@e*hA]ZnnhoEA.sX\MJ%aNJ]NQB3WH]`[6d!$[m X ?XZmc41Hj3A`gd\,XKf#X)oCp7pgFt*OtSUEe>SdPD`.X;b)JaNA\^n$Hqq^Mh3_r?+eHn,8$5)cDH)M-!eWgOZ(]mlh`AJ^,tDp/$$J&;pH\%^\Y[API^i+AHK/i,3?26(PW55Hd0RC0VVPF?@Af?AViM.k brkN5LA3M?g_dD+(b8.tq,2S"F* Xtj.VbXlpKtTmP,mHh`)HLeXP#tpcBeZg-K)tlqbaXl'!E9%Ejo9P?0<=T;,ANC"5Bn#^H]?-d9!Se'+mp&o6YR(m25k2Rf@`CFUD[kdAQtj'I%NmQ/`W,BFdMG;;P%XaZN@D_.TTS5KfG3W]br<.]YjY'k.V+O#[0l1O &#g6C5AM(#_I.*\F.No3^C#s6][S8\MYs[iG2I2dPPG]W5JAVklQg_EG25j7`I'(jKo'IQ?0D]L#X,pf6=-RSB9j),A@6.+@#EM(_esBY)5>PX^L]&F"fgaFS]2TBfVJ*BEc9@>K%D#:>Hk9R#n8Hj;n8F]:;Et8UD)ArC:15Q0+1snt3Dj&\P.<q6r-@S%abjA)K6qe*+\#tIlsb=DQjS=.[[OD;&k;T70#&X$'A,>W/bPTOr&dUS..Z1GQK*KA(X%%$k/md0ZmN+E21iLMiJK'GFdS'@5L5!$j!JD#hJ>9s#UsqU':$(#)!NoWq*k$=hsXj=n`,AA6AAP"]Ak*5_P>0.VRZcP.A?0]$^P.94Xps^Me753/ONH_i*`*7oG)l!g8CGG%=1-fH^BIU_t\#?Fs);Gf('Xbae<<=:l)j#h\e;rY.ZU#F!N-:o.1-<$Qk. /M!rbGAc&r%=Vj&_,i-+M-"G]fX@1Aj#j7J+$/5hfbHUOA>bmb(7]@+jYCNCg>B>9M;0#rCq5oZ]r9@hb$e$R:P"+2D,'J '"ps:gb'TGEc@'t;"4DJ^k6aM-)(E*pScW4dAq%?Yr^,[!`.FW3q?^6aF40AYUWn,GM$Q3ZN.a2Oi).1P$>s008oRAV$XmF(!X:HeF:EJ`E$tnj,RSAR(`(Z_2"=A,)WE(j65.=r-3t&6b4[>/EQ5Iii1OBA:o;''k6q3W$N"+DnJgNKN^2%:[Zk="Xpn[f@7#GLKdFi<[>ZO"Y@ 7R#Vn5DNP]kl.6?QX<]JJ>"U(G>6;TV,'>X`N/>^<6e]Y=rEG/maO*SWSH5cMYhpfT:%TC3TAgm[aO&f2R"WSX39mtB)ED:`;-;W*7?*Oa6_I0YY[HPeFAsQ'A"5s_f'H^%BUN]1f\] ?p9LX+lWWreE"PZ].Ef7Qe2P?s6-^$t&'T&[0,EaBKthk\9*AlDW$s)CS[Qlib6-r[q@UshcoJBUc7ndrtbQPM2K#CBm6SI,i&A5:]>C +4_ZC#R%:mKOq0$FmMCUeP!Hg^Jr8P:% ?e%Jq19AG.\OAbFGV*\B9Y.?j98=S=bJQVrOjV&hHGTf+kj6@%%l$El[B-U85[bg""pjC6;r4Ya[dN`#[N/$1\YfI*l:DiL%?#N`9AHh6A2rLr(Vhc$[Z*C^U?SM1I86hto\\Tb6@UsglAIo%L\"lbh>h]G8/s+4)a *4olRYgfXB,!]:BDb=DA)ICp#)6c!BZ\])'K>PAX$,'0]5^E-ZI>MGac F)Jp9mi=rhr"%n[W*BMPIHkU"_:]Y?P*\N]AfdGkR?HEoOn&Ge9)BkUjH ENcm,MV:EP?QB>0B!SCDoBWb%I[A"8A7Ii5A2A)>e;ViJ#bC1XQ.g9jqLAO$nQe'g@ISjnFkg\t\Q^EVg:e(XaU-AT2,Xe.%D-g`W$PFDP7c_C1ln8Ui]pp@U*/2)'lc3Q>J$_5Nl%.a.=1<<46LR:WBdA2ETem5-^'p[6G_n;\gN=)N@E0DP>kfn!_46eMq`2Di4(K;+1G,X*!KZ'&(Gs6IdK_c<4n)p'gP.K!hp%g2+'pAHPdX.kq4.H10aO($ns)&JtK:2?^X=L$T!nd`:oHb$,O/$PM1 hGkFY5mi"^ZHKFN<0*\0rkWB[()Fg.1'^8pd#G`sA!X'r,o0[eiF^CM%G0pmYKKHg%gIWJ I1']6cLlFKg5nW:&:ofb+Ejk&naPs3iQBTG7H`.UDg;n'<38XtqH6-NX!5rG*h`n>r@'`.c9&F"eG+A?3G![`;O%*LiB;koOJt3a,\aG9L??iGc?RF,Y9)FH 19=WQT0W_bU -:J/!3Q(R5f! gD9&5HK,$B=d)1i-#,bT9Me9+PEY4*#Lo#bK6(ADp+_8MLO0!R/esc`#W/,ksGpTGJd1k0Zl8dk"LrEPI;`VfF"&]`bl<$9A`NPBAqEV91:IH4-mH-b$?W7oHKX.07\hlj]G`&QBi 4R@+l16$ T&P7KhnF_LKNG;DtSR&ch&;j$&828OT==(BMt,/WGBil%iW*j,HZ=HRO.TSV7m`>kbWTo9P$;l#2;spkK\j>E3?h-ZpNH!:&50TC]\&0-%hiHeZf4j<39n1e_Bl^+JhkBJA? DAatMI%1rZ(YF C_c!2D+_`t+kAFF=9@S)fjBPD8L]Oj6%J"5A S`4(OidbFqk",r-O N^g9j$C7Io9^!]KZk"s:m#90bM]D5E)js"Qa9+lk'Xb+ONY=,(-1 4aA6OgC(qdOV^"N] $AhU-9&2Kd;^UM9K`7$6.W3F1Fc\sp]/%]rG-Fk-(jj1qNr,5 5QqnA]@A[Nt/&0U1?eA?A[r6&Bk3,DjS17B@g4o[6Z3lAT>PXK"MG1fl`U27L-7IRk-//*\ k+6OJC1M;X:XY?s9-VjH*AOQ%QGK#o]bm$,`hQN&$0QF_.-(2`$"cbE0jQrH7pWZ99Z#%]*s&i/ctQ?r\9K%gjYMg!ZB48"q/q+n.fW6'*`0D3]gGFQj-B2X`&e&*Md%lgf-2:>lk1AH7h5>6pL3p"PSO)^)!=/?7(S:5%fpb<.]"!frm;o5/.qtpr4G,=Et+A"-_VS:Q2Ph&A#?p*FVUi9OPj)sYJK/d#Pj6ZU =gXMCK?h$WTY:#JjN=AA]K.dZY,B;AGO56C(c'g]$P-(\/DF*X"/jl96JA+gJn>l;]RdWp6jH#pNdt'1U7^4qgNl7K#O;PA&\;1a/s*,PmG$BZj6L,5+dO^Hq($;\je4;`5`D<"Y0-[o1_6\r.AF.emOM71,=T])=4RlPMa5g6.)mheX*t6)M7cVKQ8LV!BEd$R<. h2GqHFC0Ns+s?JYeXAt"C=H(apc;]J0pAnML& $Ma55qhEp&k=:9n7mPTOA7P8rS_E%an7;M^(:aY,D`U?3YH*^Zh)^na=bkW@JOo&f?E\qNC+Z(ck7%Z/r8F]c]M/si't?:2I@;o2?FT8O1,iGhM9Lc/^EB5lUKa-Ilj_f'b?KH6U)A&A:YnG.k8;.gc#iYhU/5PKO*2CkC)A=Wm9hAF[I?7rA=J;Mjb'9n-nQ7c?_Q/$L[VOe^_q;%%t)@\A;G&r3E1-Ce6hG(sYt9)qtJhs!gjpPa5H=Y^sj`7M:3l')69]7h/>Oo !E]7oAFhAf]O h<=)V+74ipr4'OWir3bB(rp](X@B9(j>O)&UV29,=r`\E\pgD6aLVO@4]p=QrA^d"48KtpS=JAXLU'U)FVN4mQ2helEl]%kf L/aPr4R57HoT+(JOA?Of>:BQ_fEV==N#Y=D-!jeEcm"U,a7HE!AI#Ap=c=p!?jq8rl("H/m*:3iN*+YI"cm?&!;ESGIao< +`8Uj!FAiL+r+lD(oh(\G\U<-mb>Zso$QRskn#&=QLl+)M\&D,mmcP(G.V@Q&\l6]%WSNUaJ1\EV+-Mo,H)f0c<Z$>@?=/-?hU\8n T8 9o4M.!^]X%i5VV7kL[l$UT4?D!aJH!:Lp`MgXJE_2LYVSA0s%P-a0[p596d%s %V!@0t5O#e(+ `E@" X[B >tQ>ai%n/D=:Oi&@%,Va'npZ so4N$!)k,_h4mpg ClW+6jrf^rt@\7:L0AUVG6j30g+Dmda`I*AcG[r-J^]S5ER:L ([\ 'Oj^$!PT^/K%qWl&^VLV@'Zq`WcbF+tL`M E#RJfj27.I$rC_hh.W==$s>Wo^8U<`3p'\)>6#:Kmt[IS;/FA1c3MOO;15qR\k%b74fT`^j8NQ]kbs%N.5k2))oGJ]GVe\gY">Cj+cc^:RgbqaGOG7*aPjU=4I1h8%Ym&)O/^UdMO]s_i4aCp&:Z8C2`R2BDAj['ZE(bY 423me^/KaMH04tC(Q>3 V fiIpUX>EKdp_.bCc2AWW\Tk>?KA-Z&jX$iQ/*iZO#HFd1:SrVX#E[ZkG.3hbt@*r44i4&XC/K]9%?Hs3caUV+&fIqI21*h4nnW4tVD&tVK44p];U,Y;LsLM8&>4l3r.:'YiW>)q2=K^!3h9O29F_m40jW7Bi##fM1^DnJ5oWrN_O:d;&SX=e=Erqo;JHn\o9CD00qVpT4IjMA`r1')8JY,(p8d5FAb1ERtAsArdH+)1!>c/As.1Af4q,Ads//k1^V%4q1htP*"KAAU$:8Tl#Xp' SY7!a0h)GrV2.g'JmbYRLO)LRA<4b>"`LY([l!QIeWG; gd,hdog "Y`#g+M:b_O0"\.f9E"1'O*o'eML4nD@:ARo5/G>7[rpTP\i:7 tU!rb#sBA4EEN)o)Ni[ ;2/-_A>F%U)GMj c[_s18UoP6k-A-t@"aN/KX9cA'Bp'hAc3Zp'i.O(iH=o4b5JRt6&`C\RE8D<.*KA_2fRf-IR?<aDo#7oeI+ @cbq@6QnaPeG+q@RXQSS,A2]J:ce.[VMq-8H$dJ2?YPGfr,$a6gXYkkZKCoEYMCe*HFbQCgYn$GfFr6ELPGH=QF7g%p;aj)dPeUmISchF\"]6P'FAH0f7iDjao-n'[qXI"PT4la?DUfc9k?'m.-N\i_:dC6/'UfH8BSZ!rAAd/+58iD,\I;#"kZ-NoUr$*li&@'0d W'RnmA%&+R^lS]WQABo2P3P^#>;>N;G2K-fTeXB%;%8fn;A,Q%%ns?><8o *QJF]rt7:1#[loX+;0\@"RL&[*9+.d^2Oa+2cc<d?\&kY;#g&CC`ik)@6F&mP/(#7>$(O>kMPCp3&$1aAV&(-aL^I$QM6?5UnJ"@]_Vs dBbJl_681=,g7pNAcVD@6MFFR+p=Na^QKhb5" m)1P&9d](6!0QB;@ZNN"[^RIGq?dteA/H&Wg?!NmJj)n9j?;Xrn)A.G000"[?bIi982-n6rAf`gnb]Li9_pD_00p\O!VJD#RJ:SM7,.OBk$a+/%ehlgR/`-a,3Dl[6U437I(g-dFm?3a,"0WAS`MSdckj;^91A,DS_jlfSnr'NBPn9An^:<>2,tT%e2IF?MH:%T:om3@b-H's/A8hT+",Ho@<0.:MHts;XK](7P9ro#NaFHsR6n#Sgd#56*RM+t95gWAo6;/RK5Z\\kSam[(9@)/;_!H]eXco]q3+hUF Op8eZt4 `OKe+LDOF]qTMDnY9!M@Fo_i2LFLsTlnM@cqcl(t*a/Sd$Vl@8Jj;a*@diN/...8;bboWLH ";eFtsQ3!S/U;]UA_n@+n2://?H"OZg!t/8BY18p7HCLq,]h/O$M^XNV[]B$!2mKZ&Dp#0dPk1lc\9`"OC!j^ KqIoc#/s\GAfsW18)-XA8fkOT7W;_BJGar%p`pQGl->3%W;3kb`NBh;jlPKtiT?opK"Z)m#(?2jYIt;c_Gi=m)noCh3nM,MURUo'"-A@Q$E!/YanjTG)F'>lV I!6D:6iX]8;[">h:$aQZt[I8J5b5ha'':)oK';Ah",Zk)mj)$IJ]53kP\9%bPcf2q1>J q;4c/b7U 3]5<Ji*PH&"e!2&i%s,PV&:+mM&gT^osaiZ BA6 jIsjqOJs[*'2pJWZ2?!MPBB[No_QWpD*8=41&0ikriorRAi3[QaID5ki5@SIKL-P7`a h9FWc./jQndQ3gC&mb&>EHe(m;rHk*JWSC `[`6o'U#MGFW+=#%]>gYQda..\Uai?714@2"n`26b5N]AKfOa"@himgc:Cf-?$K3*Na%'2P$R)OmJ48%&[i6c?+#f4@t?A!jBGktEl?gF^"=rbPBle;s0WfFpiWKpOO;#/5`\Qnghr'\0&QMbrZYB2nrrB"E?n9@F;/:;!H:/a5`YB4"L%+ Vs)6n^F'R\fA(C^n3f:AM"`+!#Pr*!k='5ZS'<lt8a0qpkHDcUiL')5+0S6>Ka-B!S]7\]W5DnaQZLXfeT0+l:PR6l[ZhB<6p2m#$XUl4K=-00dVAat_b371"\eYVPe+kK'?gFA9T;PAG5SFqN%;Jl.&FP&G?KG?`X,hdZQr"3)D#.ZrP&"eFHP4\>,>A9e_M@,51:Oc6,Z*`m?k]Ej@9B/l1e[/NSA#/PDK`+R^Z0:[$_9=1R,$!PhSOY_#c0\<;"J$tt:>s.0Vn\L.V07Han]b4!Ti"d,M%5)AC(8JohVLR5qJkkhB 1 4h:t()$A0d4>=k`nS$<^*T`,?-#4Lb/A/HC7Jfnt$Ys;@p6%%ofb1eg1d*[Ob%,S?DP#"[2Vt3,D[A'')R>XQief!P!GT>PaSE4cD&5d2D B=1b-*9`kAinr6pYq7QA']!%JA\b;QE&-B%76m*3T 1d[lW@nf(o(264V s];P]5A=;Ad#a2BsM1>oF^A+ 0fTQg]\ofTp`<&_e[A>YYFAo7b%#?\QUVS]l^AQ7@a2>WDBm&T)[CkA)H>h7q(m4)-Ilf6Ah%*rZ&Od!"no"AFLQFg\]ODV+j+_/Y#%c7fLZHD*USnfmKn=W+J%Y>\$H]]a&eIRgLgm36@KthJp)6^6r:AcJjicCR+dJZ)8AmNFH^MkSoG9G72Wq"oRn8bM+4Sj0Drg&)b<9s>+SJ:H!+B:.R$rCl%@r*8VGd7lmX[/Bp(\nhtU9No7OG%Z.n%!t40&=RA);(h&2re#QVjaI">Ie+&DpW"%44A@l$_?P*S.q#Kp;-?\1<n0S,C+^h;RfAG;@KdcrCfFcYOl3+DW!+89kD$>`((G9c\?G(O%^A6I1(%j"6_;(h-oS05i*]PVsl!B1bGr+,#F9B"Trdq2\#rXiV>&q8BTf8)ZPl`P[0dd&chG=?GiW-LC80L`6GP8/sf:S\/7CJ_,`sU!VeToliSQ4)oN,E2CjEt96D'A'$Jf_GHlPW05caah,O.?AjL3EcW0 U7,qU-E!pKce(2/0`8"77bgBQ*"q2Gh.+[@.E"tn=X0[h%CU1g?Bk&,>2d7nS5qtU!%?b:3<7O[!Ym;Ws&F.bq$$8V/-@D38X*<\46*T VX7rg$cCG?#W9 =CEi(:AYk38OAHBbo@6gPSM\)FF29a!l6U9A9iFq..l=45o23O-Y"ql1KW?!;O=7TFBdokoT5s(XkbBoRGs7pZ[s]k;;'`i*2olK%K6=]eapN&*G/A30`..,U+_n+;Qai_1\t[4%iXHT''ABsqHAWO4c7(!sY7@DAt>rS^`LJKmC)62:KCh!L>1>M0Zplodd..Kd9 U^c=h)_c0->jP=W+9Ip=c3q]Vo93^ZMQOG:!#ikFbN[dV0*+sK]A"q^V?e2?YbA;()aF5od-c;Uj:(.d/$C=\o-lHB)4+0KiAr`>Y%A$A47US3H9Ml!/i1I=&!Gsn4T6qY/N1Qio+m$p9'F:VhR q&B>XDo6'$>e6pdh*WYB7[5`k^"HtY)0?V]2_>BWto!K599ds]mUt,1KOt=3B!lcQ'E,>I"A?O`@9qMec$5$U-5\3pE:TQ7F9+]!"p`K=ek@>,dC#O/$8BpkYbVL\*6Wi8f2o,;VLS@RHr(]NkRQnk?8IL0oKLj'*N\Vrq:AN)aZ!"i;e(D(`*F:_.$f',ZEg]NdGT*S.:A6PkGf0?/@dmLP^A) Jh3rjQ0-kZ@OA^T41[DLG)O0Jtg'A#G+c2^X>l8g]1A\lB*)c&bnG8imS[ocBS.AXL%K^ .*L2`,CUAE.'DkbK4LZ_@)4MZS:Wlk('RHFUO&WsM;tK5fL5dm<-G_tmh><M48CSG#aDd =eP*OC;Sr6-64e74'>aA/"Rn>e-@cKaUr#`D"A%Bp2)>#0 Y-=s-jr:ita j_jD`jN+i(GL@)Cm%o@Afc`c$66HAt[k5gOGJt-not a Sun product JDK and a js + * engine is not present, return an exit code of 2 to indicate that + * the jrunscript tests which assume a js engine can be vacuously + * passed. + */ +public class CheckEngine { + public static void main(String... args) { + int exitCode = 0; + ScriptEngine engine = + (new ScriptEngineManager()).getEngineByName("js"); + + if (engine == null && + !(System.getProperty("java.runtime.name").startsWith("Java(TM)"))) { + exitCode = 2; + } + + System.exit(exitCode); + } +} diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/common.sh --- a/jdk/test/sun/tools/jrunscript/common.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/common.sh Fri May 30 00:00:00 2008 +0200 @@ -52,4 +52,5 @@ JRUNSCRIPT="${TESTJAVA}/bin/jrunscript" JAVAC="${TESTJAVA}/bin/javac" + JAVA="${TESTJAVA}/bin/java" } diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscript-DTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-DTest.sh # @summary Test that output of 'jrunscript -D' . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi # test whether value specifieD by -D option is passed # to script as java.lang.System property. sysProps is diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscript-argsTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-argsTest.sh # @summary Test passing of script arguments from command line . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi # we check whether "excess" args are passed as script arguments diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscript-cpTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-cpTest.sh # @summary Test -cp option to set classpath . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f Hello.class ${JAVAC} ${TESTSRC}/Hello.java -d . diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscript-eTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-eTest.sh # @summary Test that output of 'jrunscript -e' matches the dash-e.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscript-eTest.out 2>/dev/null ${JRUNSCRIPT} -e "println('hello')" > jrunscript-eTest.out 2>&1 diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscript-fTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscript-fTest.sh # @summary Test that output of 'jrunscript -f' matches the dash-f.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscript-fTest.out 2>/dev/null ${JRUNSCRIPT} -f ${TESTSRC}/hello.js > jrunscript-fTest.out 2>&1 diff -r 66af07c1f52a -r a6a6e9c3d502 jdk/test/sun/tools/jrunscript/jrunscriptTest.sh --- a/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh Fri Apr 11 00:00:00 2008 +0200 +++ b/jdk/test/sun/tools/jrunscript/jrunscriptTest.sh Fri May 30 00:00:00 2008 +0200 @@ -25,13 +25,19 @@ # @test -# @bug 6265810 +# @bug 6265810 6705893 +# @build CheckEngine # @run shell jrunscriptTest.sh # @summary Test that output of 'jrunscript' interactive matches the repl.out file . ${TESTSRC-.}/common.sh setup +${JAVA} -cp ${TESTCLASSES} CheckEngine +if [ $? -eq 2 ]; then + echo "No js engine found and engine not required; test vacuously passes." + exit 0 +fi rm -f jrunscriptTest.out 2>/dev/null ${JRUNSCRIPT} > jrunscriptTest.out 2>&1 < Foo.java + $TESTJAVA/bin/javac Foo.java + if [ $? -ne 0 ]; then + printf "Error: compilation of Foo.java failed\n" + exit 1 + fi + printf "Main-Class: Bar\n" > manifest + $TESTJAVA/bin/jar -cvfm some.jar manifest Foo.class + if [ ! -f some.jar ]; then + printf "Error: did not find some.jar\n" + exit 1 + fi + + # test with -jar + mess="`$TESTJAVA/bin/java -jar some.jar 2>&1 1>/dev/null`" + echo $mess | grep 'Bar' 2>&1 > /dev/null + if [ $? -ne 0 ]; then + printf "Error: did not find main class missing message\n" + exit 1 + fi + + # test with a non-existent class using classpath + mess="`$TESTJAVA/bin/java -cp some.jar Bar 2>&1 1>/dev/null`" + echo $mess | grep 'Bar' 2>&1 > /dev/null + if [ $? -ne 0 ]; then + printf "Error: did not find main class missing message\n" + exit 1 + fi + + # cleanup + rm -f some.jar Foo.* manifest +} # # Main processing: @@ -116,6 +153,7 @@ TestCP javac -classpath TestXUsage TestHelp +TestMissingMainClass # # Tests for 6214916