pax_global_header00006660000000000000000000000064117162640260014517gustar00rootroot0000000000000052 comment=59b087ee42fcf471fc571fa26d4d60b4955572e0 apq-3.2.0/000077500000000000000000000000001171626402600123025ustar00rootroot00000000000000apq-3.2.0/COPYING000066400000000000000000000020411171626402600133320ustar00rootroot00000000000000This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if other files instantiate generics from this unit, or you link this unit with other files to produce an executable, this unit does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Public License. apq-3.2.0/GPL000066400000000000000000000431311171626402600126510ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. apq-3.2.0/HISTORY000066400000000000000000000152271171626402600133750ustar00rootroot00000000000000Marcelo C. de Freitas marcelo@kow.com.br Warren W. Gay VE3WWG ve3wwg@cogeco.ca With valuable contributions from: Daniel Norte de Moraes danielcheagle@gmail.com APQ REVISION HISTORY: ===================== APQ 3.2 - Build system revisited again and unified with the rest of the framework APQ 3.1 - Build system revisited APQ 3.0 - Project maintainer is Marcelo C. de Freitas now. - Modular design, which allows compilation of independent parts. - Code clean up. - APQ_Boolean is now always treated as INTEGER ( 0 = FALSE, 1 = TRUE ) - FreeTDS compatibility - A more generic ct_lib support (works for SQL Server and should for Sybase too) - Error messages has been organized. APQ 2.2 - Added Sybase support. - Exceptions provide informative messages - Documented Set_Port for UNIX (local) connections - Begin_Work, Commit_Work, Rollback_Work now implicitly call Clear on the Query_Type object, before and after. - Set_DB_Name when called when connected, now changes the currently used database. - Instance and Set_Instance primitives for databases like Sybase, that choose parameter sets. - Case policy support for universal SQL code. - Value function returning string now always trims trailing blanks. - Sybase Support Introduces: - Cursor support is now included in APQ for databases capable of supporting it in the client library (Sybase) - PostgresSQL changes: - Defaults to Set_Port(C,5432) - MySQL changes: - Now raises Use_Error if database selection fails (used to raise Failed). - Bug fix for Reset of connection. - Fixed MySQL support of BIT type - Accomodated MySQL date format change APQ 2.1 - This was the win32 port. A number of changes were made to the build scripts to make this possible. - Now under UNIX/Linux and Win32, it is no longer to specify linker library arguments, such as -lapq -lpq etc. This is now handled by the GNAT pragma Linker_Options() directive. - win32_test.adb program was added. This also happens to work fine under UNIX/Linux, but was created as a simple test for win32. APQ 2.0 - This was an extensive release and included many changes. The primary change was to include the support for the MySQL database in addition to PostgreSQL. Now APQ is structured so that one or the other, or both may be supported depending upon the user's own situation. For example, it is now possible to build APQ for MySQL only support. - Generic database support is now available. Through careful use of the APQ top level package and functions, it is now possible to write database code that does not care which database engine is being used. See the chapter "Generic Database Programming" in the APQ manual for more about this. - Many other smaller changes were made that are documented in the manual. One major change was the renaming of types from PG_Boolean to APQ_Boolean (for example). Also PG_Oid has now been renamed Row_ID_Type. Package APQ.PostgreSQL still maintains subtype definitions of the original type names, but the application designer is encouraged to change to the new names as soon as practical. The support for the PG_ names will be dropped in a future release. APQ 1.93 - Changed the package hierarchy to place all PostgreSQL packages under the new top level package APQ. This is to pave the way for future support of other databases, such as MySQL. APQ 1.92 - Fixed bug for floating point and fixed point types (was rounding the value to the nearest integer, due to the fact that the Ada.Text_IO.Float_IO.Put call was receiving the argument Aft => 0). Omitting the Aft parameter causes the value to be formatted as required for the SQL floating/fixed point type. The bug was reported by Charles Darcy . APQ 1.91 -------- - Connect now issues a SET DATESTYLE TO ISO command automatically to assure override of the PGDATESTYLE environment variable, that may choose a different format. APQ applications must however use ISO date formats in order for the APQ date support to function correctly. - ADA_INCLUDE_PATH=. ADA_OBJECTS_PATH=. is now in the make file prior to gnatmake to cause the build to ignore any possible prior installed version of APQ. - Added ./win32 subdirectory, to allow building APQ in a win32 environment. APQ 1.9 ------- - Fixes a compile error that occurs with the newer versions of gcc like gcc (GCC) 3.1.1, and probably > gnat 3.12 versions of GNAT. The problem occurs when Ada.Text_IO.Integer_IO is instantiated within functions/procedures with the same name (like INTIO), provoking duplicate symbol errors in the assembler. A work-around has been provided by giving the instantiations unique names. APQ 1.8 ------- - Added info functions Host_Name, Port, User, Password, and Options for database connections. - Added a new Connect primitive to allow cloning an existing connection. APQ 1.7 ------- - Added Open_DB_Trace and Close_DB_Trace procedures 4 levels of trace : - Trace_None - Trace_libpq (libpq trace information only) - Trace_APQ (SQL query trace information only) - Trace_Full (both Trace_libpq and Trace_APQ) - Trace_APQ output can be fed to psql as straight SQL for testing purposes APQ 1.6 ------- - Added Set_Rollback_On_Finalize control primitive to the Connection_Type object. - Added Will_Rollback_On_Finalize query primitive to the Connection_Type object. - Expanded troubleshooting chapter about transactions when programs terminate. APQ 1.5 ------- - Fixed Append_Date, Append_Time, and Append_Timestamp to put surrounding quotes (') around the value. - Added troubleshooting info about failed time values. APQ 1.4 ------- - Added Generic_Command_Oid for strong type use of PG_Oid - Added Generic_Blob_Open for strong type use of PG_Oid - Added Generic_Blob_Oid for strong type use of PG_Oid - Added Generic_Blob_Unlink for strong type use of PG_Oid - Added Generic_Blob_Import for strong type use of PG_Oid - Added Generic_Blob_Export for strong type use of PG_Oid APQ 1.3 ------- - Removed two debugging Put_Line calls that should not have been part of the final release. - Added a few pragma Inline statements to the spec. APQ 1.2 ------- - Buffered I/O for blobs giving a major performance boost - Blob_Flush procedure added - End_of_Blob function added - Fixed error recovery in Blob_Create - Manual enhancements, including expanded troubleshooting section. $Source: /cvsroot/apq/apq/HISTORY,v $ apq-3.2.0/INSTALL000066400000000000000000000002771171626402600133410ustar00rootroot00000000000000This is a simple installation instructions file. The installation is the all-known basic ./configure && make all install Please read the configure file for more information on options ' apq-3.2.0/Makefile000066400000000000000000000005331171626402600137430ustar00rootroot00000000000000# Makefile for the KOW Generic Library Framework # # @author Marcelo Coraça de Freitas # # # Please, read Makefile.include for more information all: ./scripts/build.sh install: ./scripts/install.sh uninstall: ./scripts/uninstall.sh clean: ./scripts/clean.sh distclean: @-${MAKE} clean @-${MAKE} -C samples clean apq-3.2.0/README000066400000000000000000000144621171626402600131710ustar00rootroot00000000000000$Id: README,v 1.19 2004/10/07 03:35:27 wwg Exp $ =========================================================================== = APQ Version 3.0 = =========================================================================== = The APQ Ada95 Database Library = = = = This package has the commmon part for all the APQ drivers available. = = In order to connect to a database, you'll have to download and install = = one of the database bindings being: = = * MySQL :: apq-mysql package = = * PostgreSQL :: apq-postgresql package = = * Ms. SQL Server/Sybase :: apq-ct_lib package = = * Sybase (more specialized) :: apq-sybase = = = = Authors: = = Warren W. Gay VE3WWG = = http://home.cogeco.ca/~ve3wwg = = Marcelo C. de Freitas = =========================================================================== Why use APQ over other products? APQ Features: ------------- - It is a thick binding, making it natural for Ada programmers. - It is very simple to use, making programming easy. - Can be used with strong Ada types. - Generic procedure and function support for strong types. - Supports multiple database engines generically - MySQL supported as of APQ-2.0 - Sybase supported as of APQ-2.2 - Database neutral code is possible (portable) - Full BLOB support (for PostgreSQL) - Blob I/O is performed through Ada95 stream I/O. - High performance blob I/O through buffered stream I/O - Optionally blob I/O can be unbuffered. - Native binding (no ODBC muss or fuss!) - Full support for NULL values. - Additional support for DATE, TIME and TIMESTAMP data types. - Some support for TIMEZONE types (PostgreSQL) - Supports bit string types (PostgreSQL) - Leaves the SQL in human readable form - 4 levels of tracing for application debugging - Trace_None (no tracing) - Trace_DB (C library trace information only) - Trace_APQ (SQL query trace information only) - Trace_Full (both Trace_DB and Trace_APQ) - Trace_APQ output can be fed as SQL text for testing - Non restritive license : - MGPL (GNAT Modified GNU Public License) - Extensive manual, with examples for nearly every function. - notice while the manual hasn't been update for a while, it's still a great source of information. - Manual includes a chapter on generic database programming. - Experimental support of the Decimal_Type package (using decimal routines used internally by the PostgreSQL database engine). - Under active development and use Design Goals: ------------- The main design goals for the APQ binding development were: - simple to use - easy to read - reliable - database vendor neutral (generic database programming) - at the user's option, strongly typed - strong blob support - No C language interfaces or types - good documentation It is the authors' belief that these goals have been suitably met, although the package is still undergoing active research. Excluding blob support, there are only 2 tagged object types that the programmer must become familiar with. These objects include Finalization and nicely clean up after themselves. Blob support adds one more tagged object that the programmer can interact with. 1. The Connection_Type object for database connections 2. The Query_Type object for SQL interactions with server 3. The Blob_Type type for Blob I/O and operations Having few objects reduces the learning curve substantially. A large number of functions and procedures are overloaded -- reusing the same name. This also reduces the learning curve, since the remaining differences are only in the involved data types. Much complexity is hidden within the state driven objects. The APQ binding allows the Ada95 programmer to interface with blobs using stream I/O. This preserves the Ada advantage for strong type checking while making it simple for the programmer to perform I/O. As of APQ 1.2, the blob I/O is buffered, giving the stream I/O for blobs a major performance boost. No longer will the programmer need to search for performance work-arounds for blob operations. Version 2.2 of APQ brings Sybase into the fold of supported databases. This is particularly useful now that Sybase has generously made their ASE-12.5x Express edition of their server available to developers for free. Version 3.0 provides full compatibility with the FreeTDS library, thus providing Microsoft SQL Server support in adition to the already existing Sybase support. Trial Programs: --------------- In the 3.0 the old trial programs has been removed from the distribution. However, there are some examples in the "samples" folder for testing some of the features (but not all of them). If you'd like to help, providing such tests would be agreat place to start. Platforms: ---------- These are the platforms where we've been sucessful in compilling and using APQ so far: OS: Linux Kernel 2.6 Windows 2k, 2k3, XP and Vista Compiler: GNAT 3.14p GNAT GCC 4.2 and 4.3 Database Servers: PostgreSQL 7.3.5 MySQL 4.0.14 and 5.0.76 Sybase ASE 12.52 Microsoft SQL Server 2005 While not yet tested on all platforms, this package will likely port well for must UNIX platforms, including: - FreeBSD (untested) - NetBSD (untested) - OpenBSD (untested) - HP-UX 10.2 or higher (untested) - Sun Solaris (untested) Win32 Builds: ------------- Win32 builds are now possible. See the pdf document named win32.pdf for instructions on how to build APQ from sources. Feedback: --------- Please feedback suggestion and bugs to the project homepage: http://framework.kow.com.br When reporing bugs please provide also: . Database server with version . OS with version . Ada compiler with version Thank-you for downloading and using APQ. See file HISTORY for revision history - End - apq-3.2.0/configure000077500000000000000000000056471171626402600142250ustar00rootroot00000000000000#!/usr/bin/env bash # Main configuration file for KOW framework projects # # @author Marcelo C. de Freitas source scripts/buildutil.sh ################### # Default Options # ################### enable_debug="false"; enable_static="true"; enable_relocatable="true"; include_files=src/* work_path="$PWD/work" prefix=$(dirname `which gnatls`) prefix=$(dirname $prefix) version=$(cat version) processors=2 GPRBUILD="gprbuild" if [[ $OS -eq "" ]] then OS="GNU/Linux" fi ########################### # Command Line Parameters # ########################### # Setup build environment for i in $@ do option=`echo $i | cut -d= -f1` value=`echo $i | cut -d= -f2` case $option in --prefix ) prefix="$value";; --enable-debug ) enable_debug="true";; --disable-static ) enable_static="false";; --disable-relocatable ) enable_relocatable="false";; --os ) OS="$value";; --work-path ) work_path="$value";; --gprbuild ) GPRBUILD="$value";; --gprbuild-params ) gprbuild_params="$value";; --processors ) processors=$value;; esac done ######################### # Initial configuration # ######################### check_in_path gprbuild check_in_path gnatprep init_configuration init_gnatprep ########################### # Run local configuration # ########################### if [[ -x configure.local ]] then source configure.local fi ####################### # Include Files Setup # ####################### echo "Copying source files" source_destination="$work_path/src/$project" mkdir -p $source_destination for i in $include_files do cpu "$i" $source_destination done ############# # GPR Files # ############# echo "Copying standard project files" gpr_destination="$work_path/lib/gnat" mkdir -p "$gpr_destination" for i in gnat/*.gpr do if [[ -f $i ]] then cpu $i $gpr_destination fi done echo "Preparing def file.." set_gnatprep version $version set_gnatprep prefix "$prefix" set_gnatprep project "$project" for i in gnat/*.gpr.in do if [[ -f $i ]] then fname=$(basename "$i" .in) destination="$gpr_destination/$fname" gnatprep "$i" "$destination" gnatprep.def fi done ####################################### # Store the usual configuration flags # ####################################### set_configuration prefix "$prefix" set_configuration enable_debug $enable_debug set_configuration enable_static $enable_static set_configuration enable_relocatable $enable_relocatable set_configuration OS "$OS" set_configuration include_files "$include_files" set_configuration version "$version" set_configuration work_path "$work_path" set_configuration GPRBUILD "$GPRBUILD" set_configuration gprbuild_params "$gprbuild_params" set_configuration processors $processors set_configuration project "$project" echo echo "################################################" echo "# This is the build environment you did setup: #" echo "################################################" cat_configuration apq-3.2.0/configure.local000077500000000000000000000002001171626402600152720ustar00rootroot00000000000000#!/usr/bin/env bash # # Local configuration file for KOW Lib project="apq" set_configuration APQ_EXTERNALLY_BUILT "false" apq-3.2.0/gnat/000077500000000000000000000000001171626402600132335ustar00rootroot00000000000000apq-3.2.0/gnat/apq.gpr.in000066400000000000000000000027751171626402600151460ustar00rootroot00000000000000-- Build file for APQ. -- -- author Marcelo Coraça de Freitas -- -- Repository information: -- $Date$ -- $Revision$ -- $Author$ project APQ is ----------------------- -- Type declarations -- ----------------------- type True_False is ( "true", "false" ); type Supported_OS is ("Windows_NT", "GNU/Linux", "Darwin" ); -------------------- -- Main Variables -- -------------------- version := $version; OS : Supported_OS := external( "OS", "GNU/Linux" ); Debug : True_False := external( "DEBUG", "false" ); ---------------- -- Parameters -- ---------------- for Library_Name use $project; for Source_Dirs use ( "../../src/" & Project'Library_Name & "/" ); for Library_kind use external( "LIBRARY_KIND", "static" ); case Debug is when "true" => for Library_Dir use "../" & Project'Library_Name & "-debug/" & Project'Library_Kind; when "false" => for Library_Dir use "../" & Project'Library_name & "/" & Project'Library_Kind; end case; for Object_Dir use Project'Library_Dir & "/objects/"; for Library_Version use "lib" & Project'Library_Name & ".so." & Version; for Externally_Built use External( "APQ_EXTERNALLY_BUILT", "true" ); ---------------------- -- Compiler Package -- ---------------------- package Compiler is case Debug is when "true" => for Default_Switches ("ada") use ("-O2", "-gnat05", "-fPIC", "-g"); when "false" => for Default_Switches ("ada") use ("-O2", "-gnat05", "-fPIC" ); end case; end Compiler; end APQ; apq-3.2.0/gpr/000077500000000000000000000000001171626402600130725ustar00rootroot00000000000000apq-3.2.0/gpr/.keep000066400000000000000000000000001171626402600140050ustar00rootroot00000000000000apq-3.2.0/gpr/apq.gpr.in000066400000000000000000000163121171626402600147750ustar00rootroot00000000000000---- author Daniel Norte de Moraes ---- tested in Debian Sid, Gcc 4.6 , gnat 4.6 , gprbuild 2011-1 :-) ---- ---- this project file permit "simultaneously" : ---- choose compile with (static or shared) and ( normal or debug) and (system operations) libs. -- -- this permit cross-compiling too :-) ---- ---- IMPORTANT!!! You Can hit and compile you program just passing for your -- program project file these three(3) environment variables: -- "Static_Or_Dynamic" , "Os" and "Debug_information". this is made -- by the "-Xvariable=value" (without double quotes) -- eg: if your program import apq.gpr in your my_program.gpr made -- -- gnatmake -Pmy_program.gpr -Xstatic_or_dynamic=dynamic -XOs=mswindows -Xdebug_information=yes -- -- to compile your program with lib shared+debug+mswindows. if the combination -- don't exist, usually the compiler/linker will hit -- a error message. these combination was determined by the time the libs was compiled and installed. -- of course you can use "gprbuild" instead of gnatmake :-) -- the gpr file will take care for you where are the libs. ---- You will need however, in system specific manner, a way for ---- your program using the libs "as being run/executing" locate the libs for him :-) ---- We just (just? ;-) take care of _compilation_ :-) ---- p.s.: You can use gnat-gps. gnat-gps will permit you choose in a Gui , the enviroment variables on-the-fly :-) and if you already have a cross-compiling enviroment, this permit cross-compiling,too. :-) ---- Enjoy!!! :-) -- You can need set ADA_PROJECT_PATH project Apq is ----------------------- -- type declarations -- ----------------------- prefix := $prefix ; type Static_Or_Dynamic_Type is ("dynamic", "static", "relocatable" ); type Debug_information_Type is ("yes", "no"); type Os_Type is ("other", "mswindows", "linux" , "darwin" , "bsd" ); -- Static_Or_Dynamic : Static_Or_Dynamic_Type := external ("static_or_dynamic", "static"); Os : Os_Type := external ("os", "linux"); Debug_information : Debug_information_Type := external ("debug_information", "no"); -- Debug := ""; Debug_option_list_builder := (); -- null string_list Debug_option_list_compiler := (); -- null string_list case debug_information is when "yes" => Debug := Debug & "debug"; case os is when "other" => -- :0} Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) when "mswindows" => Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) when "linux" => Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) when "darwin" => Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) when "bsd" => Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) when others => ---- :0] Debug_option_list_builder := Debug_option_list_builder & ( "-g" ); Debug_option_list_compiler := Debug_option_list_compiler & ("-fstack-check", "-gnata" , "-gnato" , "-gnatE" ); -- fixme , if necessary :-) end case; -- end yes/os when "no" => Debug := Debug & ""; case os is when "other" => -- :0} Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () when "mswindows" => Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () when "linux" => Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () when "darwin" => Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () when "bsd" => Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () when others => -- :0] Debug_option_list_builder := Debug_option_list_builder & ( ); Debug_option_list_compiler := Debug_option_list_compiler & ( ); -- fixme , if necessary :-) --> insert some thing making sense in string_list form -> () end case; -- end no/os when others => null; end case; -- end Debug_information for Languages use ("Ada"); for Source_Dirs use () & ( prefix & "/include/apq" ) ; for Library_Name use "apq" ; case debug_information is when "yes" => case static_or_dynamic is when "dynamic" | "relocatable" => for Library_Dir use "" & prefix & "/lib/apq/" & Os & "/shared/debug/" ; for Library_ALI_Dir use "" & prefix & "/lib/apq/" & Os & "/shared/debug/ali/" ; when "static" => for Library_Dir use "" & prefix & "/lib/apq/" & Os & "/static/debug/" ; for Library_ALI_Dir use "" & prefix & "/lib/apq/" & Os & "/static/debug/ali/" ; end case; when "no" => case static_or_dynamic is when "dynamic" | "relocatable" => for Library_Dir use "" & prefix & "/lib/apq/" & Os & "/shared/" ; for Library_ALI_Dir use "" & prefix & "/lib/apq/" & Os & "/shared/ali/" ; when "static" => for Library_Dir use "" & prefix & "/lib/apq/" & Os & "/static/" ; for Library_ALI_Dir use "" & prefix & "/lib/apq/" & Os & "/static/ali/" ; end case; end case; for Library_Kind use Static_Or_Dynamic; for Externally_Built use "true"; package Compiler is for Default_Switches ("ada") use ("-O2", "-gnat05", "-gnatn" , "-fPIC" ) & Debug_option_list_compiler ; end Compiler; package Builder is for Default_Switches ("ada") use ("-O2", "-gnat05", "-gnatn" , "-fPIC") & Debug_option_list_builder ; end Builder; end Apq; apq-3.2.0/gpr/readme.txt000066400000000000000000000001051171626402600150640ustar00rootroot00000000000000the arquives here is for use only in the install part. []'s Dani :-) apq-3.2.0/legacy/000077500000000000000000000000001171626402600135465ustar00rootroot00000000000000apq-3.2.0/legacy/APQ_VERSION000066400000000000000000000000041171626402600153110ustar00rootroot000000000000002.2 apq-3.2.0/legacy/GPL.txt000066400000000000000000000431311171626402600147330ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. apq-3.2.0/legacy/INSTALL000066400000000000000000000115071171626402600146030ustar00rootroot00000000000000$Id: INSTALL,v 1.4 2003/09/08 01:33:08 wwg Exp $ Warren W. Gay VE3WWG THE QUICK 'N EASY INSTALL GUIDE THIS DOCUMENT ASSUMES: ---------------------- - you are compiling for UNIX/Linux platform - you are using GNAT as the Ada compiler - you are using gcc as the C compiler - that you have ADA_INCLUDE_PATH defined and exported - that you have ADA_OBJECTS_PATH defined and exported - that you have a suitably modern version of PostgreSQL and/or.. MySQL database installed - that the C library libpq is available (if using PostgreSQL) - that the C library libmysql is available (if using MySQL) NOTES ABOUT OPTIMIZATION: ------------------------- - The Makefile that is shipped to you should have a parameter OPTZ=-O0 set (if not, then you should set it to that). - GNAT 3.14p seems to have difficulty when the optimization level is raised beyond this. If using a newer compiler, you may want to try OPTZ=-O1 (test using the ./eg example build) USERS WITH PRIOR VERSIONS OF APQ INSTALLED ------------------------------------------ You should either remove the references to the original APQ directories (source and library), or eliminate them prior to installing this version. APQ Versions 1.92 and prior: Remove all: postgresql*.ad[sb] package spec and bodies postgresql*.ali and .o files libapq.a file APQ Version 1.93 and later: Remove all: apq*.ad[sb] package spec and bodies apq*.ali and .o files libapq.a file If you have the original source distribution, you may do a 'make uninstall', provided that you choose the correct directory to uninstall from. INSTALLING APQ FOR THE FIRST TIME: ---------------------------------- 1. Make sure your PATH gives access to all database tools of interest (eg. PostgreSQL and MySQL) 2. ./configure (This creates Makeincl file) 3. make 4. make install (as root, if necessary) Account root is NOT needed if your ADA_*_PATH directory(ies) are directories that you have permissions on (you can delete and create entries in those directories). TO REBUILD: 1. make uninstall 2. make clobber 3. Repeat the above steps MAKE ERROR? $ make Makefile:7: Makeincl: No such file or directory make: *** No rule to make target `Makeincl'. Stop. This indicates a ./configure needs to be run. CUSTOM INSTALLS: ---------------- By default, APQ tries to compile for every database supported that you have installed. The configure script obtains configuration information from pg_config for PostgreSQL, and mysql_config for MySQL. These tools must be on your search PATH for this to work obviously. WHAT IF I WANT TO DISABLE SUPPORT? If you have both PostgreSQL and MySQL databases installed, but one of them is giving you grief and you want to bypass support for it (without uninstalling it), this is possible. See below. BUILDING WITHOUT POSTGRESQL: 1. make clobber (If necessary) 2. HAVE_PG=0 ./configure 3. make BUILDING WITHOUT MYSQL: 1. make clobber (If necessary) 2. HAVE_MY=0 ./configure 3. make TESTING THE APQ BINDING: ------------------------ *** WARNING *** THESE TESTS CREATE AND DROP THE FOLLOWING DATABASE NAMES: apq_pg in PostgreSQL apq_my in MySQL IF YOU ALREADY HAVE DATABASES NAMED AS ABOVE, DO NOT RUN THE TESTS AS THEY ARE! *** END WARNING *** 1. cd ./eg2 (This tests MySQL and/or PostgreSQL) 2. make clobber 3. make create_pg (PostgreSQL) or make create_my (MySQL) 4. make check_pg (PostgreSQL) or make check_my (MySQL) 5. make release_pg (PostgreSQL) or make release_my (MySQL) The test program may report some problems about your /etc/passwd and/or /etc/group files. You should follow up on any of these error reports. DISCLAIMER: Note however, this example program by no means represents a complete check of your /etc/passwd and /etc/group files however! It merely serves as an example framework. POSTGRESQL ONLY TEST: --------------------- *** WARNING *** THESE TESTS CREATE AND DROP THE FOLLOWING DATABASE NAME: apq_pg IF YOU ALREADY HAVE DATABASES NAMED AS ABOVE, DO NOT RUN THE TESTS AS THEY ARE! *** END WARNING *** 1. cd ./eg (change to test directory) 2. make (compile test sources) 3. make create (create & load database apq_eg) 4. make test (run tests on tables in apq_eg) 5. make release (discard the apq_eg database) The test program may report some problems about your /etc/passwd and/or /etc/group files. You should follow up on any of these error reports. DISCLAIMER: Note however, this example program by no means represents a complete check of your /etc/passwd and /etc/group files however! It merely serves as an example framework. $Source: /cvsroot/apq/apq/INSTALL,v $ apq-3.2.0/legacy/Makefile000066400000000000000000000105331171626402600152100ustar00rootroot00000000000000# $Id: Makefile,v 1.68 2008/02/06 19:43:52 eveogro Exp $ # Warren W. Gay VE3WWG # # Licensed under the ACL (Ada Community License) # or GPL2 : include Makeincl DISTDIR=apq-$(VERSION) DISTFILE=apq-$(VERSION).tar.gz #DBG=-g OPTZ=-O0 CC=gcc ZOPTS=$(DBG) $(OPTZ) COPTS=-Wall $(ZOPTS) AOPTS=-gnata -gnatf -gnato -gnatwp $(ZOPTS) .c.o: $(CC) -c $(COPTS) $(ZOPTS) $(PG_INCL) $(MY_INCL) $< -o $*.o all: sybase$(HAVE_SY) setup$(HAVE_MY) mysql$(HAVE_MY) postgresql$(HAVE_PG) libapq.a finish tmysql:: rm -f tmysql mysql.trc gnatmake -gnatf tmysql setup0: # MySQL support is not being included sybase0: # Sybase support is not being included mysql0: # MySQL support is not being included postgresql0: # PostgreSQL is not being included apq-sybase.ads: apq-sybase.ads-in sybase_gentyp.c prep_sybase $(CC) $(COPTS) $(SY_INCL) sybase_gentyp.c -o sybase_gentyp $(CC) $(COPTS) $(SY_INCL) sybaseopts.c -o sybaseopts ./sybaseopts >sybopts.tmp ./sybase_gentyp | ./prep_sybase "$(SY_LIBS)" >apq-sybase.ads rm -f sybase_gentyp c_sybase.o: c_sybase.c $(CC) -c $(COPTS) $(ZOPTS) $(SY_INCL) $< -o c_sybase.o sybase1: apq-sybase.ads c_sybase.o gnatmake -c $(AOPTS) comp_sybase setup1: mysql_xcr mysql_xcr2 mysql_xcr3 mysql_incl chmod u+x mysql_xcr mysql_xcr2 mysql_xcr3 mysql_incl mysql_xty mysql_linker_options mysql1: apq-mysql.ads c_mysql.o gnatmake -c $(AOPTS) comp_mysql c_mysql.o: c_mysql.c $(CC) -c $(COPTS) $(ZOPTS) $(MY_INCL) c_mysql.c -o c_mysql.o apq-mysql.ads: apq-mysql.ads-in mysql_generr.c mysql_xcr2 mysql_xcr3 @rm -f mysql_errmsg.h mysql_generr ./mysql_xcr >mysql_errmsg.h ./mysql_xty >mysql_type_codes.h $(CC) $(COPTS) $(MY_INCL) mysql_generr.c -o mysql_generr $(CC) $(COPTS) $(MY_INCL) mysql_gentyp.c -o mysql_gentyp $(CC) $(COPTS) $(MY_INCL) mysqlopts.c -o mysql_opts ./mysql_opts >opts.tmp ./mysql_generr | sort -k1,1n | ./mysql_xcr2 >gen.tmp ./mysql_gentyp | sort -k1,1n | ./mysql_xcr3 rm -f mysql_generr mysql_errmsg.h mysql_gentyp mysql_type_codes.h gen.tmp opts.tmp mysql_opts gen.tmp postgresql1: numeric.o notices.o gnatmake -c $(AOPTS) comp_pg libapq.a:: @rm -f libapq.a ar cr libapq.a apq.o $(PG_OBJS) $(MY_OBJS) $(SY_OBJS) ar tv libapq.a finish: @echo "--" @echo "Now do 'make install' to install the library" @echo @echo "NOTE: Remove any prior versions of the APQ library" @echo "and package, if you have it installed. You will" @echo "need to remove those packages and libraries" @echo "manually." @echo @echo "You may 'make uninstall' if you are about to" @echo "reinstall APQ version $(VERSION). This will not" @echo "work for prior versions of APQ however." @echo install: libapq.a HAVE_PG=$(HAVE_PG) HAVE_MY=$(HAVE_MY) HAVE_SY=$(HAVE_SY) ./install_lib @echo "--" @echo "For fun do:" @echo " 1. cd ./eg2" @echo " 2. make" @echo " 3. follow instructions given." @echo "--" uninstall: HAVE_PG=1 HAVE_MY=1 HAVE_SY=1 ./install_lib uninstall reinstall: uninstall clobber all install clean: rm -f *.o *.ali *.core b~*.ad[sb] errs.t libapq.a mysql.trc comp_pg comp_mysql rm -f sybase_gentyp gen.tmp sybopts.tmp sybaseopts rm -f mysql_gentyp mysql_opts opts.tmp (cd sybase ; make clean) clobber: clean rm -f mysql_errmsg.h mysql_type_codes.h mysql_generr Makeincl tmysql apq-mysql.ads rm -f tsybase apq-sybase.ads rm -f libapq.a GNUmakefile rm -fr ./release $(DISTFILE) cd ./eg; $(MAKE) clobber rm -f apq-1.93-win32-2.7.1.tar.gz rm -f apq_manual.dvi apq_manual.pdf binding2.aux binding2.toc binding2.log (cd sybase ; make clobber) manual: apq_manual.pdf apq_manual.dvi: binding2.tex @rm -f binding2.toc binding2.log binding2.dvi binding2.aux latex binding2.tex latex binding2.tex latex binding2.tex mv binding2.dvi apq_manual.dvi apq_manual.pdf: apq_manual.dvi dvipdf apq_manual.dvi apq_manual.pdf manlabels: sed sybopts.tmp ./sybase_gentyp | ./prep_sybase win32 >apq-sybase.ads rm -f sybase_gentyp c_sybase.obj: c_sybase.c cl -c $(SY_INCL) $(CLOPTS) -MD c_sybase.c -o c_sybase.obj sydll1: @if [ ! -f apq_syadapter.dll ] ; then echo "You need to download apq_syadapter.dll" >/dev/tty; false; fi sydll0: apq_syadapter.dll apq_syadapter.exp: c_sybase.obj lib -nologo -machine:i386 -out:apq_syadapter.lib c_sybase.obj apq_syadapter.lib: apq_syadapter.exp apq_syadapter.dll: apq_syadapter.exp apq_syadapter.lib c_sybase.obj link -nologo -machine:i386 -entry:DllMain@12 -dll -out:apq_syadapter.dll c_sybase.obj $(SY_WIMP) sybase1: apq-sybase.ads c_sybase.obj sydll$(MSTOOLS) $(GNATMAKE) -c $(AOPTS) comp_sybase dll2def apq_syadapter.dll >dll.def dlltool --def dll.def --dllname apq_syadapter.dll --output-lib libsybase.a @rm -fr ./sybase.d dll.def mkdir -p ./sybase.d ( cd ./sybase.d && $(AR) x ../libsybase.a && for f in *.o ; do mv $$f apq_sybase_$$f; done; mv -f *.o ../dll.d/. ) rm -fr libsybase.a sybase.d setup1: mysql_xcr mysql_xcr2 mysql_xcr3 mysql_incl chmod u+x mysql_xcr mysql_xcr2 mysql_xcr3 mysql_incl mysql_xty mysql_linker_options apq-mysql.ads: apq-mysql.ads-in mysql_generr.c mysql_xcr2 mysql_xcr3 @rm -f mysql_errmsg.h mysql_generr ./mysql_xcr >mysql_errmsg.h ./mysql_xty >mysql_type_codes.h $(CC) $(COPTS) $(MY_INCL) mysql_generr.c -o mysql_generr $(CC) $(COPTS) $(MY_INCL) mysql_gentyp.c -o mysql_gentyp $(CC) $(COPTS) $(MY_INCL) mysqlopts.c -o mysql_opts ./mysql_opts >opts.tmp ./mysql_generr | sort -k1,1n | ./mysql_xcr2 >gen.tmp ./mysql_gentyp | sort -k1,1n | ./mysql_xcr3 @rm -f mysql_generr mysql_errmsg.h mysql_gentyp mysql_type_codes.h gen.tmp opts.tmp mysql_opts c_mysql.obj: c_mysql.c config.win32 cl -c $(MY_INCL) $(CLOPTS) -MD c_mysql.c -o c_mysql.obj apq_myadapter.exp: c_mysql.obj lib -nologo -machine:i386 -out:apq_myadapter.lib c_mysql.obj apq_myadapter.lib: apq_myadapter.exp apq_myadapter.dll: apq_myadapter.exp apq_myadapter.lib c_mysql.obj link -nologo -machine:i386 -entry:DllMain@12 -dll -out:apq_myadapter.dll c_mysql.obj $(MY_WIMP) mydll1: @if [ ! -f apq_myadapter.dll ] ; then echo "You need to download apq_myadapter.dll" >/dev/tty; false; fi mydll0: apq_myadapter.dll mysql1: apq-mysql.ads mydll$(MSTOOLS) $(GNATMAKE) -c $(AOPTS) comp_mysql dll2def apq_myadapter.dll >dll.def dlltool --def dll.def --dllname apq_myadapter.dll --output-lib libmysql.a @rm -fr ./mysql.d dll.def mkdir ./mysql.d ( cd ./mysql.d && $(AR) x ../libmysql.a && for f in *.o ; do mv $$f apq_mysql_$$f; done; mv -f *.o ../dll.d/. ) rm -fr libmysql.a mysql.d postgresql1: numeric.o notices.o $(GNATMAKE) -c $(AOPTS) comp_pg dll2def $$(cygpath -w "$(PG_DLL)") >dll.def dlltool --def dll.def --dllname $$(basename "$(PG_DLL)") --output-lib libpq.a @rm -fr dll.def ./pq.d dll.def mkdir ./pq.d ( cd ./pq.d && $(AR) x ../libpq.a ; for f in *.o ; do mv $$f apq_pq_$$f; done; mv -f *.o ../dll.d/.) @rm -fr libpq.a pq.d libapq.a: apq.o $(PG_OBJS) $(MY_OBJS) $(SY_OBJS) @rm -f libapq.a $(AR) cr libapq.a apq.o $(PG_OBJS) $(MY_OBJS) $(SY_OBJS) dll.d/*.o @ls -l libapq.a finish: @echo "--" @echo "Now do 'make install' to install the library" @echo install: distribution installer ./installer uninstall: @echo "Use the Control Panel: Add/Remove Programs" @echo "Look for 'APQ-$(VERSION) (remove only)'" cleanmy0: # Have ability to create dll rm -f apq_adapter.dll apq_adapter.lib cleanmy1: # keep apq_adapter.dll clean: cleanmy$(MSTOOLS) rm -f *.o c_mysql.obj *.ali *.core b~*.ad[sb] errs.t libapq.a mysql.trc comp_pg comp_mysql *.obj rm -fr ./dll.d rm -f sybopts.tmp sybaseopts.exe rm -f mysql_errmsg.h mysql_type_codes.h rm -f mysql_generr.exe mysql_gentyp.exe mysql_opts.exe rm -f Makeincl tmysql apq-mysql.ads rm -f apq_myadapter.exp apq_myadapter.lib rm -f libapq.a apq_myadapter.exp nsis.log rm -f installer.exe clobmy0: clobmy1: rm -f apq_myadapter.dll clobber: clean clobmy$(HAVE_MY) manclean rm -f config.win32 installer.exe gnat_info.exe apq-$(VERSION).exe rm -f apq-sybase.ads apq-mysql.ads gnat.conf rm -f apq_syadapter.dll apq_syadapter.exp apq_syadapter.lib rm -f gnat.conf gnat_info.log @[ -h GNUmakefile ] && rm GNUmakefile || true (cd ./sybase; make clobber) manual: apq_manual.pdf apq_manual.dvi: manclean binding2.tex latex binding2.tex latex binding2.tex makeindex binding2 latex binding2.tex mv binding2.dvi apq_manual.dvi apq_manual.pdf: apq_manual.dvi # dvipdf apq_manual.dvi apq_manual.pdf manclean:: @rm -f binding2.toc binding2.log binding2.dvi binding2.aux binding2.idx binding2.ind binding2.ilg @rm -f apq_manual.dvi binding2.aux binding2.idx binding2.ilg binding2.ind binding2.lof binding2.log \ binding2.lot binding2.toc manlabels: sed > stream x]Pn0+|YK+%@R)> endobj 13 0 obj <> endobj 17 0 obj <> stream x33T0A(UU`Qɹ N!\A zfFf& !i\ fzf ffzf !\F!Y\! \\'endstream endobj 18 0 obj 83 endobj 19 0 obj <> endobj 23 0 obj <> stream x[r6+0cM7CCK&6 eֆ ܃K?~;::ENf0b h:4/ ݉LH@aYyQ̾T1%$JMgǓ= @3fއ[Hp~^/(^ c շ'bF\)Vnh́w(4 dD gPSD2# 4NcZL) &A%ބ]Y<xe ),Z[P"sDT1;FUw}e۱&mm 5hܔ$xLp@ *}oOm_87mfCqadsyuE>oHV@qo'-zCěm.DΌhт1 # ^}6 $F#@8^ZY^f _@Evoc?ܱXΊ p-< '#"E@]/Xx l|k·>{0ɏm9,t}( tދ: * :ݔ],Ųv2p`5AFiUd7]oNpJp ˑOR|h1MlhC'DJ5I$ck`#0&;mF2v7SEĜ*LD7HbC&9"c}\URP Ðx6'] x@a@u/ԭs$$"`$h]+ 1i7c3է/$BKg6^H"T|"T- F~q7SJI8dWmub9[%Op9icZ\, AU{*v%RH L[]TV}y,?㲸hb,2??b wIL"[Sp){W*aˌl3Ѣ> endobj 29 0 obj <> stream x\r6+LA~,mxڱK,.Th|}AL $\{!@]ηη.2{|Anモ?CeK&w?vnwegή.{痽 o 0Ll€ec Ru%l0"R4\$l2Xi5R qx5eM-dh%(Llcv}n m{4 u#_ 1RPԧe2[m$hdVJRstp@k.qgt=Q9 6k'X^z]o{0BU Ĥė"F>B۹@:I.-"_H)Z_~tƯ0&`LTΘ˰taE!lj *#~<|{ѢwU'q B`aerf(Z}v+t+$RTِ)7O>d@RT(bG s/։gX&t0e0|f~#Q 8^đaZuo}5bD$ GbC7IG'ܚ[=`N <[ gtb9R@Hݻq(84RKLOr;, l#q7} ]TOM{EJ"jyVV eFJbrxh$(|,wLf2@`gGhwa%P?Hk%@uP3(1PPiU*hT1QZ~Γ8W`_Z/ ΧZƓx]snKBy$!ĕ _z<>J#U( EP*4׭D#FUm8Ω}5b.eҷš9ٳq4u 5F %~i7ZOoY`:ҿZO3sbb{geu_ɍ"kֱjM}MXuv{ǣ8y(G!41rX~ UN(1{t#j0VnnXWL%5(vpE^B(*\Q-':!9?uRih:^"AJi_/s[(EDRJAi# xK\ea#a@fDņ*,4"c,R)H3OB|{򨭎K׆cXH(roj] be1H3z#ÞC=/c*d VKixHB mﶱO//N0Ne2* KW͂V*i57@!84+ (2'/6=SD+B;F,gAZd7 B#fj*[wP#hQ箇메RӖX=fKӕ 3=s"9 R1/FC'px3Lϊ.3ĵEh`,l(ibeP2iKc #K}22sN&dd>4Ph[ V@8!d@۸h}@E[Q^ţbJqzOv5W(| 8/b"k!qs/*u^0D85;CpPsx V5IApJ@@;cʽ}+tw4jH ]v($eJ%#Uw$7A9u;ם>endstream endobj 30 0 obj 2065 endobj 33 0 obj <> endobj 35 0 obj <> stream x\Ks6Wޏc&$NljHGHRl9>x$o]BOg> Mً[ (9 ϐ}7rKo/w?O"~Rfc@$ds,SPEiv\e,P^d@yu!|,1RR gr i9yy-7"_1P!(L<:Ę1vFsVJ;Nsu-ƀE$.,]Z H/`TXV @0멬z<)uF5$oVcfT`X$&Yř(˨Wf`)`Ǚ0͜4W3ɢQN5C>u#l1J)ARX$IU:)LOf6[}1\OM1ͬy4IؠDӄ.l<7jO pP9 IL"YvOAp $QMd&I$#x޴ CXD+ܥ2騸s{O0i֏CnN{g #F]'Y]FDvC_$tMnULve((Niz< m˲L UI:)<PVL 2)wL2$^ﲘo:RF UW}Zk0*nz*$iWXcW(ͯe,MQgE"OUX.V ㇔! ϕ(>('| {|jf @Hy/EJ-̙0$m|YC~ 5H.j=M`@}.hNZ$1j;<8 J$U[/\Dj61j[O6;iϬlcƢ0omH )Z(Yo^[$:#(ⰰ+l^"&uPa~%.Er5I#,^MƛbU %N--Z݇gy̾Evc֣Hr-o1 H:"GI9&#@Vp+ݫF}@c,_6kX5qri4ȶUI/7 X|Ro0L `vdU|:P^e?cPz6%e7oNtuħoe tZzFbHkwxjKp+*4ײ#jkp3GR*:+䞢3~Ӣ甕$:#EÇ$j &D8^ɰ-J )?[6#wWQM Wt1/WbtQ~XmqmwC1L2AWRm6bu$7V=Jb Λ5_6P i m?VPBkNu% XJrg:eG%?V@zϞSK" 汇r7O((]fgkY&.0\ұ7w'kV'/)ՓQ^X R kaLm \o 2h><0LTjǚ(|w/18ˢx5߮*(vr%kcL+ HZzw E$]==7sS*<#a;5@wfSgYLHMgL\茬8A>/Mq!@IEuv_[ oOFkx>#鎥+xjlǣMI)bHFQ{9ܜݜ Nendstream endobj 36 0 obj 2088 endobj 37 0 obj <> endobj 39 0 obj <> stream x[o6=WVN$cC6Mwꨩreyk7#RHYq\/khC7|:7)Axɧmx6x><-f'< ?xyp ytd;0$eQ1/k3C8A)K" oN\?,&ż`$!/)Lps M1ASJ&viy(6q\JT$g֍OT<˘KE)kF<5ZЊEz5׳+Ĺ[2(gGXmXX,бP.3@ aC# z$ڠoF?CE=L"(\SL źq]y6bP?x/ %I޿ypd>:廐Z2S)EUDg*WN1Z2=bvH SؽL,r/6=M_/2k4dm~LՖ׷SJ$ 2iA lyWM&b1, {"SDq *`\PKn&Yф!C+XO׉rZ,WLУS&bY3xHfcՅ^6Cy97p%)Q #C2? `3tj|?D ğ"C*/H8≤1fXyB4 J^LF:'v [Ap'lxY<$Rw1fL>/UY FK-gբ0v{?EMݵp8$ʼYc>¨ ai IJr5{46f3FNȝy0*Ue|4E0[eluOڠ{TJ2'X.Kj(JSjo_Qg0,VGX]:RS f1I "%[D-MR-|2w|SV=ЉdzXE&z1* P˪&%M{ᑲ#e2y8(=I!0hXZFҋb] 2F5Cj2VFQ,[%?Ϯ7EJuhu*o(Qtp6/G7$KׂE7c(e4C8\i>щWP]O/]/EQ63(!겱vO֤ߚ)i5i_*++V&XDsƗzzY6ZG"FpLk2u WC@;|5>zӕ ^Å}#X&HM9˛om (MG֥t^I1~s}2R>g|+Gvv{'l\WgEn, M[ p|^CnL Wz)v\XC̕}7nCMn꿗aŬ_! eU>[ teޗmf'qKB?}wpW0[?jWqGaQl['"{Kc=!V- k?YxFnLk& qFXErZv[J1uBU;0bN}nQl␔Wn&XH\Out+Gh[-G\?=&<vi1]捝eXY_JF!(6kbdWwyHS;Wվ m%JhԜclm^}4)T!@y4=W8Ny^ J;v*J3܇_,JlX.mQG?է7'@endstream endobj 40 0 obj 2117 endobj 41 0 obj <> endobj 43 0 obj <> stream xZnF}WɃ6{MVԨ㫊@鄭D*ᒻ8ICHeΞ9;;!!m|9< \2:4H*pv; gR tСt6=] _%|Ź@g*?b#pD|5 ^i$~diȚgY@(*IB;SUv:k QHь&B֛8ޣV'&[^"^05F#B=.'ӉE he#OmO"Y8˚ L1Gn㣓i16Ôgj+DŽ9)QY%1C1RwV!RK4^mF+_dş1Pghq&#rңi>4XXaN^ZBvP>@tXIX{r̵źM2ʹtxbdמn7aZZCqӍ$ӞnWmlpM[P .T-C;,x6|lv@3!_EdXGڌy%DP-qD0qc ~xٮwp J+7Ӭ1=",Ϊ#y oQ...y3 ǻexc! bڍY.SM쪭ecpeŮ0Me-N&9?c AL5j=P1/ {v_ -[?Y#Qn8]XsZw" 0Fm&3`4XN]I-cUX] f Z7D5U}:g9?=0'uz1[\:?Rk91{Hwr.M!Fuq-G=k;mDol}O4Xϱ3a]/Va~?Ј阬EbZ} x_CMV4îh{k9 _oôP Igv;ڮW`.f5G]#mMjW^b=wkh3_|Px/*s@XjJ~"SS 1,7NL7/}tl ~-$q%u .$6*zlIm7M2+ %VXZM'jM d\(,#'-y$IZŹW; 2X -&[5A" ;'.-~Ϛ4D7n\Sl wIM4 W -r ZD[>ӊr.1>w7Ӱ HNx쑗Ǥږ3ql_EݕTP(Ḱ読v(՜Mo2$2U`_R4on٩<jRڍlRjdY%gHfHD{%CZ;m}57Sʪ} ͥ˛(j7]4bXyyp2,o+d,HVz񭓼dFoh Wfkٵ ٟzZE۲]@l$e(?[QζNM^l <{u̱\nhc+ײ*7[A4F.G캩-=m!oمU>;^Ds70FJRBvV1}vBDs3Oaf?Ő_nB8 /N2endstream endobj 44 0 obj 1835 endobj 45 0 obj <> endobj 47 0 obj <> stream xe1 @E9/M3:[@Q!~c+$i|K`TC^[Jg uEa-ӳ<7Q~kqOIGL3oendstream endobj 48 0 obj 112 endobj 49 0 obj <> endobj 53 0 obj <> stream xY[oF^QB)~ٷ\@:}̬D*$U{JҢw w.wbDW9ҟnrvA9HJ*WE:!痻ٳWž͏fJ# 3}GJ+Y5 nΫο)aՕu6rN8b\RIZ iNC<p"&/. iH|{VܤuiQ _(O 2 'D |A4lRJن]QmY̺^v+\"I# ,D0̏Sp֬=%I\м8`&F[[vQKUv!TyzG0VC(w~Ќazicʟ`T#|A\6i޼W41\r frecNEƺ I⯗WKrJbm8' u%H9kۖ*F!& Kx )C4J,Aɡ1[u͉E9l\Q{&PNbk$aQW1N;ezZH#%Ug2@쾃+J8>.* 9=7Bi=YVaL=١K6G)VQO2YSPr@SI_Z'|W7A? F TIBz<BƒcNj=u6X|MHĨ}m'󥃮L4#فSb 5xE྿s&+Et0}y }Y6@1_3*+1ϟɸm yvʰ6\:ԍlc`ʃq{ا:]#뚲bjqSfyG9{Rb-E " HD& ']} rI_^ܰ5M)~OG)JNsnu'Y8p}*0 ANY_B}:Iɠ8>V0hoi1V҇dk+!ݒ8zjX\J qo zEgʤǀ/)~u1{=Y]җɦX(ĩv<@/X jxơsVuy?85EU !?@*~[ ܕ6&8}٢LГ8?,hӟN]«|Cv)&ˣ4)#s0/SX0^fUD-N0H~Ɯb+EvPD1zumE3+ƻ2Ƨ[;nFqV=ærv6}v\WErendstream endobj 54 0 obj 2308 endobj 57 0 obj <> endobj 59 0 obj <> stream x[]oƱqt@wf'}1`PJb<3ԒTCj,':uTU(o?_Y_s**{ +\ no/nkz^)_{K7;VHUTFz|o7{ Uon>}ڲPeCC;?4EćC[a^ֹˮU+lU-uEeNgEa(/m`o-ZXq}tyiSTRJϪB]K댧~Jwo+gIw_ZۍoyQf(^Xᝆ8;OlM1> |!!~,8j8Ovqb'()d_μs !E:XỲ2c>;rg$R:/0~~_;5}w};ON ^ "5,t RgIwQ˫w5x2/'x4wgAji+bǩ.zր*VwEe9ƶ@xLg(hr~>u"2l𲰜A}>StKi=i_F*MB>I 8LA:O$Y8=r KC ki*KٵMP1YiGwXY9bZSiac.;Ty~GWb< &І:d9o?a=9Y({SSx5S<[aO$[j-8nCBq!mY~xXnޕSYi $rN4zS{# -TiKR eɬZpe\!u;>E#C~NܟPJHu )>2RoׅDÔ($(䯧L1# x'$nJ K!"XJ QiHxgȡn;wAfMM%TuQ0%m|&T^%WWuz B5$H"J[fB^Պx5T2B2[ t/V yYt jJ*DKZ)?L 4zD^"SEn;ڵ? "I[̳ivwM@B6~G)[oT7KH(Vd4ԘqݧnO!slPGhR<umnS ?yCw?Zo xc899zX{ʑTč5 PbȽP72!`PEYd kҐ2sNn枓ʌcN5g顏7 F<-6 q͉RhehMlآ*$<O0ƍ7X2=pG &E%.}9fu |Af5@ēj؞H>ԩaTbJ;ƶ\6JnJ 3J('@GVrgf 7=L[~P).B3>}@`Oau4Z>4p_ B"j&WbtEסu!&a|4E(HjsKzǽ";CЧB"*+!s <>&s'Y!R $27mtd uʺ]%{~ Bk_9e&2Glq Bp?'c,SDO {6ۊ򐔈A)wX+ ?t܍rdQV'O'gpYӹ0GW gPJ٬Q|\aFu FjiϡV<ΘtT>4|3bVU,yuр9CBIxJM*.NsNC9OVxp=uD2t0Kl( cْz3!=VbϽ(Veee2'Y9n qR-ƧcP(юfy.Xe-BOxBsGS d.y٣m]byA&|`FV1:MG@[xJ, !WӋ6i?%MHĹ\-OۡFq7I*ty8C69F!E^85ԫFjp@@@Z^j\Gٽf;KIX`Pؙ/%G/1è$9uoʀU̘)3:_2Z(G  mv*hX3KIh"0lu1 St ջ7 )EPfQȨ;|ER#} 0*#pJ/ '7fS3- Ѣת\bHi&IlJLLZeZ*!yLAs[v,ǡk@Lf%ɤ?NuwĬ2w@%ktS]<ń>_~d6u֦ rFRSJ*@@pYդ WI6<{ %?"Fѥ Hw. &B-2wܼLHjC*TɧJj{]𲝬-E!Be>"l}|> MDh}ʨ5M]]4&԰C dy\PY6h1`MQįXj7zQDLv:5V8-ۙ0aYhI=aSŞ2Cqe6ub }Mw> endobj 65 0 obj <> stream xZr6ʾ+m*vre*54̐cEhÑ,g+NqH8}XWwg>x-ޭ^]}s%e.Z]ߞXnVn3'Vzwg2geJ^g/{ӛJg:_3+%xeĹdkIg\ǻ^k\fJXz<ŋ_W ׋bfvv0RfںՅ0ظ҇//ߍ/֙d vܢ /뀐rmfotaSUۋ^C6#y&=qߵw]U݈'v\dFG*1\V;q/f&5u|ma^jFxLJ~rޫ ._>s-݇*3Z>Uunq\@͏ oD|mkNV/ m݆Em#_퀁1!/pX933roOqKArxFw.GvU.B rQJO"6GbA("M܍ A&9@iFD'8-f Em@.^H9|r .JgN"zIa*6Φ0bm^U"% Yr|<WBj@:'Q=Ay0JF0vV\!@;RATojʱ:#H_z~S!q %)|2U.VpZàZ@R*$%N*02*w9ŮXV`J*uCX1BvkPx*S]Z{u m` 8!ANUawt<ѮPvazNdbpʗ'[}\'օvǕ5#t_uR%ú+s \Xˆ+u#D= (U; aKF{h&9UoKe(pZQ 2q= fR=˰TΑe|UЏ^\^SqbZ=N5?4oC({$wo3bKj[Έ,oe]6@v3Gs!whiWaB>w7tEPT]eK55>Svi^ 9P!.Gл`1VSu)''= ~tjrIxz bɧv/^eHw]*QG_nvGF",aeZ8wWW'M Nk.~wUSu:Dp#Qq:ǸLU4Ã3I~$}/GS gl7,gxu3! USust8\l0NQ6f_ }=}U uꫦ&b*wi4*G*DY}NE]2wװ11~ LӁS_&~@ijbG} ,w/yOz.6K H 4b9+E{ =C3/u<)4S46'tPl#"lMh϶qΌEgbJEe,Cܫi2>JT'JϪDԜԉ?nh [DMO5_Nu=ZPɤAW풥~:rһP8u&(9rmy> endobj 72 0 obj <> stream xZێ _1o m-+@̐#rS]]Mrז`08fuթSU*b?_|Yٯ_^<}WVUƭ37\|qzXbi\ego/_ o*[9 /WpQy->{e\')~/._m6+*XUJ$Q+KQ 7/7q{[)+8>|RVe}1.=ݶn0sŭen'1~Uȼ_oL|zΧ(Csq%A.VG2VJ|p$}ܛWLf61&հ7yo 0Β@lЦvI​8S:muR+Sy+,V0 {z/ej6vY䛡!yeeEFv {vxëu,ҌA@&Mƍ:h0&0gNtO(}8"[hn2Ӱ>I(@h9Qf Bg)v;bӒ_%䇗ɅC-<ɱc<4MJ qGEVX@ݱ邏QJC9z1 6XꑯnC& J#ҷ:FqmBOCQEx[Իva BpHE0[\,#G~h(@ .{G(9@I%S`w|&F@ԅ? qNT:șY 6J-bQVcDvR ݭqs.>b!Q@$IauQ%e){bLk4T̗"[{PTp|~{u>4UpZCƆf D)xpj.O {yrWq#.X(nG 8@~>vۡfrIi/rI~p(M{gAd26^~^ːЁ<0T|Œ b,ʼn\>2^ˠṖl†J"L,IGݞ`s')s ,+uSsS?t?472&?pi[z/PBBb(ĽVT ב+<}glTrtFˑ9wyܥ] ?zW>/6>.鸯4QE>!gu)8,|)J\n~6 rAT;䍬THzH =TDέvTޠ-/>YŴJ3΢/.QԄK}nGĩD4_-v8F: McL&QZfy7ߛ OebE:x,(3!Waqa4x4N-DNSβaGAeNtvaGXzF\U{H6{lbۣ ;R< k`hG=PX2lR+/NPaښ~u?d_Tmg52 #UT"UBl ΁-Z=Esod 0xArV񶹟BӨ*8`<բ9`?n;NhkYm;Z 7)&IvlX8\pz6]lT fv2\BϱD!F+0j鹌s7.dE}6Ǭ _lp/v:Bz d\TbRqM*W)0k(FUuE{AcRWeKHM  8\Oy-JNti-x҂q68B?cYI#Iwz0#&2\RB(/Eylth Nп)MgحcY lBgW9J9LyiWnx=-٥`VkX Y]zz+-=lxNo)^>U{LHdT&C@pjX|c3\ѤXo*^2$%ZS)%X0d8a=n',Õ"glZgnw\ov"߿ܯXά2)}rGMb 6.^?dVD_BnI3A0ˡq'ѧrG2&,oJ>,\_p^BR}wnY]f.S4[\{KH)'T7aȷԀu5K?K#(!_ECo)eg}{HRD'V.!+՚9SnYQ{*wWV/'E" 6T .ᡵ;+l2 KL5$N~γӆMմP|da兆n!PVK )ahBӇB=V)t9&YAF%ט!JKH/W, 퓒/5D}+syA}_G,wH8u]"o;> endobj 84 0 obj <> stream xZ]s6޶;h-qgLzgiHBRq_pAJNf8 [__}bXٯ]]|e3[BZW Ua W߳Lf4BbYffa $W" uCEfk?Ęi=72t^YoX7rnwoo>p-)qzkg kbv_}nQ0Ʊ<|qP0X>!Z< ݧWDh ܛk~qap"m c܌Ʉ6pD\ͦq<+ł "?qͭQIr:y_T5UWoƥeKlm)m&eB ZMxM=vc cyhyph;3C]g +i)aWoJwa5kndfXݓDDa/ l<^nn_zP{Z]b~;8z)/v=9ECyq2i0$4ٖ t玣VkјS]ĕ @0\,%ḘW^Wrr(t}  fY*,k$-`Bƣx|n&4X;tZ40'q/-TN})7QO![BQz]p΃"v㱕B0s)߫O:Ԟy&p;Y#-'T zv\IףnSX&HWd,Of wx"ٸ68lH>W!&B/0P0*H&&(Zڣ8V`X& zI Om_{b?.|o&M09 2Ȉ#T(QL zG C >HƒECށ @l‚t`+BB3#ͧLP}C'5-4}PB_Nf SQi@;4ŋ,Tݖ)Z[q.k\1Z+f-/+y;nU⌠'vBT }y$Ѯ^8 wiONA.'> De4VC(q[곐FhϢ/nsmКX wz}`$o5UeWDž\s9,m `~XBKbrS\T/yRX= t⮣S]JP'3 2\ZZFוdj:J^;=U`"/JF&f>1,ȵB]ۃe@Ο5q Oe &^a Iy[eQ`1>Fd'e=poA۵&t^RPW3)\bAC<#褍wؕMz0UO~y[Ju}< :LB T,yVC9B _~QF<׻](RAE8Q}oH"'99]R> endobj 88 0 obj <> stream x\n7^B?[ f!Pcoj q[ݢ@`lmJr]k$w5ȳ1089߹dޟ{y\NýgR6^/@a1N~a<%kaPQ"AH7|o2J# ' ŰtNNf)G|8bL6DBE\;dzxv?UeSTaP?*RGhl X>`f "q\]/O< W?|$v,no}@dʹWH)MaU5U fDy jC_, y1*Eܳz2q6` J{re ׏)M9S3S=_/ݚ8eEYD=%؏ތ)-e}ύli~nZϬ.GRJ/S71ܦSTЈ+麈)Paj,HXh/=ڨ]qRj4#(."}WٮfphQ\QUHF zE]T1/WnbG6ɉf F+ 6Vl{aT2;_xuWs5=o< |\ĽOAm:z.xvgmiaUeL՝5fRBgcǫRc+~gnD_ . j'[¸}v\Ud~ g,f-&;Y spL_g9'ğ{ba~ZMoFZE"/瓻̇ )ISؚsĢ3O&sV+EBbR;Q ޵*G5e0O ; d|닋ф@~YeyNю=/ {vɁԽGix  kjV/lVH(t 3tJ@M~!E`VI-pker5-Uz漗]c>ڠ), E2 Lc|4؍` حfp0"h!1t) GJ-  _.ron*̷!,_Q=z  nFB0 Z0i`uƲϖwI 1j1+2m"+q'hs#Aة/ Rt͸H,xےit`Nv|YM\c,Q 9 0g0S/&ds:"i^SBQj׳K!Ea<,%UqH [?gp`%>C[8'"(y9w1x~S$5_ +| AT.54 ]m 6,gT2F+mNmX\p2|U/9TyO.U*a*H}qjD҈|&Tpn@{,|r<=''`d|SP%hI31$ JL[2!v"6>Q$&Q4"gPVyZ)ȶ_P@Y]$M.PY)(1Xs;7+U63jU;Pq} QxqZ'dsQl_ 5o_ZUet*b2T+P}$Tp%IW}Hz,NЮ<`?ZtAB.MEti.]P"i5DPL|_A! ƣL_`P4:g+cYB\,؎ށ%cʼ4B QFͩge!CԮ:tG{u7*pF:^õFtFH*f+'hp`. )WF$ Xqe7[M/~2J)4bpR売icnV^rdM=?`^VU5ޟ(R tw|R7ȅBrwx`^>{~|N;>yDz"=P 'M_2 ^2qH$T?$JbewIDA!ha5#=䔀cR 70@=r;X;Vos!6M=\Ԟ8W+ya"c3[Rҝ/'G_.en)O  )AK0vq/7&Fu'!|p!C^La.h8p+%>Ⱦs3Y*L;ʍ?:Ya)]7IsCRࡋrH!1DZ2B:F]d_7e7z,j#YsOH778dMU] 'ɗ0 ̘Ibgo5aV褞]_\%7#{{e#8sj}.wQ=by 1K!v77&_3cގ`:UȅAI87=j3 씢l=>PBQ&TnLP)*3&"ȔP;ҩʍ"TD --O@j2)3:C&RnH~Ɍ 5tݻa'z hdz,K4FVvV t ֠ n6FOM̐zvD4:~kOlR\ͿZکTp$",pp|K ʌ"NnL;2̐͝(D]P` (*+<0ѓpCesV=ۨNZ'uc2)N$AI]sh%Μx&I`mʝlw]ູIh;11Ҋ4twn?R ^7'LVb BzN,Qh-Q䦵P/;lPR)nbdL1u+3&&$8t~|vCTkskHkvp_@ i-܍>FIu'7$T.!A1#z@hg d=jOn74ImlOfpD1}0Eׁ,(32"TQfL @Fժ0ʌ$J4*ߛ?܍@DCg2*(NdneL ESLGvRܥr`aw$Š?[1W;!zr!qdUؽ*bځ v;E/GwߴbBɓfffL:'\LÓ>8#Bp z -}칂pyZ'{Q媚v53`O!O3Жte`fLzE0i{>tj1 wAN@!sm" V|gV2DO.&k}t97X+ hVM[xj*Mpv47 >pE>h7|q眫tŒ"nY-wm_g4;&3Y ސD\-ӥuRp(lҷ!m'G{}# 3W;Gŋ Ŷ?gxZMl|d xs㵧e 1hL11}姾'bhia dz06P<޺9tz6?!>s!Q4{"d/?P Kb`nL6 S`fL RShՐ2dcy:7=ئhL@\_fM)%jdn.@0 È}n7pa|1E:XH!U溯5wjcTåk'5F.Ub$XJppe> ;~qF ssHendstream endobj 89 0 obj 4105 endobj 90 0 obj <> endobj 92 0 obj <> stream x\n.O1?"~)뵓؋vQMg88kC8kic,8 #xv#Ÿltr}ёAFRGןHsT#JdHj WIG#k'G_!4c! @D(,U'v0ĩw^'D Nvꒈ', 6 {# ֈ9V8I7Hmutr~hUˣWWN.\~7VMw{E$c%7nRNWWazU寉Л@ g`nT$}ſ $}$)0$NXU@:,__GPJn~L"pč8^,OtnޫK/.RsuS m83UB7\nґ#i~>Y3CmSl͌)9]scWSL a.!lt7oL Ewr1'c|ט?c)xUTX * 3K娌M*03crTy3c\p帚A!U/( {̵׀Rz$ x;Cb$pRxFWUL%X-+2~abbe#\#y 0E^k#AG9T,. v5ymU6Q3t/թ`Yu jLo5)^CJLjY'4fwBq=1^-BS#^o9XE B ^PfyE2۞.-~f,ܳ,_x,e G}Ӕc(ẢVuQ?6d(ͻY+epk42˙Mv'Võt].Q# Z xc\礻΃=zmqRwds=F`YLtٵ)qlY5dw~Ғ*N=HO ll%> %\fE] $ ;CDAdǹ?Ԧ:1Ѱ .۴/|I !/jpK %&5pD^ GmmF Ž}%Ly6KRVFFÇ;wT),ZMwvi\n(v7dtuo0q˘+cU ֫jRqp 8 {Bhd{yeh\P p27ì/CZ {t~ڤz ̌R@.!`=_V&8ErsqӘ"53 0&B$enL H6.CCFZ_WLAˊ~ zzI9%&nhG! 2]((R]KU(GVmݘYT 0L̐8bz׃dZ/A>\$cn Hw ûn,YXl;2AeMA}:mݓ}p ۍRL@.ɷ^0&|:.E0©A-NĹК8l=LL,@RwY2trszA%9XcnQ9P:QMOe˦ȱ̰(.&8A:e8,9P02cP(0aRLgiX Ea,ony1w̞QYʩبbm58M`]R";Lܘ`X?y{ߝjæڿ..ޜ_xA큺'\ݜg}@]͌HYWψcQ𿘙\]̛7r2n(k&d_fؖ}Zof0bLcbzn1>V0m^tN1ݶ"?jl,GhxO +7杀Lpj}RB^jcs>bRnHbZ6+38 P4E7,(3fC9H̘8VHl*Çg{I^×E&nYi Wr#Ծ*&zSLp/;r.W#*g'92R1⤘^pWl{@% /:W7!Es GӚc&Iѽ- )Ԟ=Knit]+t++3w aVf8iH ^.{M8[fo C0n*fˌE8K\,l.2c0`Dz G 5@K'f|Iλ"f ==መ/eJB=;*ǔ!D7T2*-a Sφ "ŴX慶tٮ;(rL"`. #vɶKZj1@)lVմr uNW;_A^`,ng8E.gyR|0L[L6\/0{̵{.FժiQeëZj\O{^K~`H3<<QOGכ'mH]k]e#Mն>K.\ga%GUѷiH,;w CȁI@C[c A)Yt;軌)d&6:'ʁkQ|)Y3rhu9m7~dw h={f$TEAcvsmY.V Hҡkm0o۾ dy$ٻׁjt4 ~?w<=\]u%Lw#:m|mS,l~Xaw+xnK+Cκ+ BIl=[HR)/bٿ,b<剢$E5іZ64iX׷/_}ua\V}zvwx?㓑endstream endobj 93 0 obj 3585 endobj 96 0 obj <> endobj 98 0 obj <> stream x[[o._᷶;K ^} hH⸿g3ge[mJ3|;Ww;\Y?h_N$x7Ib*BBqwv$iߓ5'@Cpd0a< /,7̙\\ ~X\LH/QzWMx./g{t+I a%Ŧ+^6 jIHs3j$ÜXh0F\(9ֹv$p.͕W" >INg>~Q4G(+ӂio7CtwyQU R%+f8 Z+^լtiƻYjպj5 I@ fa Ra9Up/S!AZFUM Niќr? ihzx!pL7qe(Psox&ǬYͪW 煔=&jP5| u:xЇPKB&,WܰhMWn9`vǻ\eN]>PL}|DY-33!rKzIoWTוu۔(=Z \K1p% l=!*%iwAf0u9 n^7mtKV <"?mk?KY X@@H10A$P F 8rP`Zap .@^.-1Ɓ ^s3gu QYoYz@:fߺ 3İD6a+{lo&ϕjvE \h"8$4 6LP*/ zVU[BZi0 XOEEYI:v!MхN1Ljɠ@NR&46qjJ۴MPS;C̝l;l*!fCU\3Ox.AbxaO/cde +. '4m\`2)a+^,do~!c4;)M?hd ?ȚD#kbG7+Yծ¹@L iQN} uXīMJ0hX 4ԇf$qV_7r6kd :׌ۆw&tze*1P %;7F5)77D0:P{_'i u:pAҮ &fP n!}QSf:6ћ0k 0rzx&!1a %Ftƶe,K()ͫXY0ɹ s, .c Z YGk}\T!pǘXZh 8- G 5X4FǤT1ʶ{#ڼ@C[/wҸIA$'pf}ȉ[H.gU+2C?1wSO-=L7x_u^?:^C=qt{M;Ij?txP#K\5GpbK\2>B|Va(O,3Pq އYxlHQ]_֜qfUC _i5bFM*V bL#C]2zI䖜x`T95B橥D X>*Œtoy;cr>ԜK1=mP1'MXvȅF xx\4x.̩YFGhd~/DG4D%IK"<0c$>JO,R5KPIpa#N:bAu~6KOdDҐl{bpvjkmY­$bNlҁ)O2Mud$tF@Z cYi%lt myb{1NSN<~s=t=|;q$D=YOB ZR tHwq"WH5fܸx穀 tT 7\-/ ۄ)+u݂v[׭єl|d{c$IֺbaıHMmwV1wࡐleV: p^]$^v5[DWq$㇃ dhtJ[]9lw?)Ť=%&7FFhi  IVk faG1DuNN#n!RQ9jN @M"x7 9D}9AI+oQO[.ͼ PMYvIW0dN8`K\5KĮ4Ljh_vB&?bQ lb~ME׋"ZdJ8 En"UxIef`[6Q UrKYPr0Tm ڴ-8NIE=]C* = I6!I0ƼÊwFJMUە/ g'}80j0C1`ٕX815_0N-2dj˲.\e{Ac"d>P=BkbvjƽwSyTj*M&MIGՁG{!n滃b=nG?᧳ۢendstream endobj 99 0 obj 3767 endobj 100 0 obj <> endobj 102 0 obj <> stream xXɎF rWhVOKn/؎_ 5-2Ey\ŊawK"j@y8\=pM}k^ygvmsؕV%o/ I_L$dml;xk"JHwb8f󈐘[%$Ghw1~\6P0X$6Mȍy,;V|4:dFS`:anĘkyX+[[;Fc ^"TC?k*cN)L7ڈъH#P,bI?dXw\S6qxt+xl!B`br>`dF}sG&;ɡ94p\V݋Sh!u2D43{hV\%e<}zq oL=("!c<#Yzd16. B-΀C&C}Q*Fztc 0G*_Kwendstream endobj 103 0 obj 1823 endobj 104 0 obj <> endobj 106 0 obj <> stream xTMO@z#wo$D%BB-Ā)`L+~&T,y33Yxu]e=Èe]IP1N,Ⱥd9h˴ՀUvS~!琵 $m'M,dJV|pǦ''i>?<@ 3<ȁrHNxX!B$v/@eMQFIV$#J3,Pl?*!xجڲ*ܥݻʶhpƤG!b*xsP2EF d⠽^77u-聈?eעQ,/hE@$ ; F)Kl'<;Ia:X S m0dX<l|~/#!ͻ:ScxJ_Eu1 1PR%mQ=9)\_261Yl: i1ۗ!HQ AXWFhwuH)좩|S%ΗEtmltW@ WCtpCt磢)_kTCbem$f#O{EgӔT^F۫U;aJGlc2iMd`3l 8jxy][nobHendstream endobj 107 0 obj 674 endobj 108 0 obj <> endobj 110 0 obj <> stream x\n#7]_!`vhxk'8c+Ⱦ dgF,)dv7&E6fj' BTM P;z<77oF77/G7W'߸9#k/owL@D_?0N{t(H1`S^]_0جvv߫oog'˾bPp1R7 -* 808I@kӲLׄt熩Q'8_E4;%"0n.m>}1"oORdNvT\2ݮu+0*BqBR?O;ͦh(.폕rdYnTjYVú[,6ɓ&Eu_n~XovbQfx$1x&I Ѻ\9Ĕufb+w }2>9߳Hkm%Gk719:>t&fnT5N @t H̋U^ffF{sxWnRMܼuF RZirvSX܇(FEe){X"T͌R{P5t$үDjƜo2ZEUq2GcL{0U357*V'fqL}[̛<3t/8ތՁ+4;&6H#ĩlvM<̚xt[vPnUF *g ʒ'5oÃV>dZ+uzy9)0ڋC0VwQd8gC(JLH'UIkYv'D莉fW/d"]™m+غ&2 3)3=.&[+ADTLJrRL}wstIR R%plzʱ.  c\aDB_vHk[KI@hP!])}Haq l!wsР`_DW!o+]D/~]+6Bp,ytphsPq!Ñ9ܨ'Қވ;?3,@0TF 3Qװ:1<3,(:T ΌR[,v{u{s݂f{fC\BAN Nk7E)3NZQװ:1=3,`ַTɑqdz+lR@0i]ro˃f"" MЪ}?bVsut)NJ .vgyہ?[`:r #jUQK@2VLLUxBB۫/]<1d6k g ՘=UR붅E{a4*bT,hTz m5ݒvʱv$ݷǨ`<إ-XܨUau H2 TZdao%nnn㇇{œM>>0Gn_:ֱY ]u]h't3MW^ѥU e]۩Xp%b3U]8- WewFa39⃟C0:DD/!K^_l ۪_pB*GL4ab}mU\k0 #=viCˀF*ωN)?T:+ (&BPKJ/iz!ߘp;w^H+fA74GyJ!Z5 u%Si$Mz m^ ػÚ̾yf|$~Z_ [t5HRmJXXs Q#TL\JK[OO~nJm<)NgXf9Eh]h'G~XIū~8#wOxi&)^o4 Vd̸Unc2r "*W+Ch^0>1QU~OTQ7uRDcl;:;AUS[uPm;Az31[;0UEɈƯA{&2qA-z}*56 ԆJl x#6<4.j qNCd AP{q݃iӲm$yjs}L&tj35͓wM+C 4',z-@+r;J1!z|xrΝ+XW]Eo?Pn)U6&]"74{,dڴGUBfPB"(HA-RF~ ^0A55c_b7`^#.W`rj ̟s~S4'ASRA+SSc栍ɌLlLnP414ؽ|^Nlm'kh適60}X S'X3|)W"ڙܐl{2)mdV42Fd^=J*.~򇇽!7.kxC-CLltHJW_s/H'RON /})'qu)8_~||])1I ?{p((]%Uh,LN aih ?&TQ1ØThb}^.?/+o$NSGƏ<[(b(evf3 V,v}`9ژb0+%"ܚ; tB9Ϧ߼1x Í'B?VMt.qfQL6_KUMYPFyʣ *_dE1ˈ^sx*bJ*]R>(_|N9 yn|5+Idɏg_endstream endobj 111 0 obj 3493 endobj 112 0 obj <> endobj 114 0 obj <> stream xZn#7]Q_@^2@D{4;~dԾ$Hrf?[dT[RwD#`lvY<:"%g?F̷ůcq>daUD1U/)J)Qb8o؟Ww_xfr{Shb$q-m?___^L)MM\$j,lltw1SVM^cۇj68 ƬI$N4rKo AcmutФtjX-lZ~s4DkX>w0rjt=},?~w__zZ-!Bѣ?c *rI 07k?&>&NjVΟ};D+]@\|ǥzلniJ(7f}5ɚXb=+,´v{@Ψ؍~pPёGJgяi8 wϏrOmx;,%h(G4cyl p N7 'cS^·s VJ|Z~s5ߨBfx1ŒXN%L 5oFHrζraatYe>sxٙc/`h$x=-:Bj}:X#x1%a@^B^ӏD&"YXou#8nF~Iy)pEUkR>08$V1ܗq. ,̧:$ma0bU)ThܩCͶ\?:xˀN&ts`Dc)X Y\(jmJv=]nT}|ܴQy&;z:[/R/4ps~M%=IqEdG4ˎQְ¨*4bx ZǴ5&%AUeQq .03 Gp[N:'F* Q0W/)7 G0uQrcrT$'!렎aܨ6o)3fmcTx $ Ld৳N<\f+%=rT ܐ,1`bs怒aZCw ㊹brEq׽-2cl890uql P8z!PŽ0mfy. q]Uܕ nlW6:YnE U? EB/^ZI8H7n<5=p hQiӈ/> endobj 120 0 obj <> stream x[[o-QB@_5e8AkuXE@ KBJ7Wmbt10$绝9c/{{č?yͰwѾAFRÛI'pD0{({#{ޫw \B W󋿸 iLv$Raxx~$*@9Fh?]a/&M9nX#i"ŭ!x78x΋E$O̐*ͼvcIe)6 0R$ NFzvWBZ c:Lˈ`ɪOU1q!/2'1u.wP7媜lմ\|%>^Jm(GC<0c/Ƴ%gO>/aH4tV.{ӈ*ȶkh|;]dI7.W:;Ͽz+$.#F 8AZYe_: \Rĸ+dGJhsLH(.V.58&cY:RQ8W%!fթkrS > endobj 124 0 obj <> stream x[nH]죿Bo; <8g" [0h-";շDٱ֚cj6NU3?w89vGg8$3-{3Yd!3"{O<7gtc< Q-qtbpzi*+` Ol1)zfy& E=ھ%3T>ӄ jXI&iU.*Ld*A?hTx Q\d\ |3Dtڑ2c9 ߺ`lF2ZE,mcQq NVf$d(2A)GM[NGbd5_,u67*a:ÊW;{q*!z4GwQ}[ |3~ojxϖW9#: #b B[Xm{_7N%JT|1VC@?3,GaMy.JAY- YVW>xJOϣ!ֽHp#tn $|o4.'մE' -уTAԠ<4qqUь ,l٢K3cĚzc#L)(V88 qXZ'@ZEw1R2/- K{%$ ڡ26vݯ਀rD T0/k' JjxSE:_`Zytҫq D"Xu.& D\id!FAmy&h;VsX7gT8\aaLGo,#(p9SǕەR}G EU8E5˱ZB=dV`o5ģ.#U=CNj!q2M!j%7*P /GTx=.rDL#r}Bދ1Cis ib кj:5sB7 J؂i|aFL=I DfQ}W5T > =ka!wI]ā1C 1&*P q'.\ uDt0^#)9SA sE"ϱh`Ś(A KKi[9doDE8f96=+CAdj)|ײ^$hw:ŹLCG9MD#~i#('a_4_ZTeէYMz7a@K3ס@P |ѝE {7d$K'<)ijq#WH gr#Xv!HA-J"؞`2 'jRzÉ80)fM&3WmMˉy I(XW]3sDT^J_Ꜯ`؅LJQ (;di#MeOf,>ԂxIy Ł*/.DN3rn}3EBTB46E]tU׾~=<=<<:ts`Xp~r,~%>_~W?Dl< /XFr|G:5#1Zk0}V,8q0m o #:B-+ +Ǟn641ɵʛ }/ l\€'!՝_CB ])!UF ũ/>s| cUi*>ث 4ߖN-# C'9] |G0,ǵ d1`bk7@Igj0mi~9>|1o:#*g&ɗPy7v#oޛ8?w_}.󾝈LDFLddlRI ed-q Bxi/{Ҳ21ǘWSwXzquQɟ(nVuq3.ѸlWѶBjכh?tO Y 浼,,3[( ?Onbݓݳh%]Ut6Ty>YY2f"̗CObubfOi'xbh]Ka![(ꆶꥑePl3Z8h/Ϣ}3ቴ?}KFY"uKB'Tbdq˦c!aFS?: rvKʋ6>=d;kkH=!{-I([RbEo/ģ,ckӭ [QȨxt\݈6Fc=D We.O];u*:lsBbŞfte? {BVU BTOYBUsußhג7Bo~GC(l>x!Tb!,uNW!vu+sUZnangF0)Ǘ0޳  {Xȵ3wuR.sux[/e5;7Al\o)< Es޷ȎT岰G\zQB0\ݰ.{/@X+n:nnm? = ~/!togq厎> =K 1[q@ ;2,2*4|ߺf6 D9..!/hQF&\0:4wrϒs*]8istn^K4hYģnޜ?7P x0:<;`I0<[9vd.=sခ9㱯'n%Q-,>TɷuU:]z&۟R(≚; oP%ϛt_IʟUt^{E}tk&,sis_tOKXudgB(^O` c-< m3ng˻p&J\r99:I4Zpp\-pрS&,o+Lìmlt?endstream endobj 125 0 obj 3767 endobj 126 0 obj <> endobj 128 0 obj <> stream x[m6>%@Ʊ$&wM@C;u3=MDʞ P ">H&"쏳???7J.ʬ43~fBBradNr}◗s/ :x*s*_^=sȴ6>|˷O"D ˗JLRZ݃p[w/ SLteJ(EZd&iz|VfRiIt|kW|^V\GOwMPҪG?fIönTVY{{%2"EABlK!ȖY-:BJOw^NgeY|f l 3wulG* W3QhE5(du5T{ C;4 #f5<䣴u09NӳRTv[EauYSs$~nFh:_!D"CvU,š#`Se_;A>ExHX6Ѫjpzki#X͚JOVnZ u;Y @d(8HU!AA{:,4rdąK%d]D`#MG:`f 0qݪ^LSxL )oᷗYտ39;QR' rAZ뇛~'|AwUXM ΁NTn愰r-30 SwzX BC#2}_}-ZGp؝~q6#Ij>FAVvU}HBВя7"@hKt&?X ѥQb, 'gju"tփ!A>:vn"Y ~DAH .myΜA|ejAx ) V]GwHfU@ ,-gp8G2_"(aUHc}t?@U2ܹV)[E~S[S"w6s^;'@". #<p1W 9&߸صmB5SBmܚa_G~xj 'rr)ũ6.>c|n|k=|Ü-qTge!)f TKsw4XZFes#U'9)}xT#dP2a0Ѐ#j, TYr LEQcJ$AWW}q_4CQ$nͥf\tuWa$M\G0$o[Ȝe4퀪?Ȅ / 1nУ*<J )R>f&GҝD9࣠Ehclv%뾃4,)kvո$e$k}3& it $͈_4S_x'K;B6P.$e: Q9EFcC6trS"!~nþ!0MpHp+O1v]u"YuGF0^K+H$qczK= 5{o42W{] |fcȐY#*  Me; ޸iг_FjA\t#̘@P }1DА,"վڞ=}qϋ;g]=}u^<[oo$dF~F.А-1ݶg>T"$rXcΩV8Ŕ9a\{+Tg*M%`;#"JeAU X]Cr/9AFw`נ ,f OJ)ȁF1WoM&37A''*! Ajb.>I@,$g}˄Ifs羅r ;nc}NqDt"C$|@wpd(٦p{gUs|n["k2 ʑLGW2=KR=3+>nC0_ܳʧXOsWtC2 k \ݺrlurS|jhk[pp_.ɩp.ģ)'<:j4s[7:.~M&f 魹Й5:!fKHS]T8q'|RHc%:5 㼍Oʼnuj B@FάqHj!$GJR%LIt XO=`OSU:j+U2zTC:0>3'TpZj(97r0wөΞԦ},{1m1 08m ip6R ϪTvj8_1vȅtxihuҝ1P vs*sc"9|40{4CԒP@|U h >|<1*z``ھu4%?k0,`!vU438W_dʟ Y>-執41z8WS(Kn|f'R} ڗ$cAW iO7= ZŘWu1ź^S#8X%% Ru#4M!-PӠ&a5yWo8&bUq6'^NԶxǑ.-Ը|WhBLIkc2P SiglR Cy ܋AƘ@!0q-)p%;7ӟ? +ʪ\1gkW>b=f_.҄~SbhX8Ѥ(4)%k2dE1 -lxIhȽ$Tr 8t&.t_+>^ endstream endobj 129 0 obj 3651 endobj 132 0 obj <> endobj 134 0 obj <> stream x[mo8>G -3;Mm4M|8@Jmy%ܯ᫤ZNb_Ԣhp8C5Ax_l9k۱c0kl< 5J ,-a)>|E3D)Di?t<$R=-dF0Eҏ|8;_j>a&lj8Z&̐F\ H3ੵCDDo}>2h>sAං(Q# A"vY墨/e1~,?b'(6zzfdb)P"yi^7̆Wr>KXO'\#LOyO_a3*_hCl )<-_F9A4Z~& R.WnM駡P}o׎Lϳ?H85 !P6d]֚HT攆e:@Rzd fLjƖHp~yH(*,BYd]xQ%`7B>uECM1|B)tobUQ"D.DJ[CFln#g O`1A #Tp٭d"e-!i#V:PP}TL6 )T'X"*#=Y),L}¡^){ p,nȗyM6:??>\?FgnC$ƐDgh`'Znudk~Bh Z^nu 5"qrSjg ЀDh}m#Wf \B :27?alG@^lcלCq;ROxƒ`vBbm%`Q%NL֐nbֹY GɅ q/Y!AT6ۄ"3ڡZZ@>}"nYrC$z6#f:[tOQ fϯ?z UbF3M"MSU&-ӕH+h_u֨좹)Jk/1A=!Ƀ<ǀgame DMc\<Ϧao75:Qjsx `xjVgإV\O(=4$M# b̈́Mtv RH:^.*Lh{$FU! ^" SL#FhO׭tx5x֨bEEck=>V65K;dK:uՅ\ʦ!x3nPDkL"x > `F:LL ݻ[}E[ݓVI +oMϝg؆@qۧc ˝*¿ Z:9EGN)q ŝ^Wp6o%A|hG>`ivf3pÇo'p+b 2'8xE?OC{ĩ\mt, Аy hh`, r%44Wp7Y;}Q,# X|G%4ό@zYɳsK;ɂpCz=V}_gㅖ}[;ϲuyB`1mΫtC m̨E+ !>({כy{A6S/Pv` -*vR.%ە^ػ*w{We/Tz-~T$"䢨?@U':+ $4j΍ULI˵Qc'$z,6~2ʜ# cyY ʪ> ;WfN7˸n o$*yF/}aTY?wEli#rܿ-|U YTraŒlWPȑG")endstream endobj 135 0 obj 3082 endobj 136 0 obj <> endobj 138 0 obj <> stream xZkI? }N~? 6p&؞]IFidǺ(G =3UuUaD ˔3_MߜO^|dtjTՄϤxQ"CRKX&(bo׌ûɳ߿=;}&"\/o?ˌ OvG"·9H`=8\fhɌ*vSG4l珸j-k$ wq@5<6f!ʰViaL?*aPr2pHT>gVXZ{uQϗUY rwuID2,)M|~[r҈*!.f]CB(jW|"䏺xvvܟ_I[KL8iMP As>U1Owdjo,lk?UEPBRʸ>+JT5˭ˌ OtˮzL !X!Q[/ypCZ(ۮ3U ,1BP) HHBu I\aALHٲ]߅Q@ ۥm؊$)M5}d2 dU;%s jc&T{JZ,{^ J<V6Pj QusLkW尐*"]7~Mx3Hh9;fDI^R_Dai2Hd#ȮWw A{WX EܷH_cho|,X"S(j4s08yʵdY~ۥWe> dQE.yh/YB0'j택wx`x$Va#hx{.I@u$!r@ !fmiOd Ro%Cg|R8ɃMm r^{%0$f`\3,&y@d;G{7׵@@4;;F4BP (mw +k 7)^46BDH:lXuI(yJe0?g (k'=(QH$v=50Ĩ]Z4>>G%$7 7M M?Q$#SB|5+3!Cw̋5c &D3*é7,1fYR\'6^ąX|JZ$9j^}0I ˦*9s@vA`,ȧjU~7$9P{[9Vbz 'H U5\f-*.4517XS=dY:k6F BjCN+ InWz  ϑH%celq>ANwu ǂ̥"DhbޓGd]e(Ӄp]!6A +Y fBD4QSc= Wy*t?62i7&/:tQ'ԉ-@w,8R( wT Щ^ۅ]'Ev>v/* ³%x6 Uh ʡ2%5W <޼-S}p@*l3l{M{03 *#z%OK'ߠMEhsK& Dh'\'y^6 Oz`vؓ ˓+ʞӗdw[+V UًŒFAprR[yVQ@-=p,r_q2 =6aMA1K䩥FRJD?m/Rm&$gʠ?` .#$=0ݙg-,k|3pE]؛,;0|l8yf M.:/e5endstream endobj 139 0 obj 3012 endobj 140 0 obj <> endobj 142 0 obj <> stream xZ[o._!d Z q֛ -Q6Һ=s%eQ Dpxs9!Fd;Y ?x3Cdz H9/?Qj'gtk>LQ1N/]||i|پf D_//W׿gR! vH cC CM  42 CPc6 Bag9,~@-HZ"ЏQH aJ{/|*Cqi#Bnm~W,D 02-|}q +`G1 ż\vQDhPpK:T  FB3Ĝl4ђ*'r5]Nڍ3qQ J5:@ vpޑ! b@3y{'!S 8ЄgU(Vs$DErs!6@$Ku^:tpIVD^:,`phVkneX_z 3&8WiatOp72b (ڦ[^ 6E ~DIkZ9oPKGvOYI$E/)ȲHNզ Ͷԝ,+B(pmvęt̆)򱣭Yy`OӦeLTVG$[Q9ANx)|l0(,3]--wcwdH|7o̴!unL!RTeEImBikx9}Xs "-_yy}y&$ YV%Mw鳾d}V~渧aye :f|)eC~6oHiQ)HÇR&'4GrĞ4S#Ƹ"cUXp<G)&DD᳨z}[_!O b͹r\Nފ|MTJ%-`Js~um83ۺV<4Qzdsh=qp{oH6>\niMz泦QW#v[XYӁ)2x,eIuA5rȌA]$0Yaf= ,QPh2R%7d a&|A\@gmDsj< ):GoiGe6eH 魑H aNoP5NwT5BuZko5zrkr 1~瑥Ӻ%P`ߺW@:l(FZFzZ#-LPߠbkiwT56߷FZ#-[#@ڙ,LNe=u}+&b]OE;lc2Qk%o Ndc@>ZWUǰE=R(f &"uB2[ A!"mA/ۇnYOĺ*Rl>况 .j7.iʨ*Nz8U'7Av--"|5Tૣ=_} ̞| P6C^A-ȧ7' 9 3\}*U#X> endobj 146 0 obj <> stream x[nH]죾>$v/3O=ZlȢ"Qw~V_IIb1@OWnbD2lg1{=8b43H*yv=32%24Zƒq"\9q8>8?xz}vqnIW4;;wHsË8JD%+7$R+"TkX1d6 ~M}EҊ0jY&F !]1"LNTAdn`L@6FZoW{Ti]?GʤGlVI9|u^A [qd~.n@ ^_ˢy}z7J JLpD# ZpNf哳RhE}uj`V?.a0CPW,pĸVC%X̀yQ,'bKW$3X]r#,ypm4@ &Acy;1ex1#Pa8RMs#e9^)BFR|rj(`}Q=|gwŝ^YWWeX 18jMuHo˕GBzf4箨jUoCďV ƀ&b{LMFɾ.LpP)ikרdvbC\dj\@ I5 Dgv*rG(b n27V$0cZ5..~]b :rv(1@g\+ &ٯYX?228}1xvpYN x#=-hg q?5`6 5\) px϶b41{MlN+^N#BI#1)㒻$s>?2GFFDMlq;`&Y pi/1[ʖxK&z!jd }^&Ő>gIA/EMM$Z`ABJqtx[ĤYAK!fLUΖC tpAvYk1 tތC^ 煹#5`y cPDg1N2 x=d3 R)mf/ɱQIݐo송S U'C^cY +g4^#uzYsl a,Ӊi]3-cBNe:x}T!8}7+e7,y2$S>O!VgFW'FІ>+OZm{ż<ďKfvs8SԷBBmMU{*6+ȇ8x(i$)KEQNF><9Jp&r0deڕ ȅ1Ų. ܷ$1e7kGk?jzM5%u`NSpظ/ (S iu7*1H״8L;aF'+ժ-zz\z\TߕoC8岨_ZDaHNuy%rfUpv ?p2[VE ~ %MA_[4z F[(='8}պ "].$v IP4,OD˧֎S+R/SO?/5iPj?> endobj 150 0 obj <> stream xZYoG^~}H ` 8ŀ0F^FOU3$ X@ϰ꯿jJ؀xv뀅g<?35pi`tsLS@[MfG?rj;/pkwo??_JCG`&̤ӏ>.>iC4<=!E349wyhrF4, k Auzέ)Cm~$a܊+M4waIn9]`f_ƹ!-O4Nex&S&9,%'Z YY-DauWE ows-G# ?xʏ"5GkPnIsĔPLWe:߼L@{w2DgzMcMٌs1o,S_h waoZt Cf[JaʝBy{:JbڧPk>:8:x?=SN>Ÿ/^ؒ}087 Srǫ9K7A nt>u;;=k$7Q1QtP]ԗADk@n~=.!,dU7~c0y R(1[g,[Bn?DX>݇FyU->q}\Ops8sru%aˬ)LN3xDMytW<;,KgX_(iR Ug UP: Mݪ,a}i7Υ)6eGJ$MLy2]pZ3bZ64̪[N5wEǓ eJo)=^$V3ñ:D0zoAT)<=.,!(;v5Ըx܆Ԫja ug$pUtDHɠ;KA5$ A6΀#S;0"X*W5k.`} il< ﱦ"t.O5uSRC PujT"){/V韃ux-w+Og Y>Y2thL C9z~8rv=A90f[Kv1g`ڹ9GmuSx72&|}'Y<{H}qĆ|b R:0]}۶ܥxeCC\۹ˣMufݶԙogᖺOi 9xJ25ŵwMB$B>XXi7* μPqI|s%R-erC sXS ZF\AUiMYn^ N#7!12,d[BPmvXa 9FZ[G@0Ŏ=cm!v]6e5̱gjME(N;9ٍ]Cp0{f ^"vD7MAI>t/7Yx\t([a10UϷMMP4 )Bq[0lq~ܥܷG9-EKniJK_ Exendstream endobj 151 0 obj 2683 endobj 152 0 obj <> endobj 154 0 obj <> stream xZ[o8^-Pl l`_$T#)ı @RaſlmmHZS̆oN/p6*r@gJ)TIJ2 3F$y~eD.x_޹ a )ɇ_?~y71BqzEd2Dr;_\ 88ZbCJFs"ވi 㩻'1$:_b1Q2w-RC5AU}l\tD3F47|YxuXA; LfP\KDpiBql%Zظ4Y%ZTM3ju"pYJB3H,"pI4.77I#4'^.,1.oڃQ0%B?oYWl <,lŤI.k:ii>㠽 iժW uz2Y`"MuJkG szYL߰l)pD$ b[.2Hf}e)&n 4rgH&5[шY`xM yWe51uU j9+&*,mEQ,䮌F2銵ZDicQ%*iGʭ?"sRiXPe8wdpQ/ o>?' 68>;-'DYIX 8BzH\#2w찪I'@2 A:(i3ӢM`3geE뀝73ʤ R@UͬohړVk7&\J<8P>-/e?FqtWFrEtƺɩHc-KkBiϡ.t!Yc_m~Иu0mCZ::m qL΃QDL Er*ȣMhF -HIkO͋@h$Hp; X3!W^\,y-ꦸʴ뢞̯ZSj&[܁֣x.sP,{u:Ee|a-A. 问m5JXbCQ; `J[{Պp9bfإiX&LIϹxZ  m=ʔnb'$m뤌Jj]FJ?0W8)WZ2˴' + +ǯb ob]Zlkk#F#rtBp4i렊aw/(#!$i#,<{.A;36^;w7(]WaqAq{u0[jUOEf.wo>~N$xp!ioÿioc貽5z[tJ e}}"\`'hy}C|h>EGilTF4 8( Dfw^Vѧ)*2\L@Bxv֐<0Lmc(E.s{#lyV6#`nr / ?/1JpTY߫9ȧE\WsL\(D0yր0UhFlɻ.⏔H!qבb<"DXuBHIfUv71+fuC,I)8<K)8fg2u5σ*nLi|_7x9DSߣדCHP0]1C;?p40;M<0}Z!= pL7;447ޯ>887zШܬjƹYs]nt*=ͨkucnOQ|u!ŹYֹ١1YֻC.ͺИܬylL-܍47Rͨ|j^l|B;ͨ|lPu>lnda@h !0wE&C+SKg{NX)+l@ {]A: ΧWxt=, fol!5s(]hi> endobj 158 0 obj <> stream xZn 7~<v/*[aD(zfNz")YZk`4{NnJؐd166da LOL qk9_l4%Մx1x*0_07Z"$tՇ'4*=<ď0Af&?==> a)✡8rD9phrF4, +iUb;SZ:(88aь"JVA$JT K>)WZ_&Su1 ;W\5UKg(X^4Jaè!F2ڴl9 r%qBTšeeXP("M72,2ځv6 qز6^MSLd j~pU= f {}xR2hi˺ 'Nq2!2e5G--h&ؐytY q /IsA:7^qG YjC#N!ч׈S@OWX/HAuPUVqSU@=e#w*e|2To*0Q8|$H>җ0S2gܧ^J!H쾲v @tptPYNGwСu%]O(9;AlXGZ[I:K߃*yt'Y<@N|YFWn*1Avt9a](@/sXfGt_Ve A9U3Z#`;!)Xi!Q'dЍ-t4wlWUn6jP  6 ܦ8d8qAm |qZ,g@ OPX(HfƟʢ4PC^{,y )]*ܗVg Y˭8vIɞzc< i{zV0A|y\>>([A+x@]h~3Y4WQ&I yP#nvЎv6;*]̦W6 '^Y 6hR__G#?$Y^K 0`}@Fn'> GʲМdH @PDz}RKEU"L0Ӵjx YVXqv4t &*c:_ 4 ӌ:ㅙ&֡/Dɶ+I:6w3x P> kr!+e7(endstream endobj 159 0 obj 2652 endobj 160 0 obj <> endobj 162 0 obj <> stream xZ[oHؿ> Hiua xA;6eK.fS;*IQh6<\F”FRɋǤ*n l𔖲|vV%׌ދӳo8;=W(R2\y]fL|q9[cg+ܯ[3 xB2RCJt1 Nf2.g/죄6c,gHegk3Ztdl)J O=G6F"&ܴmvuee/a[\;oӫz׶I3nuh3vn %Wk2~M$dAxɸB!c7BKI:t2AK$^,դ/wlyɉy6)(JmhSE%'q.bԌ&D~틳mⓓ8&,)yIiD2}j2n:K!wJE{gf,K`cyۮޕD\99p Ͷg c=(%YDhA_QrIyOܹ؄# NP Dv0::i;7#K*Bxo#!ړBk՟*Nv_gTOt?7VI=HftʴQ1L>mg8ɓRܻ8ʊGG<wiG JaG)1nIXhދ& {r#YY.8#]/:SJאJH6U xʞ.?88bQ<6Nf[@l+sԃ=i4i-"z㛃 OlxSpldE*Or96L0Hۄ:ڒ`ȑ^*s9)6<1'm Zpzj4KwjN\?bI[-6p*B4~^a{o>|ŏKcopʸe.TH1{j2 v)Mj|l1jmԫ QV҈~l cM&)RA\JA,o+ BnQdǑ*^خ$f2wm"H"d&FU^Y98f+Q%`bE"+bC.V ۜ}n*J d :3z96E?Bè`}c`HJHYzJ H*/t"˼DYs2w! Lg̯'pHn"7oY(b2^:&* z=rQr곎$.U*i'& {e"ij5is5EL's\L= D&/ڙ3Ɲb^W-`R-0Pjā?HU%<630m,5QGr"ď<~+Wv$]WqmTs9T6"_NMUBK Z[ywوrjMx[ Cr,wr턬ia+بv{]fp ڿ^=o/Wg?\} q T@FzS=)촃*1U_%{!ut: gU$%}RPtDS)p*XTS]7UᵂJEz~QP|KQN+*U{nH;u5{"x{IE( %#e&(a} G^:Jh%z&^x+ wP'W7zl7OBS:YN|bv0VIv (S;v1;餀vxI&W#5e!`"#gA=a&:t5NobXRNX1j_e9R]%xOu@+&ۑUdFQSwUendstream endobj 163 0 obj 2782 endobj 164 0 obj <> endobj 166 0 obj <> stream x[moF>p-V;5h;~ `H}%%*v|qQrv^yvZ:+?b}ӌg]rfULIQUef(Bj}-g]sv>7.^w o_-OeĭPN Eu\;x՛vϔ&Th]%IEz-Y"-iWnQbqߍ ~K2kR&ue뫠f>#%R43W0ߙ-ju]n)W  Exk}6AԀj ν~ٵr>mU_ԑTQ$m[4A|՝ֆiwBTZy.ї}fM6joAy4u0"BȤ6'(*qn}AS`E(-0#[,IuYA *ੌ 4^4V~/8E.̴.C6+6+ā@X:_u'Ѩ@uѫc6jU4ܭQ\=1`9u hMl4H A4qIPPm"QbiWd 3|i[ n>CCS1Wެ#nwuq|Ι2pd1 a*D]a]5{հRb`麗ո: ZjgD1 >|!BʱW\I{Q4*80XAsP."#mQVwЄ2DἚf;AW.8͡[:'>jr9h&睹 R' 0.埽99}ˬvo3zr9yrWo^~#8.loM%}Ys˺i,6PN2 w. fav(lJ| eƍ ӤTZCUPBGvȺKm]D=j$ KA_l (,l\=&,ؓ(hKF'(3{ftR *o :=<Ls PGƍ>ԡӶ|BYfz?yAxLGjWQ_P!ob M[Nc-CRRwng<_prS>Tǒ*ئzֶ<-rJӽ$dd%6 ]HA}mil)-Ÿd~؈+وX?&gzH6pakz0pɣ&对״AÅ"줣LdhWhLFb7m$vËR\+C~@؁#9rpu gI}4+]7YVݶ/I!]0Ehw &Jm4*33#Ýs㶷!@%\ ځ.MzLdIM#W6 Am> mE] _ssHtM,u aT62Px2 $njhݺh 8 ,1*UTXe2#pa@m6m8Wnx=1xqE$(v Ge]yf"P^۲O#ez6ȬMݶ:򾚢sY5E>1 A%0`} c `(u#J2xt T hSTg uRbε߬0X8} YHe /bUUsjњ<ʈPv eU#O6#cRetb[QVvu&ʷcnבw93Dˀ=mJd&==|HCY5') ,Px Orܔ_vי/ѡ.Kj!B<afbv[pY^P,)̍GūʅI*&Lп$MW$@UJ^`"E׿*& Wv>bܔU,@4]G* ~uY-eL_΄:t2t: mG z )SH:2 2.!+0Y)#fM!ʪ^Yf'fv!`sbq dhp d͔^}X14۶\yσ~ΠIK\Oٿnڔ n?Sa7SfuE=8颫?|7,:}^MiJ Ԏj _oX0XRZKhAPcGT`|`OQM|@7!Q=|pE.$Ę_3Sͧ]B hICgi1)-˾)CrDYzh)x|ƸYF5qǣ N V{ 3A2`g3&Fp쟏` x"2_?!,c}6a4b<&7p0+3}l֮Դl IM_9~#%>fa&[\AaQ]ZBTh"ZF rȹ O8^ڸqUWQ]ǰ 8"xbC~Cu:&i ;.AHK:cI%ٝpeb8ghoПٞ*.2tg lO,ry1磮w*kL{^`_phJ1:w789KϢ ƪT#EdץrLN8#3fTT:CGcbcv xl wԽQc(er}\M6sey-z=A| v*B"nq$i]xlF ]OQqg))Ğ^h춿G~=Meom_Č%9$S0 Ac6@> XA5 2A}ד)a`_!DByhuRbW92Qn̖eᔛB ?q/C FiF6\F6"Yd 0@)Ox_>kMZ9yf](L[bh7q j~4팹#SI3)5Ԅc^ť|Z*琘 t4w\sDAyVL0b^Xpīp;qgTjXk$i F!i]`46%e\/4cI`5;v0OyGLˁYQ+[kU2e~i)v'"@E<>&Q&Ll Ru[Fw'{2˜endstream endobj 167 0 obj 3607 endobj 168 0 obj <> endobj 170 0 obj <> stream xZn ȯ y\ EgH-10(eqxյuMj ]1"mlGַַ6)ŸѬ}6hfmTEkR <(m%,+mGb5`z5> EX5̯K)cKipxۿk"41T1f_0_:TkAҟGwK@0ؓ]2 A_~?,J)BQZgiɉ_E^>~}&,/wTpb(ۚ"wlj^ewi:hv.b"y MhEhùS3cHst 8qI) !$;fN+_ ֣e̝ ' gj$l0kz;2DQ:r{\dv*#'Gy.g'_| fCXga" #Ti6[!ȰK 0"t %MK05<KkHbpf>>0{ t ^@Jv$֞._W>DBL'_S-NCS6Sb}J?`.@`^>x)oaWP; %kܗ:`Cj9Pw{A`}Z;%-4]G!1XMi>^]y_X{៾Е5(aQ\g(dR; l~ӡ~qooz׃-uہ1˖Oޞ^A~ܽ_^_N͍q\1fo"O/>&ӫ#(iۣ# Ck#A|lN8:4ǹݛDž9UJȰkc$.u^z̸@EO9aO1[D6_xT % N bkqc}M'M5py|Gn˽{ﺷW@"hciAb'w=mk B;|ݫ#;U';aS_{c%(yDJ$*bk[xl5'" ZxOfbRbX"45ࡆRil^E*w6^"5V%\j z6"U-_GE5 GB%U͡7P&p5 MgX 5J8]k=kQ6^羦UyU؏@Sw?}.=\/ Uj{nJeZ;QR xĢvjеJ!vypo a)x2}u_̖*2 AAk\HǃuӌjF 6 pF1p:lXSV,j"^ Zo$G4S3:; aO2 .(ԕ2SSxaഢg4#&ث7p;([cPzpMI]\d9ċ?%O[-ڐU0r纖C)%&Vq4NIC#֢] B0ڈ)So~֦JnwafJqw4k["_gۤwg[FbQٚ^840 iGqL*~t;]o[$"i[&F"6/8hP^,Ѧ5RNۚW7]ʏ,Q@6͆+wV:5endstream endobj 171 0 obj 2830 endobj 172 0 obj <> endobj 174 0 obj <> stream xZn 7}<V/-|cˆICyf EɋEY]]uԥI Q_;]|?>ba-.Fo&_94r49?_`#)v&L&gB> ɇ_:zMiU{2;xƉ_aPLZ;xrhr|O6Igs#q&EΈŷABP^%Ƹs0eͻ$%"} '>{{Z# KbG\X#Mx`7ǿfU{|:?oG9xw Ʃ W]9qdr`5u3W+!T Rmv^+^|+5Dcn_Yq"$)qaq"Tß,ӣe]Ӯ݉'VOp 'M.&+b \PS<#^DjkV[.<dmǖ`tob[ *w zQSLkWtw+,8}AQfF~ż)ٍ@K'e]w!("kb(HA%}Ln(U Y.*vй.@yǫ>}4:dRWrZVM"dQEl.X `qBdG8CZ3f *:'yC62+Dgˬ xZp8oEǂNJvK"UBP"bqf˺X҉UşeXuTe鑡]MwD#@2X@%27D]M3I T>c@B7I0Y?_dU5Uw /`BZG^7 㾽\"V+R۾؉8qI1@ LXFZT] b M ݣi9+g/JZr8>+`U XCq&+2-iKGO'7W嫈XQ 1 Qۋv!$ Q1ы?%/O='%e|';x7WpoY)K@9@\gjR| i3"a'5 qhlK#En'M<+F-b('!50=#! J$Bq5<K Uft.栊U(Q+#yB4@,(*Z@ar=_5p&-lH1eKQ ֹ K.c^Й>8s 2eSp-sh~(ϣd s0V"']94v_.*EFOkvuU6Ӳ^(,RDn﫪)p`O &\u *%k`ͫd +G `#1lEA l9B ijf1e7' L iN# q6]8Tī=FBC>`C^7)%arCn_vvP_SA-0Rs;DYkj+1HP VTKEƴ O@jӨ)o'0x$5I%Nzzj@;IU^{p8^PS+1ݠ d*!'VaGNyFhB8z 4o]:v_M* z~6/hM7\C -J.GŬLL]WeXPcUߖ< WES,. f,n.ĉ/S^;I?Nۍ"WmΦ?rW~ 摪:NTíG'r+ haTNawU]&2Q0@cwy,/M%8 %DZA%{OU Uq'7f|ǚqbݞq^2E~c:W nc:(}2٠x`?߱:~{9 )c:i9[2!Y WWjZ`(Cj'Y )qojqV6qgQך_?H=cɺ>QTv kBAʶ9UbX0.4Eqp2#mlƏgdOf~ R4&}eU~Jq<ˀ<sK W]~`?n4#ڵs>nbQM7e^I$7i&0!1&EUl|/͜m2wXFH[vmE DDY"4A-UrsdT `.rڧgCCKN=W*Ew3iw1෾h$Z`Hr<K`(Syj(꿱 Uձ }ycǼ݊a{^ >|@(E3|ki(c~y_uB 'q7hK`3r]Yڿճ$VV]4rL-ܬg\P앎"1Q"zV4C+TLJJm@uپHT L,p5# )=ATo|;G ZbgAޖniwVe;KyL> endobj 178 0 obj <> stream x[YoG^~} 㾏쓯M$>ŀ1"G$woQCD@s1ɗkg4%F2RZ܁,6/F湇H{Br ߶n摐 1NsloyEAm/^ԣӛޏtda#% aoAIj7[;o!}wݤH\qdɤ^&2=?\teP_seVP2.˰YfVOq,akobqN4aJ$V*~U2Ule(r=5z+x`i=O%m ?||M@h;ڥW&C}MZ2+)u>v|͚ccjI]5iJ^˷%@1c R IGܚ Iwuj'-c 0,ҮM n\hҎAqF\MFm.׳r3NK3 ̡LZ"I!8b} ʤ-| Ȃ cno5 H\,<C̛E~ͦ ], JM>3 -=-!O"$]%,t-`Ɏ2]J@YvG Ҭ'Θ#[0YY b'_5xe;ʧJG@w|^Pw8!]] 5LWuZ?rpBz۽^ Pv9Sr% <}-F^%K7܉d߰P?CEq=^JB gML=HȁF44!3^WU5ԔP@Їl0A!W*^.8 lD` F =]fHJq{4ض2\P)΅[ T7ٝҨU3|5+Dؙd ;7晊!}f inq A:ˢ:57 1 ii^x:"`*0ʾO!,f B,(SKWϮ[ b tEW=N]/f%ӄ\nJb \B \Kn2iA9~JnB E3jڬ)EHn(pA1^k,4Yf3Kİ3}L\82ir)|1"[Ġ9W$q ? D\'k4vgS,p#{n0,04RȷlVYccBg)awzd>% R^7Jtǻwü@űJ^1*mС&kdRMdmG2AM8¬t $ X/|]1?P2m @9MB Qqd K4Ν3^L95x| oV+iCU,ldHH U!(^~x\BfJ{t`R̓cҞ]wh[T40rxV_u#Ӻ>yZwl'Ӻ{}Hn=1`yB`jRw􃉺t!z}$ {l"һuve2e%4%[p-8* v֮:A MhpKmv+mzM{o䢉"SMx4'IQ?@L$ӥrm+tΙ$ [m autdoHs .T4!=a)~(^uׄSh5oyh*Jb;P߮svT .Ti]jW[f:@\)AՐUM?B>D)-5~zRW3,|c$i\_z œ?e2I\Nhyq:w~"Y?>.*-ɦ+,2s}K Y1i߈0ajb- +7&$ơnn1[uP8Ǐqҥ54@ъe\EM=v \/xw9pEVòOh5qF@f^b'a up̙)Mv ZB+S HP;+2J\R%Mgً6[ΛybbqϠ\ʐ$%"L~X~Y9^f[SOW1MߍY,,X㈏>wvvr^^L@(bgG$dRβjm#|yv7c8i(1y@I+f_u^>חM.13`;BJ-=GHLVLM/m.0-H{\^/)maSh&56ÃSUvu@x)}0؎Lٗ1#_ =PyG ր)JE 4>ȝ0?7b2 Xn"9$.Oɹd]xe6r00]<+$ H$zAЬ0#GO@pN%%.|E]tk/dINN_Xp׋j̥&$I5^Pd/sKD)1a!P(6w'+$9|nOYw_ǩ ΟAf@܁(;zv, ޝk*`endstream endobj 179 0 obj 3429 endobj 180 0 obj <> endobj 182 0 obj <> stream xZYOͣe e}AnݞOm1AhIT:wT0"Cl NCxp􅈡AFRɇ㫁 H9Ln- Z#i'_\!-`x:8Ȯ$*x|M*Dᷱ]v aK'vd"a; iư K!ԘD(7AFN5k_O$Fg4uS_04Q3 )L{vJn<;7v4&#XRS"į+uҤZ/(R$a EkSL;2-n+FB$S7N3‘Mrl`QlmH\uȿ}wY%<7~zx$Kajy( M!i185{neO2SJu<|6f{cZc kՋYV9sbQJ&.g ϕ膖V):9PZs 񘪜u11ƅ|Z( GVU^%K0uA$tle>)lҸ}*YTTY˼X\"XZ.\[h7C"/C+IִL9F:%e)7qT@PQS*E"Jǧ[`eы<9]ٯ`b`7:^zTMeˁbғhCuBvCq'͢.DP5W/*];| uT8ߐ 9;?N>I{wd)(w/R2SW$4F2^S\\6bK5vRxi}p=ZIoT{g;)jCDڕeaL>XǠsf{R?uBkSS'T~ܷXd/u>HCbx/C>L!^ot|PAmkws/=ۧ[F{ef2&ɸ́m{~'=@tEԿxR?Iѣ@ML9?j땀L}$pxץq\g9(Q],,:m6 ?B+B:!Ok7m&CgeU_^ip!o/cݞ<]ꝼSW'Tm ;.F;DžaJ.䥑-0&mK6iw4Tu!@\iXΫ:M(pvi\ E5w,xiA|cf#~{j \ED(ޒEAxxgZX~uXDэ#2f'|i !1`\|j}}6z1o:ZJťB9# *̘tuoPGlJl VAX\InE\I3PC 'K"(endstream endobj 183 0 obj 2430 endobj 184 0 obj <> endobj 186 0 obj <> stream xY[o8~ϯ۴@Êxb2YO@6`@@DSr%{2P$)KqR"h<;߹2#t?\81ZWf^lfL泫#>jFa$ͤ0ZaDWjqө!DHMKh3N< _%AP ~kir_M c&,~6T8/v#@< LWnd3Jǜs")8?b+[[m I.?҈ ue4aQ㗾T7绪}41&vU,~(ɻDL 50:Hmu|"]0,0oSŪVm;JJsX1؞ѤF>]QWÍT˺{ ud*xday8yU+3pˑn #cNpڳ!Ήg㊡'(r:!EAfC|ѦmcWՂx1½n<c׸^vMg ͝cSt]DK /84怙 Ot0PƐu*M|۩)'c`C%ޚ"wMüY>v_]q`Lퟚ mr᱓HEU. 8Mǘ<_< cTZFw+` &q\ Br Di5*aPq$EloN1zYWg!|(zw ph 1j 输`@ @E A1+dCf tȤ!Q"Xc"[W^zhbgq/#.rQq+!򘍶MI ls[ v@^[bԡF"F$CHb)a uR` Kë1\y@)$RN9UZ`La(\pCGDMNdH)|xx +St]>Ns@ ݁Mmd4C*ù|=esGYP֭b ƪؖUY!H~ycbX<ۭ/5X_j8/y(\`Rzq"IUء1x$YsH 5qAOkصХ |c!:vN5.?ӥu&:aLjQĠѓ?*(;G;%i7LT 2*CT1t #Y_(˲A<nSfx[,E"0?i_.@ iSn:M?|k+h7fU_GNn M(ӗӯg:)oWw_7뵻gNG[//O>\|_cqѶ~uCdYqkt)e ѹ8<!<VXztaM^ 7_|bz\G2(n0># G8$4Ka7V]v [6'v3ʾL61j8o٩Jf/prjÑm"'%UO?p2M9 ɑS3U2 .}Dd^u0cDm&wit}_ΏΏ ,endstream endobj 187 0 obj 2581 endobj 188 0 obj <> endobj 190 0 obj <> stream xZkoV]G  `3hX85Z-6R޹DqP{Μ9sfRC~?~-._LV1%'zH)9TFTNslyih]-2A{&>Λ͢ZʘVeZ/$,eN65뿅8[Ai˴&Z}vrDF?U}``|Kl(iM Xoj7mպnPJ =L'W | ΔO͙bq6a?vv^ }yJq֛vݩBr;oًM~  HNerLGX>iOW\]0i*4i Lϩo$uw=s) @xX6>{rMxX~VJ6ֳCgXa jqjoeꓶqL @sp)m[7>y/^7>P)xSC3Хp׋z]]Suys PrCU's̙,ݐEU,{p=+ag<T߃o9AUxGLjcLNS^΃9|}@˜de o{G e ZD M *b-T¯^ւKzSy#f FlYQuHNx9@|qס2tݴ_6DZ:Qk{K0T;Bf@ ex^WCK" eqXQH&#qZu]N0)DFaN!QViVݺۇ=>םZvJ@Q۟e'@Й~Fz}a(:m2 xJ2:,dZ |ojfԝ,R2U\Թ\Um炪[}5si,]ԩ/ D1 f8\"=UTd*{e2ffm6b "\zuV-#d!lrkre>pND <0$ D0!Mn+y// h"\eWD0y:&>SM)Ї]m.4 &**3t4$C_$y5BD $h(JX1)(euY5\JAQ$g_z>h\ ?&˗մYT]G%T!o Jz~X,)óFhwهg?c&Qix+fՄRʱ+beCκlB05L|;>fN$/w^Q\YlvĻ[­^:MVڶ X:+ SܿGIUV_"NYFh"-#JS[,CqXs>盥SQ#Y(驼5o6DNlR 8ǒY;t ,6ӄBE Д,FbjZ;Iݷ;+Xn%b]AA$q>ZhX]La#Cuk!i 1+(zcwtf>^&t*hF|ƊV{kRȯܣULM(Т՗?};˅Z gߩہ]a ݳJ4O)uÆ j,41ϷK3ZV Vp٩o,:< ^ ݷ"Y$ÇfM0a]#C/nu ש-em + ᧢|8&_lzc2x;Fn{QtuRS++uaQ\(B0jA5MCS轹Oye=ެ*y z(J*gu2P=8wԲ-aUh-^=;pq?Jendstream endobj 191 0 obj 3160 endobj 194 0 obj <> endobj 196 0 obj <> stream xUn0+tLzCr~>/GPR\HÉ+RXc&r`Hez\ v BM3YSlSU*4w"MG=Ȍ 3jPzt $xFܱuH8 \xz򺧾-dj̊yogu=y.y t9vQC"7qHf?Ky3]%L~Kg 熔J#; )]ΌV*de-"~LefΫ6IĔ̺,.w~ϫE..z ̏n]Vqdwcie e5[`zyx%&#1 õݴ+Ity*-yen=:MR̞*W7- iMn:}#5j$=Q"ѺiWuD0NȪͬn:o;/ mOI1)~qendstream endobj 197 0 obj 824 endobj 198 0 obj <> endobj 200 0 obj <> stream xe=n0 Fwc"%Q8F)oCRˑ#j>{ {s7J~3@@Q H$&.~7QR0DKZlvJ(ʍ i;Mu&)fn3(j]?W#;2L mXBXK%t^ 1K;endstream endobj 201 0 obj 201 endobj 202 0 obj <> endobj 204 0 obj <> stream xWɎF+tXޗH`-pHjDb$e'TZaÇ1ZZ^zUYc/OOkҟuzN5HJ**|@Daվ:Ji$pk۬1w#)3Iw6 ʌW. "~jY4?vq"{ P6D6L-#CKj_f IF;;B۾!NmRN ݴo>[ ּ~@Bd:<+]p ,mx(qHD_! g)CH:)͙ ca׀zylG3$)ɊwF("^g+_@Bp釩?GSdwA yl]"yߦ#8KJmtKCFHA7ІZ@mPYpO>&[#ЌKJdx(.o(NxFUּT@33_wJyq:.ط9k$'4~BaPAT@SL\A[IN~omTA,̥&E%q2 xc#/"69L";LsGR~;<9zei ɡpR)KP a@P=`(6i4,˺WcHy?o68Ly1:driuẂhtK7]cKz# "i*4#8gD8ĖT G)C ``"~R*kҁQv:7㌕"ϧ "FmWsBI,),QM9[Mcm1#e'x`b!wY'{zgFHc2'㤇&(U%3ʪ U<ڱk_<Dh@:Z_ Qs䛢֖Ī7/N͠_P[]w|,Vy4A.u}qH6 VBm}*ɀ0Γ F)uib5H$tXp[;4/ # ^t {sAwv<'t i'mjӟaAZ;_,*H(!9K $eE=l1~5L9A@VEf!лčuU\R 99?rY텸\Hɼv5\tN*3Bͨ1mEfCxeB.B>?<9sqݧRL|H:_ʰHxK ,#4h0MJ` |^*{˷wqpiԵ7R>VV9 f:W/eS{6K 8ʉv}_byendstream endobj 205 0 obj 1610 endobj 206 0 obj <> endobj 208 0 obj <> stream xZnGg~`0}$O$aX@@#kbCϐ*[}r((0QO:#R`/nF_G_ şMv2z #j_ I]H-fW?`<;awp\!-`d>zɐ}B’׋CJBXyc mѯ2 34CQu@(`9y7ɾٮK캜`_{ y\2g¯2|y3 9&_{Jq?C ]f])%]$ea*~?`ȯ:M !\~g~R\@-\D]s @\B cd=9X7r_`{{~~,6z!!a3!)Ə,R }} 09}ӛ4eaN j2GuiVu{CM'ַ.ltu'gFQ hlv-i`* Cw=t9UIT vރ!O5~Cb LJQqhY`7*ti9e?^VGZ_FJfZSß:2SG;72EPnkO MhCGloste[)J&溔HRMGi6)mR7>"98$2 Ng:6ZPoA4 7 <uۤoɩ誩n`!]Iz* ڢN`F%$m/ 4|2n q^:x-Q0$ 2$bDDzA5IU8_d+,a%6+;'Heh}S-Z[9E%r:6tTK"jN"Tx&_`/׵Oyqʺ)uX&H'7if͢\5:1jU9F(Q;>GG&}L T)8  LB8Yj'?9%W/n>or0S.*-f}#L}[QϺϳ%er|̓,a5Vr1Snʶ /lɒ[ P&a[B8tWV5xtUCB@DlV<`A"EjҦ61Ԙ|޸ 0*1|VbNwzЄZ뤴cc6ܳC~hB{s@!cd`}QmzEeY7{]Š<_3feʱ@,cyr,fשܾ|S&L{mam=&(IOP JSLN jv;.c;Qnд{sHt| y~cřpj-;ћɁCg鮅J7;[6 &kBvuP6<% J)"Z,6iX;:9U2]j>Jxx钨vͫ:H{ ŘEL:AD3d`H]\3@S@ލJr2l.ϾƋ:ɥO//>Ջi ޅ:2(^괲 NC[46Wuv)boԩmId)IgN7*%xh+w(gW X)ʼӫ_U34**Tx d"TVIQEcG0LN !U ݋]N7<GَA[K}r=*ʨ Ϯe'&upz o"I _nE2#2i#DQs39b<ǚR)]CGfP?EtɁcgEQfxj^̂Κj 3no`ɖ-o ETBT{a?IC:GM ; CX}] t-t-K:FhP4ۻڷ˞&VZ-Y€!,Y"&2^TAS󌀆е*$u_|QTce|^ Wgt8z[N, FG)(/FKkendstream endobj 209 0 obj 3017 endobj 210 0 obj <> endobj 212 0 obj <> stream x[[oF^QBoM9SdiuQ,`%VJJ=Ùsf(Rr-\LMsl9y?y?e3[N.'/ >\̈́i3eQgOuaaz<^\oLB^t,܊-,7"a"nf33i7WoSAZ)Lq+[^p6ʬ2f@b@Hg瓗n]5yM^~WL^wgw1TVt14qwH _wDDBJL,KDz{PBD$˳DzuH&kW83IPP\8ߙw &T&P_W\<DҰNJ;H +3Y%U}jI9?\O-Qzj:J zLqom[n?!1k(xQؾe : !MۊDARY:kX +sIwef[Sl ꉵ*vPO--2#{pW/e&Ș!uVsd<[$9u>ALi#2tuqֿ|lA9} gn&7EX-U 3 ٪t뀺\Ͻ4`%A t[Yy}k@ʋ=,ׄ8u[9 YIF)8v`#fQ &@/><$#6zѭsXԫ^^_&%erαhr`I^=_]",7W/)iKӆH՚f5ӮYΨO|# QH*q\FIBRnC\GCkT v㽒 .[j`YIj>BkBJ.<Ò2U"!a @bH G,Po} k ?>]nGvko‚ZI?֩@ ):PWj?Zq0Y8ccVDK'@=+by<#Y$h\o=1a7uBh:+jGqn`֫Ͷ*羖94P<(~#S!~ۦĄ"m-* U= d# AF LL99k2~Pd'{$ ۹{nC{ Șd_{[ȾL@vdq/C.>!hEAt{G`=S^;䏨@o~8 Q?Gۑ .,.YH71{U7ac`T{eBDv,8 ,Ӓ\qLq*XCk-(㸦FqluC^ɑxdqi :"(5$~ N|eԉI|U>ȃA(U8*j[f^DcQ!-wTQ7Xdb5 eU/@KZ)#6,m~!3x8^\y[lRH V{]>#mBdVā]eEj $dH6/+p.BbGfwĮ[PqR"'5ҏbGtN5]C 97?8􁮘!PhZtӐɚá(@l+j#)x lJ9n2v8 ݞ],oㄾMB9&?XC قHmLD=Vl[Czޫ&OA3\m寤JVw5В^J9 -80aג?\4Gk\3`z=!b1TYb̺l0V[|jT5@g<6^KP;XSզˬj I#M&e{$ٱ7膏cQcci\9W>L |O>[ V^)/9HVdD8>\&*.H =#`,C"ݜbiz5ZIM ]Nf,l;Lbn"hguAJ7T{&ʛ*)z7`){mY0$`"85LgfWJB%k&P 7!4?qcC=Omvc;I+kA{ #9AŴt9sp7"JhdTr00i d ~"mPF 'NH6 4>Jʵu͗PP=J=~#эN\e=UjV_0fne v!Bbq[m#~{5~8v77ܯ<U|^;z/eQ~ɘ Р`̀q7oV6ov;|ҳ)o"{.vnYihAj\]׾F&O@Tmʳn?x<A ʟ;,SmG"}@j 'u#ξ(gaMs(˲uGܠ(~f+c+7쨒QB( TVO䠴p K*wwzժjY2*U][a+mwx{g/S GaTWQ_IޫQtk-O}d:FvOR?&i(endstream endobj 213 0 obj 3755 endobj 214 0 obj <> endobj 216 0 obj <> stream xZnH]죾BsK-yztӮJJ"ZK!.{M\ZVuuH :4_>o2Kߓtb1G>Z7X8܄XW?,X庚)&@f^.u%]4hv63cAX<͢/Yoͺ?0VN?D1!Oi-V=JYB B|æ\iAr`&@mq[Rd OŽQ e,Z܆ݯ\ySoSPЄC+!@NĘqAv]d-A͆(4B UH 3 ^nxd:%PH.1&O ^ S,穡$sG/xJZz ۗu !/B혝Amݔ;8:Pd~௄`dÌ.1"uP) {,z`2u^  BR'pD2VNPrFz$ Źض`MqE,u,#L80H2IbY"p%%;l& ne[ՑeON^AI537e&#םSHG >FcS ʆvYb(Rqk~x4KuYK5C(BCvԺAHuuEq}4-Veb:BtWD_cF"MpP7禌jv? Z8f4@uz0̎; -Uh!cI:(dyd/C@*w1f<-PyF?Mג Sȫ"-fh`!+?Ă+_4 ٶ\_F$@J"fyK0a 8:gE*( G=O(y^!TYɳ,dYK?H]P=}d D[IKASb41vϼ+ly,e1y]H(w#Ng^=/㿍N}띈 QVFqvd\ mD|Hr9utt˘,0`cX3H+k+P+$Li[C@fvɝArT IKy%&%U{ġ'`@=plp2NF:T20q)-vŝw@%|(%,ӃxdHpT7LwlL1ݗ鎌 i@v+0Yn$LA^_C FŨvJ1Qdߥ ݡ!yH ɂb> IȨ 堪1%92&(- ~2l8YHqCͶ^ pkBIwhfvnRiOGRm0{egHkG֯5(2vdHn{8 GŜ7wnmCw7$'}l8Lȝ>m6cCWa:hCȸH shBG1vܤdr,7-<[Y >c縲9?cs&NpG lp:h1 \9 w4° Fr4e^UqX5PIuWP/]bMt fw#{~([47|ֆ1H.p`~/JͮR-";΂GݰX߁]90=Yl_$endstream endobj 217 0 obj 3090 endobj 218 0 obj <> endobj 220 0 obj <> stream xZn3@V/ `{Ā]Z #rdM›yYcnCIԚ X͙u9U]5>ſIkkkp};\u״3xPjX_Nz/zig/GߵpD\6ѩwg&\ըsH'@PTiwR?o &Eڨ^6_u%kb3Τo41u@ݦ݂:ĺZ6=\% ~Xvu]/zcKvzաqs8/hk&*S^ uFs Eu,RUbU=YԺ|27gqP%%?Mguҕ`UaKo5PX*Ci )8^`Xt8)E=#S?1IP1pLtn^Uv JAofIׅQM>" [o~xoaoƅԹ7?ޟ?zL#2:˗fڥ\BH/yQ^|xzޢ,9·O/Fi(Ы;kIzw~s z|/~zK4Dmrgޟ]$i#yKY&pP~A{cE+$U+#i-eD̊C>sIR̳5@:s~y$NEHڢ":rxQ3:A<%`XWq+mV}Ve"i8'ĹU;-#9)#Zf&fJ(0Or 4fE!@uES]P<@Wp:+T_&) r uTBjF*lv*b=)X(2lO}֣uPsk=I(WeQzc> < E KiSOɑ!: AˢOC/=υ6!AƳZ)0JWk)p}`9u3ޱJvŝyP5[WǞoӮ!pc(vL>6 TE,Rk5&j=ޫT/o7.f:@] jr/ }Y*>nply} }\=c%YȘ=Fn(_TU (10N ]<,6{dL+p Ͷ×&,N` +1!7p1= %G2 PacrRi6aJa p "o=D;dDendstream endobj 221 0 obj 3026 endobj 222 0 obj <> endobj 224 0 obj <> stream x[[o>+F:4}o7G@VDaW+Ex v&,ZvWU_UW5!6biiHX,s"iI%2$# e&b'(q4G/^͗\L1Cf0%Q~k3H T3?xf* wa4R0[*H3M gΕSňH,"7êg+srѱ QDQ;A&9m ׀C i\6T!PQ&j(j5w)B8&a@6r`)i zZmbjf =ۥ(fشpcsK{P@~\=uAw{$(XR-c&]-8Z}ڮmbJ|S2p&˜͹f+B֦o )pnߐ4 )(pEe]ES\kATs@=KghHJW3oz3mׯ]" JPXoY5[-M!=lMZEGmEǠ98ӽC!%viUQHg$(z5 !Cm?jF1X6܎3k6o7UW~~BcPy II66nP0MeP}9 8$|>urAbTx\v\ s,Zܗuq;8dk ]4鑄؊ i2ƒ I<a ;o,ζEr &pp&LvYܯe1\-֫r])pBxL!)e_[!FBdT{%8=1@q(U^ʿIetvo,Rfl$h Cxw!$ ]9Qxͧsgl$ I>xFyT(|s2UM_?) o;bz[)x3ҚܰrI]3 y}Ջ (ޠGJL(B3u'j6q a+g64, M[J<A% 0g HPR ڽf kV &QzvktFetG$6M* l/϶ѥ8TPr{ l@ A=)@iI\U"n2Xeu`D7OVKnJJ\~ &8k6Q=(o !@NvJ܄ )ZKy"LY9 'MIpdMQ2'f`ϤȤWp Dx< %F⫢@:a= L658lR6]w4U~0 6/M- W kl/*iH:Hԩ>@}"'+mj&Xko _T?Mi&,R?+lQU{i3Ā}ۆxyG՚R}D,n7Kzo$to\fIvPyg1!Y*oDn6̡fIdٞAq ͒;\a}:9 :wKL/^-]`?3uP^I1ݺi40]1pVǶ!$b,1nQ}3tXLQb}iN+*#_Ud;S1u6Jvfk UΓGi^VRs%400ibgbcL6OI(Y55XɺĖCb:Aa7:~[ `|SM%5`STcun\RZFۋ<6GpUaͥwLem> endobj 228 0 obj <> stream x\n.| 0s@DH EcMd6$!8k$3ם%wK.TpwsΙ9gbO;~4$n,χond$|x{7 5С(?׌ó/ ABX1Lw7vİ/` Ra!TW/^솈Āse9\ D 5!o!pD{x7]yQlJ`H1_8"k_O#XP%#Bt? ^\e*_ygoabj_~ۧo.^?}՛gs"8[.ͷ 77is&slc aʤ5Kk k%<,m׶m` Qyi(%0M4Qѐ o0&qj?=nX] `:AUՏ~12O r |`1& /0&i壐RbNygZ@ /=$cQIŘ=~jAZ ]VIjnQ I-`q ּ-; IK,) U+7ƐlQ3: Ij^Dr9R*tQfo4yF L'`!*9fx[qVO- -,I +R݅cOM6*=aYFWb 碫V)vT;zML#u7]h)z.b,SܨmS[M2DXRrS|9@$E bRH})b [B!X{T:62FVB:R6aIu~ūEdm*Dd2LE1 Ҙ] .T`r=X$^Z&9+NIО "ьr</=Pna:,fU s@A@"ImVMCAA$`GRXOk7 AOX]#t^ J\r0#u>o]NIx9΂ fWѫ!E20EWfѩkC|c2mƜIwHu*gC9x }c՗Gɾ&"ۉ$0s3Q1=)' $pd9S56NFl9y+V>X I}ֻ~(m PC(S 6V$pd']@V.(DD2/ʻ?Y)fBe,Xx5]ڈ܅sN5£6S~̑3SM?uZZr'{oDF kH{oHat=ң kLcߠ8G\wb-ю2 I넉:ιvL%?6q<GVߐc+1ݾ[}rrP ɦQ8Tbkp@&{ r)˽3bG8aoL #MY)^R IGڿ #.dJ(zovŽ H)3RLMN>-*Zz' a0kQAS@R_߻#4n5w~왏2_@F7̶ϚI4);IS8)3&LS 1{YoH YrLgwQ%:As\ ډQmHכtqzr`%Fz3m~I p 3*q:֒F?RxLGWж/JZ/ _%Ki]Qޅ`\w*T RuP,ݘf(P/M%r0Eh2nO&W}J3-觚So{aQ %7]{ a*4`[e1˒:?X AԎ C$pe r{lBfK6>VCyVS AMUgF 2)jС@,['{et#n[ydJK h-YNT ńlt[!ӝRvv}[e=VwcX'rV o&^K6I&ڤC6Fp )j\Mn' b}irr;R)b(A_K2Qn1gЩF*MɼWLMckl8 ,Q`$5kn<~D0zi&?Mq_5Uܥ)[}L]_oVOBːf][FW}%?b([F ۤvj2 !x4aUjܻXݓJFԳ*Z$ᦡLrW@J). vi)w=Ph_’=DK_zZyֲLf'J)nH!!Yj\ON$n0/#H{5ZY LǞ m1KW6wƝ!m W۝ZE=^WĘOv!~,Y8E0+|fe-n=J|T;?g"F$8Ln$4hNU5+h}>%t+Aa,{( CS4ܳh}Ȗ Iދ(:Co$-uZzՐū(EH)"Yt_,Gz%jmnSDNg6Ic:dϲs~N.>[mrMAEor=R:evwRN㢍N̝^UYyzg(.YyoX<&9=gS=s]x/F; 0co{Bbk:ضwլ*/38J(2xm0O7C9d< 0 ٖjl@?ܟ0 /җ4plYz(Hj}Z-ֱ*dȹ/_8FI׃1endstream endobj 229 0 obj 3539 endobj 230 0 obj <> endobj 232 0 obj <> stream x[nSOA ?v=l kWH`@GIZ5N9=Hv`dWU_]`a@Zs}?xu✈FZR7{d@$FB""{?|7S9Mѹ%WO DH T3xf*,sˆF e4RtU&fKtt98`0K(_شW{/1Xދ7W{GVD(68VAv:"E`q >ͪ갺ݗD<*wG5xopDҟǰ/Khwo J` hiEPEmrbnU9H$&>E'gʜQxR!MIYե uX3_a(l5;xT^ٲ!x8V&;G91 yx/m@\"h|4Y )آ*Hfu5|$*DCW`A>b`ONlf4GBvxcD#.Fr,30x#˴hY u/gZm]$H/'H.?$ҍeT0K @ [l>We'{S-X b:;L)wQ3;(CV)WMfG9sU zŘIn SՍ[drJ`N%rv6.Su7NʃvwEkPə^z*\bl 3b:[˒1,xi ʈ" KFU`DjC5K`ț&\.w-'N_=uR(({+5{vt-{eF+BZ )WwN7+P~;! Lb7xɌ޲Lѯ'ܐ b&ZUo/ ".Aho WP)/&˩?4][ w f''";#ad;ɘ.y!} {pmonH!bjͲ̸,2Ƶ N¹JT'_3c"LZ ~s0Lc8ԫ2^ͺXbiх B]ZvqiNmnK8w7u4[.:wբah9vx.'vHât3Ab?)|obl8<>!t:zX;K븽b|c2vMg}Ev=2'Z" o0 -.wY* z a}g<}w{y>{PK|Y ^\٧Z;^ Gg<Dn]G‰V,t˻ÃˣgzH0c3zzr#36 rU?_>zJo9fd:U$>ycNFptp7GFEB'Aöվ&} 5p*3j~<0U78`x#ZL;qګ\s']DR(g:ߘ-vXqn{! '2wH& j \7WC/μaZHtjp7:S" E: A˕"Ml0ޤ:/̥j ^0VQjRR+Wv_=g\xPqcdStB SF 7AMZmW$IU.ǟ+iҝ,[5cU3+ΠTH*?87=DiCITWEu{Qʍw}a臏;)L&V݂Ԕٶb5ԅ`ɐ/4$}262$c;p1Md@UvItf vgXgG"+4}j+HgΩ8"xW(+%P.e31Or^{ =,n3Pȑ]VD`\vZڌ 'CQzNZmPE ͌Gwi¨ހ3ep,IhEGTh$ cPjN"֍{)z񓂅-Entj}  S!v"LR;EcBiC{5$p(1eP7U0{͑o'fYa@s+``"ఌ/𶼪R|0v'ɨN1ݙ$v2 p޷a`"'pf'#wf8,ErL[`xz?e-Z)Vt*;)(ս n=ٷ{)3,k9ߐxmWn'Ae?O9Rn]]7Nf'?)$i*b|į@SҘ̧>F}o}6ٔQT#Ggftٯ05{̚BƫGM<> endobj 236 0 obj <> stream xZioG]G ~[},%: 6 HxGp~V3a0 =կ_F?l}n}n7nѶAFRݻӤjxQ"CRKhw=(E1qx;h]_A(5, ^!bO 1a'$ !Tũg'g~!c$(+N8/{0Fڽ RmZg?E:MZw陳ţ!Bm<3ү3Լ%BaY ޑsU@ d瀸DT˕P7 壕b(&HQ4^Wo(Jީ-maǓ2tD:!aabenJD|5f6P^)o`C,XˆFd#eLGwlw?#nweae|tv ܑ̀te-Y97G^5RD07}5 y>D^(cK"qs+ ^uB!t-4Dw݇Ə^k$M?O!ASɐr!: cTF25/iT 'n(iwn:FJIgѦJm܂tTA&(AM} K l(!4=?}B>{?c &#o?N * 9?:u%'cۓi1loP x59Ҏv!{x .ojޮt,2HwDญԿg h䇄,S}L~ϖ7!BV!KA3Ϩ$nRXJ~@f$zhV2,y\ (m5S@e5e:JLcHbc-)Uꁱ Nz,f"R<Ϊt&T:+zيjKDܣ@ŧS>5eE]$m* B[v{7{;)&t\(unIXn- IW͈Y-_$Qg/jRUfM#圈OGՃYZ@/x<(sE ZkU^bbguLb1P>Ue &O-UI$5B%a_ #%`OJaO n)+ۆùU*U:2{%z/(i@ btL3e^IB@AID$FM ㆽ&8b`->&gY LиbϩݮK쌛(lia1 oٞYȅ9]Yf*ɒ6,k,86A|;/mS*(Eq"*D`&/W  R;޾6p@ΐ=l1 fendstream endobj 237 0 obj 2493 endobj 238 0 obj <> endobj 240 0 obj <> stream xYno=~Nao{mqc; . 0vJBQqwkHtnp+rvv3CJؔ|522e~-4r:ؔiJj jr?y#LKgoNf7MiUl19ĭ0Af&}~9#g".^%CI 1ApK1Lд{$p&ԐPƺPpES.UO`d2DWN--gX>=,OC+?BR*ëuq{x}ً Bfg?^nt티mzgd)֋:w~;d4~;FАsMX%Pe&KѷoiCqfqY(REX~r:]=O1heD39)kzp !/sⱤD£~ d[R!\L;_m~]0j\Ţdqqה 0yJc ҫM\XU)R}ɨME]_5Su?.C7u5/J֐O7% 4 PlmIZM!_Ć$M؂Y"IѿU,Ah> ( NzQ,>4u~pk @ޔzC~CCA-1Q)ݧ|ܒ{-y* .}^ucmHXHM12>w|ziYЗ>@&,,eM5-m7ż̗p1)ΜYm݃rQDZLAtjy:dXq_vmp)=5pmr΀=/TN?')tB[trk}<HɫNi-(V25}%dx{);tLM$|^E` mkj a,6`zH_bه[2YbPgTu@aKuO1=$AOyF )oUSϬLը9nKI$q% P6#JI)(ɫ_ncјx G;Y$ƚ葈bb&ot {*Ү.a4E\E>PaT|#C|+ꧻӦTYè{2U)!d{>1;EwTw c%5L튙&SBr2Fz2=5H-~«[e^G`J&LQ> endobj 246 0 obj <> stream x[YIg KH8<лJHmGn~<"..FH/"3(a}> cgtv{V#Ns-{,M8V@PN]H+$<{1=|Eds'?d54d!G g~Hi7xĀVJJu43FRܿ0BME b?,1T#h>̾_#JsmjaZ5nWm@[B%?\MU0!RYTwUpG4&.L!%릚NWV(c4>8Q x240ql}ss 8C|/h%L16|~L'.}*YJcjTV8dr`*рX@b~"+x(/N̂\dp)ԥ(DNc*CB92:;FgGN>GKHc[7r4p(Y*bJg w `~Uj~B c\A.m.8VYD9LHIpsnYZgp=ҒZ"2@溚@+%q!Jl6pXt:OGoViyeȤU"|("p 3 HMgg'/=g'={;9[e Ʃ@%8A9=0i`~.CQN0UͲ 8yp2l]+sE_ 0C1-w@v{Br :Wm ,d a Ve]ͱZ B; | d,e׼gO!FRø;H r<*E,uHi&Axe"}6OPw>ROc9} Fj ғm%ؔ{! Mν[K.#̿JQ+hfQ2BB m hkK! RK伝GZJ=uAkI],j'ڂ\=^ `TMCm`]ykf tǕ=6%Ό.GnNO A uLodט%%o,1(ϒ~ KvJx6[@Y,Cpepp9LuÎwߧvbT[FB_w {u*X RP諆uvX7. a;H,Ģ`Wp敮!)A6.y)=r`vZI:{o)ZYAuD<\!I6BVt^?亍:淴VձS@]qJicχ v 6VWuIsH1uLaZN3)r?꽧Yf UxkHPU8ꘞ~^Wk\cvvnXPQQn\6L5(aaۈѻS ?^N# 4f%dmA,! 2#RYZIi ;yl|x j\ jhJWaނv.d5f5bwq؊ќaQ7N59۸0Z櫺7')BJ[EpԬ]As;_C/2ygêv5qXm[Th-횡,7X1ʁ(2E]JqG L@q["؏.A`^"oU5/:hy>X̕R<_NbbTb)zI$ȹ9:tfaFspfo2j N0Wj4{r`L cH/["-k5.Rw'|tY2n({ERn9I }[>b͇a ~mW(-kCW&ʊoK̝å14sWϔa̋³3GL=NvnZt1BNkBq'm;LKc>wZ=~ lk0w_ry*Y.ch=>cZyj[Wr5j']l뭡5h[?y7P\3MxG&P=IMоYj[@3WzVm㴠eU=#d_,+r Ϫ d#lZBrJP[[߫r $YPB]U.|X>H+t6j] DZ<*>*0rF@KCa:Əql\ 5GTg!F%pƠW yF슃MYi@% TZ7r|cyQau?a]|\b2%Jfq彌 *8#Pf76; ֦2o]檅(=%k8T/yovDP"WDNO;̀ɧm[4fW C ukP "TF. بNiىj6U:췜 OJX}La8~+xQ8;)DmP> endobj 250 0 obj <> stream x[[o> %M/!@6 #!=IJl˲z{qN&h5KWB S_Yu ;4ײ~ />ӔhV緽?; |yx;Br$ꏣMiUT B53ڇ7"gs'3j 9"%G /}xzg }ƈS),|A8aBψe h|(F/'rXA:_La9a1o I(WCf"ƛKXX2M=sѰZq||7t2[T71ʠ.'(\r63?XIs:|$Yr嗗l.FA%0q9 C51ւU8j;(Y%B:^., X)~,1{3*$:sBίnB>d|0GfhVV88V85D:,, m(0LPB}Am9^gKd>TT@/OzOe{z{y ~N^;>ypYJ rt?APD }l`Df>ZzF7pVǻⶬ@e 8u^ٔi!Ӎ41 K ; &XR;koXbU9ƽ"ZָAoga^Uv?T1¸1!9V !Eh>c#[uR!~ p?*r2)Z)QC"|D/sUh< EH-bqEGߍ_*kZ׀!(p(gdJ[ S|BnBd*F/F9$3\@Y ((7/,V|dR?"XKO\]Nnn&i|`%ոX7,>[sl$5(VSYpvQ/t"oZi{JܩˁތpuͥT$idT1L%!5_'5}JX .Հ./ dhnVƪ `6.FgEx0IL)R'cӤr-vRgǐ8^˘v2dטa$!!ʢ\FgcS#q}"4$$HC!~Y-f岚Ւ6n7 !Pq6AJ5W}?S^T4NpaQ4~j9_|3(_'>{KeSEtx@Qdޔ0h>~n_QJ- >hl3<7irA ,#\Ai5m+aro:]"yDƺ^D#$v]BBrHeqSVF'`%PPC8PI墼 v= !>v!r)O~~<}}t~IjBF_}p?ѵx;h:-oF z{9_=jZjQhG3d3QrL6 ErNb 8HՄ^O4c W´zU 0ƥW)rcW10W(,d0n!jX6H+&\?q6R Q9.fceMU mPF9| J1\F%,@`>s5)VR$H2ʤSmxG=Joa/}p$4%& 46m.s`j࿺! y Y'm .6FWT'E4,Uh`BkR\G;YS$~+c -=ÈpU֭.lNu^^UUO4ĵ@V'1&)_3i"ye3ޔ),Eo1*|}^UҐdfMVneouד0-J$QPD=8ʒTY``Ⱦ@q\4ٷaː4Uvb YүrRv5ͣ]g" p|BU4yd Z-a(gy~<>Dg-1w\pF' J|Kh^q( )ZTat2.0:&x_BtN15dU 86)4|RN|VUA ?Xalv&G;_Fງd%:N0pL>N:^+TwZgʎem0Fu΅5,KF C2HgP'u=cO؍R+'DH_Y}25kxkC[f;^8&zu6HX@Z2ƿ1uܑ7{ʁ-=}lF2#&RtiՍ:~]endstream endobj 251 0 obj 3026 endobj 252 0 obj <> endobj 254 0 obj <> stream x[n.SO!?=vn 8i8X0`,)l6ϑ!Qr> .P:Ө}14aB`Iij8ATϵ:F5䑏NIX /f?O.@x I燞  L ^<>.fˢs[vu59}KeQX)EP37#0]icǣYt nDH5qؾLxM7"SYGF"39 BD1Krȸl?XbUid)A l-^]1~:\af[mxXD^&) Չd8u0D ,*t<~J `k"Th'+QaFr]x0,VGF4>EL}ޘPe5v9i* pBw6$`6L[J8&̠(U uYbA {^.^J)cgο l8(PR0[刴RoA5ZA`n|P馾=d6PW]&Lu *LV[\eX GJX@Z'7Vџ&Q ,d15,sR·|\XAD0;Sjf:&yfFoU3 bbV1=\7~B*F V)$Qjh*S1Gv[ǀy̭VrhBT)>E"2*mFrp5HV:φӇ2!rYKFu {fn%϶A4@:JmC@%G0d˘\-ǰdh90TykAFXw]+?FAlqw83m#-*C:*]UL۩kHtӶn',ܦ>X XmОuJ;cRnSB7 l܆gkBjyfזR4{>ZnϏ,^>Q%f4AіYJh4Vlw'δ鴺 -ub{ [֎ V,)Jbګu; I f]Yhmk<'zFJj73yJ tFΡ`:(S[۸YVjT3UY̵ XQ o߶Y۠$U7\b3bʞuY:،}T{TlU;tͮ!-PX(u+wwثM%I;\eܩ}J'Nq]VHܯALW  P$+P$)nŸR虍~9/JRqZ|V4j^ӿ3M5uX7BHt>9|?+W/|ՋQ7~{rs.Ml8>\灓sɚ`[O ?2A4(A2A3QpM_S14HSN~>w1) 튈]Fʾ[nƦ !gZ&s].@}5rr6fdvZ$5n)fe!zS(q'Qя eSx8nW0%Uve5N5\yg"\{W0O7B f,ߗ""Œp8'bM_U]l6 ʬq"x*bd̖J WrgytC)u^-5k6rIz9 "U隆a ܞ l SBi͓cu]nz^$2mn.Mhyu T~iC)krS͹HV+&5Q6TQt:owXBc\،%Lƛ{vdky_$cP&[{tEl6)5$iQ].Mynk cjt2op70]%2"_t9 -4nz,8F3FVt4LtPqQ Ƃf )wwWܞ -Nm`dk8Z !@'. (Q~] Ґn}ɂbUXş`1! @R*M%wx`ŧ- $ Ge+=xӲLHXd2QrEV?nw)'ެ/G8hXU$T} |i 9\T{t{EZendstream endobj 255 0 obj 3241 endobj 258 0 obj <> endobj 260 0 obj <> stream x\n7^`)ȏMnޤdK)gi˳Cck䅷x6'L{h#@dp*V}"@xT߇ه#lŸϘ4҂6;s7j$@Xo9n PFf$㫟͝L"[Xw?A!;3$Q!' kD ͐F" ~s{ &~|XZvVqP+D,7++F"!DP^9,s{e$╕)T+߭RZ{ܼX 0!࡚hP0(ą74AXc0¯th` Hn 4ܬŔ!)E7=c.-gj퍼Yk z(ЍW>Tt!ACrtb$ <3ǗX-^ BdTi}Z-vffx@y_n3H f{͖v,΋a omu9wF˙sHcjqpHwKI[or5_5񎆥7]xc]=}!-SA":uV=7Wp̆95a Z pzgϮ_6mu_#|/OgW'e0) fp#AG8goÌ %H*ƻ7`cX~@{#'/M驕虖m9"R?=g('qfqc2تɋb+ϙ Xu94w]*nѐ_rcIEaf"A"(=R̬Gk.C R}r8㧐~z+joʿXEŊ9sZLFg{tyTgdFL&O 7EϪ\\&?3)x? I%m=}\T 2|ĩ)HI)A(!!5@0 j)iR0f>҈zl}?ᙤ@5/A~NCav@dn55&fvaAσ"bV^W| 済PoAciHstrg@dFgq /DP .4>N7밢ԛ DEfIK8,3X?liHx%,*V`l3!UDRIceψK'7\Z@ Li=TX+X!4;!. ኸ&UZ}[ ~Ee8Q1 4e0Ȍ(ȳ0I2 pA!(&/tg2i&dQApXYk[d5ǐ2oo7k<ݩ/MonpD T>cbRZL\}c/dwai2M7c\e6caSM:/F/:j6@VsϬ=h5is:֓XyB<LpX6_$]/+,ҹf0uG@AMDŽ'[j/L?FQfDS4TYUUr *T )Zj*2[i)' a3Z2#$Pj,SMkGKj1:2((RмBC :01v_Oq>mUb3BJDW[RŎjOW ܵ>lв~g&yVj^TyV.&QP$j=Td=*JWπQz_*{h[9Tu;*$mMlk/&Xsg0JۚH!juV)?EkEfǗ2iz0<˙K*m)&^>3z" T}e̘(66ϩAHiǷqrra @x,4-Rd^t0Xkщ e5ǚ(>k~L\dA!ԣ#+3VH.h 6_;a J-Tl'.&ӇrtM &NoYC }O5 EXl;`rqMӻifiKfd(ճ Gq_(:9$PVgU ~n2|cPz@n=}<71_X@6v0< ﭟPا9zn5ɺ7mщ^pMPwѼp%鴣ݝ/1rn$U_-0tYh1@iz)*-VsRE9f9IVӧ -PhmFtq:YJZHDG(qenDSJbc였50u2(y n̎J;ӷVaX p!/}|8S#{ 8UY%y ^0fH/uer @Z5Ln4A绶H:݉3Nn@eC2$2c|իi0n`R70WMоir'ФK{27"mnp:`$l ,xܯ8ḒM]723XX23$fO2CI|ן# H%qUe5ۀH 74o&[nDZŻM2ԦIjrkڽl45_;DYN  'ٜsXo Zw*"/LQu|W e 82#%l=J'OlP1M~=H+a \nU |Ґ HIDMOIPJ$#\<=U(HL<lC\t38{`MB_σ廒<'|6[eRkެ=jIV8zܹ3_3)c?Oco=~@ TUendstream endobj 261 0 obj 3351 endobj 262 0 obj <> endobj 264 0 obj <> stream x[nHg}66`u~}r&Ƭlje;0`(ck!.x#୾IIQLDF>U}TUSˆ>'7//}j{ѾAFR=OF K-a?0D=׌ýi$RR+ix!aWvH"UoDmA!-P4Y4C T2.ށBiFeܾ‹?Dr9  &:[̲epD%fQ48C\JnfK¢R0:' 4m|oH.>7n<עW4хT@Sy,`117pr RI|`.W"0FK.(o9Yd YJf͖Gb=9&SחY2'>zq\jM8< "+A Amix!HL=Nz> &,tȫVMծB\f2mQJ-RKjj?;-++̀s7YEA^ e[P/D؜ek+O˴ 5>d!!gX(#2EHN)#P,e }a* lUq@4cY(@0Oz=)%X4B[8vCHBG-v AGcP?w!T&X d*+f̫T>+VI "FJS)~ZʶtüV6 M,1WۛFw$M]ǃ]=f4S܃6+ӾQO6o|/[BsE<#5\z`T\MFszDǮZF!F3rҾ.!UfNe;Gf$UdV3`rOhSnuܽICT@mlp9kTس*z.&z= )T =]͊VԵVRJ=U$ L+٪]#RV>!vA9cUL_נFdu 捍B1FVST3Qȧ;kFxZ[kDQJLJUטTv=@5KQH@;KМKט4,C=|A5f~7,@(Yƪl:ɓxj:Q:΃VQ[kLQJL;HcUD%+m1i奮d_$> endobj 268 0 obj <> stream xZkOJ:sa?AT$vuVHĦwv'!*jl{yދ M?;ttt] ?IxyFZOb B Ew0pzOpg(#H3|G$Hq{p9Ȭ`_<3#B4fIDk' kDfI#i/.>[@j f2DZS1vY!_}’U8CSt8#u|Mi*($<a/4Fi5*r FBSgR 8+ I]hzG⎏bϦ١W$]PL06Ǫ 15ӰZM=+"%YTJE}v3gq?eUnslW$zkX"`|gwR n\a^C B)(װN(%l l9|%.8E_Q %tϣ|.K!wo4{XR~wazᖛ?#eqW,9`Gg'WAItADB^skmpzA/D4?[b:{=Yd2L+>KL!*Cs#b,/"Q~?U*wM)"4O:) /*j Ǻ57{WD7*pNLr6|U 1V!bҮX-'ab6euэokJ 0$P,&B W=-!^I]> !B@\BYL%߇+ƙ94/-dn&|]vǫcj~ N{V>-9d0'X@lеgW'ShG2 [1,:#LWed)`!&$8%!\N@P̦dH'Yl'wR @9AQ6.+^."w|͆,Z2(xlQg0pI#ء$jHbނn.A b7lXe6T2tb@JcϨR>R/6w*>#-I>+ѝB-.%Y Mq2[qp*a!j^B,^eV]p{%s<3]%2xx>HcCU RuFfemÅyH==8Z,\L$zSazUc>dG+{:NZ9&% }h2%CP=NGQ5. 甆OsEzE&Z$Zp _QRikA b}.ءT%mTfp$j':]Dy619&A DG9A0 9}fy|ysG2Ow޼7/?:'/.& oh,H{F  jM|uQAcUFFd+YDwΨFH3#uߐEEFZ38K {UCFRёyߎӲH{Fn(K7s1Qhb9VȱùPa'IN1}*uY[}'$Ōf뉒0($4tT;sY|v%nΠcAcP@<&_Fl2Inŕ{d:LMK-fO}ӺJYsDLjG!bIu5϶|h ܽ-UB5'|_x:Y]&NL?fi:3Fw[i^Γmղ ȷ*b{q+W*JZ3<0D(krDd^Fs83F~-/1&$ OXG?uqXBM/) )TReSP7JԴglRVM%7oC"˴v*H*~_`é~։!F-́ltNEx1AV:yڐ 69^]ݞLc޶gh4|8Zx;&÷JJؚFլ=p-H/F[˺"endstream endobj 269 0 obj 2829 endobj 270 0 obj <> endobj 272 0 obj <> stream xZN#Oai,HeDbEbJ08G m i c@WOF`+'D87".AONhYUyv3e^*+YҌ+$o2w*QpE]9!2U&| Ri@"D2d *#.hܻvUeMpTt(U^UeB$&sL0mcvdس+*My:uv41, fHJW:ꗏ>Umxdj2,&pRz"u%Dд6.̉o!OES\RM wIfS#Y Ж 2`6I%@@"@b8]q(k4ͪ50<ylUT{tq\^ C )d;@Mfa.\8eaȯ}*2 v)%- !> [LpO8Vxa|/UxI2ާdZQ>^zB^+qBl8~l-'o@6ã9(F8.v7e9ͳ#d\M,Wy; v;3 H+1?e4ox"w1D\OtNuXo0X"HWsUMhv*NIIqUV,&ir̦Sk2vl!B}DޓTaNuE#$ʧ&QVoњ.= W>% 2gMKyݕw N$. `M[Q8d<*zD@Gyv@Y1gkղupInj it T Ӝ.5T&|:lő9\,WI '/}F $kTw@TCao }sQ R6ੱzvLٶP#&?4,FĠoC3ҀW^LVoc=5D[էt&x LX\5e (aSj6t4 h p,8?2]r֤ y$9 zv\u8bxY=UV7o* u-X> endobj 276 0 obj <> stream x[nG]죾@v/I6l+;d5P$=C&V3#q$,FZ꺜:M Prާ ch SGZF{l4%ՄrOG>1!9q4*ztD?4pDa\+CdVTQrU9O_ɸX?Cư*X* x9ϒ pJZbx'9={"1WD0!W9e˪Wu"JŲ qN9xUa 9@~L4,-b^]Nf.;K-0겜ßEHgK34=مw^] oAq{hOᇴGClZF b{Cn{U6k2*@2ִÒϝÓ:/u2C$}[/~<㸨c4Գr\$lcd b$Z'0ƈ$tjrY\5fzPY#ɨOfyYA"v"C0ٖb2]UeR[2 .n5Z] i>X,~b`y \2'4$>%Cu׬(rǜV,,@8a)04dq3X&, (!G2njP׌d嚅i'eYb;d S jMӃ`3"6 Xi le}iEv;zScrcYk'ӧ?*:ݛ>wJÖNǫ7SX)rJL;|HܵVW3"x:JԀPX?$]X[Іt:7)X#(ᬣCjCXR"'p[9E&-,Mfo626=خ9Fy&b-B!R3w.GӴoZqyK,zs-[vl-L5HyUq8g\DRMT|$#*7e]pGsi3n2$AdWK"+e:l۝Y`\Ѷ(oݑv{LpB). VU.ղNHP%-oV!F(|6m8Fqmx-{f1\f-%k)!6TM[tC(kqm6뢚M˯?F ] )BH&=3zܙoPjYrGb5橇L9ML? V.0 r?JIAk};Ҡ[%4s C.uH7l*11bQ9m2=Ǧ[i@-45;`hi2sqM%} 0DSts{8I>B,٢cl~\-y +eƞpfXԤitq6NAWwHr'"[E3+}0DR8]/JP  mT[ mNJ[f)k=-6LrI,շ߾~"mZc%t0˟& ;6[ucTi7~oazo!m zLY1o|Y kxswe-q箕T[BBP/JTPwZ8]"Nz&)wi/(dE_pZ )Q ޏc)r~ݽޱ]28f]_E } ͕̓A kw0wHmm+B[ޒLGȍv ]hQ GCț?N[ww/.grCaD8ZF;)y8'pgWIfu~ [wSyV\;, BP±` x9t35q8IdS7ry27ڍD6U~]1j0 b˪/; ؼiTVHc93%rx{-8("2}g%UDi]Ϋܵ [3U9` {A)P75=ؠm9'e6jDtrε"|O4'/C/_}իD?ZA, Vg-K7Pendstream endobj 277 0 obj 3467 endobj 278 0 obj <> endobj 280 0 obj <> stream x[[oF~} X_''ڵ[!t]=s%i^@ݎom9cO;[aѾAFRÇI'pDN{ 1t8G1qvx;K a0 KϮ"1a.$ 5&,5,s#e hUpx/'́4hyt4":zXfsw1A\xh.Hh.) 4%ay7Eq_LxS6b%1Σy\gٽIr\GPiy>}JlI #"߮_#+|s0JâNo"VQCi-6zuR`?#3p]%XS@\P%:r#λc`oEകZ,;'1 8f14{FFP^'"4>HW 2 +x6_AZk\9HA`ݗXS?*'9?;;߻,{D(@VRTn՟M}a KISUDP1p<j͖X5{i8! >d0Q +`V)_5*P} P\یV5 <05Ԇ! 8 jk CȧZeQP׈Y\BY'O1=ׁ:PkucmYpU7m]hyS۲i8;Au1]dl,5(%iŀ[QEjna͘"Yva l।9$hZm}ijh䱹~ƍ3.;k̂ oɪϨ˶%mLCbVBQZw+!c#ŋa7M 4 4acD>:!"8x I3 #K~_  RAV 羀 !|ÜN1ULԍ+ƙ4ӛL,bris pu0k}ʪf1!5VV vRC΢äJi+i!ΠJ_gņe`%,Kȶ]'g+WQܹ 7u[&T U$ KqtOѫgy 1Ӷ(MpND!n/dIlx%6:f}Uo\U#l\T\ntǿ lj)”Ec45~FK7I"8 Rf؊8p4uGQȭҗR[`բl,gw:<=8߃,62~F uDL")أD dx(P&@TT~ʐTQ: ;+)~-9G`%y6 oKTAX_>O}]>E".@+, undpDD4t\ldŨ5EưĀF&=m= Rr(`HI|1 nB$MיDJ)"PJE$)ང)hJmI< IH +l~ei'!J ,E~<0{a]1θ"PQFC%^֕m=ʪ?X .{LBǴ7SOsDԾ@ʘvPVCZ.m#kؔb$8V5TcJZOWQ^D]5V*֗ (]ώ3]~dQ 1{j[u=olbQ K6O1Qv&JʸHrRV Mz݂m-;FkgPJnBRT|qPwYcF(>J3j3ݫO!L!L3W^qA=? k٧]m;>:VPp*jU˺w k_|"*.^Dmgl_V dc|#kƻZݺ݁ϲG^謮F: Fb(nٟ{!.: f,e૷fجC6k%695qڟ)T!x uՏa՞;(;bNwV Σ08W&+a,N^@e 0,§*piʌ{# Y$r!H~"(,~"X ˭~}|ď?جO53FqZgEB7"OI_$ߙ)j{&V5 kG&Yx{YtCٰVI(pL! fd/Dbb~KO<\l?h`6^y[ othBZM> endobj 284 0 obj <> stream xZmo7>~p`1KrI.{NK_(W0`lUVqo2Õ%9Mơ@]P$w^yf،aw//Cnj2xy2·A8\gLC]hpr78ًO_ fs?;V(= $s+\Ls>gBX߻%2 e2<.~rK.3\oYiE\%Cì8k-28( &pwn-w_麫.|}j<`%͙0:.n꬞ywvIe4:ܢ~ms2k,v?+$+ \m]f Z/F4O/Q[`l.$&`<8|qwK]OR1S<ڪ[^<@4dl pK mfr>gQKҧ"[8\wQ2ڢ^}B*V!F#.fQyBzP!(X9+nr^OˮnsHAEL\ עf^V!Ն07?O 3BN9`F=>gբ}FԪ bմn UcCdaYÝY'Xa}m5E2f1Zu|Osr-2?0WaSs\/4u{s{tG!J')ɳ43I 2/[P3P_ UQ3T2@5  Fj4'T![ΉmrQ=w Jw ,v4971ѫw~UC|u $V-VX3#".NOB%P<ƌO'oC ,yOPiC\S1H;=lӏmхOn) x}1>NQ)I4JEva!Ex v5sv:X:`-=^LYL@ >xw', ?'~/齒D 4;YrTR~@mNvhPdĺ[aZTmܵA]WCe7^z^L[Ldjc_tr?FuZӫ^\ 6'B}O}tI4K^umS0&Nǜyypۧr=M=qlE3H )^v| IEs)/V /~XVp($r Ȯz~@s84taډ8WE>e\i7-X%4?PS5릍@؍ܓ1=rt7'p&ǂF&hh]IbKJ <ȪhDh K 2d[W 8tJh{E 'jӐX#l ! '#jWv 5UHj 2GωK q&HweY2?\˕s("43eʔ6HެfBKS'/pN,hp5n0irDx2|?2xƐCpjvxr|2u5x^5ip> endobj 290 0 obj <> stream x\YF^QB>DtǾ16L6@GFL$R&8ﷺ!u0FL"_WutUuP7Slfv%ShA.'yM)ET(Mho(go͐Lo>AfH'\n|O/?` ` %6h0&H_xg䉒qѲ=Tv8BI7;;*`0! ӊ7"PYΰJ$߮2+0=w*, B(K1Yİ\d50PX$~O#Ca敟0ūw.JiKw!:\,XQh iczwkWA0saX"5[zIQaEa~tIU{AA-SQ`=z/X8ܔ MV7YM^`InqeYץ)/Z ]zion.P$AVf,QSL4 t`ʘo'/~?Ul)7ӿMn>\};&Ld'Mo f_MH[CZҠj|TFo )j+PB8:P EuVϫ|bFC78UKKe/LD4"{)1Ki\#!ȸЇ\<>2Mـ7_'Ugdh68|RudU1NQ> R dt!Tx%Ț8bb?!³ORpyVz=h\!A |늹vRu ؔs8ٜ F~7uVF#cj$x ,9EcC2iɯO'i=sJ\#S:K;K翞v_WzPy _/&s sk<ǻ82FY,=W`g :W?ӨУ|֐8]uioO|h#CmN LDbArY'a'JHc%^Y-dRflt[ '>r0R_VƅO_}UWbsTu sZ%'f׿iάTP܂y(t3aɔ 7iF ɯp9d `~)yA X='nraˎj Sth6إ)@1Mx}Q\9gxVo7m3׳X`{ gzG2'ռvqE˪M^r| xbP&U~E v_>#:TloJ'juMEr[t3 &u\=Z-* 8+~Y8gҌA-; Xz#Zul(j:=wd>Oh=m_"b5j/ۭ:JԹYٺCX~2w?g.UwӢN~;Gu^4<:>廕ۅuȫ<ƣO*(}檙psVƆ ΃1 jiWFܤFcanA-Yp}!zwQoDcԻ^6|4tftpYd sǟ˭@5?%lM-eڛendstream endobj 291 0 obj 3366 endobj 292 0 obj <> endobj 294 0 obj <> stream xŜMssqsH[%R#Rc;v7TM6t"ePzvj]ő[o  lbχ?scL&I%|hl#7RˈMIZ ^K4J8n=H xu/,+E$V}?EJ"J]T¥ FłwR)Ru9JR&%^㥬|σrD$7 %4$- H>[~?<|O;(F JxQL,T'g~*q0ub;cYGt& "fHH&"Qs?7Edg38dn٧$|\g2tb$DLHїKSHS]ѥ5J })fH #bc$5R|n(jۿ̂Z$"ܨ{mQBYQ<7־e>pPdˎ wwɂ)-shȫq 71!.C+c7fIXՊG,;)dVH9LF$ a(YFBbRF*7vۢn>5"| V~ G"=$ 3lE^Cl !>BaR)e'D:71VHY^*hF`YBfX`c2/oM*O79#ȅN)a͚eoyUϳ9Ʋ$TVQ 7^R8Mh x!Uvyʊ?f%`?A|C.4(>m{T0S仑I8A]q|H̀n_{dEm˙/egѻO@d &#QQY]yZJThո*t)vu^~24NФЖLywr@/eg$I=>,|("!JCVKU3ؽKnd vyUx(w/ PX}i,;<a;p#1.(Gc .׷6wLVkݜؔ>/C /e ?k?ƭG[vWɠTYA;۪z-i-X^Rec9vˎ:l B}`Ύ9͢Z) (h phjlΗ,|xRXv ےsljn7N gA ߤ)$1푫wY<*wܫs0n^ND 8YBœ】GΡGתqh#piYBc?6y=9~ښЖ7vAv=s^ԣȠFF}L4/oٕ̪hZ[H6bWRYdl*CY`an`Ъђy#Lsf&M'&UzX?/9 A'8XhGx۽|Ȅ`\M7*70lV|rpZ\N mk]x#QK]B3-W)C|*9ˉN؊Lr>윈;9a01v0c_2cc$8e)Mz,mKc}]VUMyt1돓,fI:y|bccZ0]w="~ĬqmCT| _GN`z>;XvXp9B [a`& QЮSUBUl0/8$ewx#(2%\&q\<`7_N,Xa %VN6z;Xv?}Kg<}9wW߿CTvQ6eo>Ka*,)Z]/e vꑳ͜\]Îc*o!g$sl#9z=O,;=:N`|Ʈ6*{;ҴlfXϗ!c,thR"0tG}⛂mu9Ib_N ՃS96A{n4^pxOJʮ:E ,׆mX'Se~s蓆i,;]2;O[f ]R0"1.tNaa$;V%oSGAy|bvlle,A!AfOJ %6.soxڧf䀭geg71Hґ%{XhzZ2r:wd0a++"3_C''܎ghg]W- հ29e>^Y_Iٳx>ԑF<'4;Aq[\hխ欳zwpq?(a3rbWqylNi3\hd={O,+f$ nXH2t)TF!B+辠dGszs˧cvfJ\]mRw)vtFCW͟Q jv'r=O,;`2׏I1us;:|ruXys:&9>&&l1N,z6AXvxh x7fֈFo4EL%S=ExAg}bbM1NhBn]?4Pqp8<͗k]dbGuua HyHwb@}?5endstream endobj 295 0 obj 3110 endobj 298 0 obj <> endobj 300 0 obj <> stream xŜKssqsQh5)1x$TaSO$ JCw[~D7ex̿x /ynՔltl &LPl?~뉠)gۿ?f Ik"n<DQ3umQ[j` e#_Eՙ~o,S̅ʈ xV6};R7yʋ& aC6V>YXL`/kꥯ]rHjM$E(^{Ym^meèssnQ8L}㷅jmA? S{9 6FZfSRe])J;_8#L)u:MEԠ&aưD[m5gfHpX 5GFZF{.&Ll&Αio~%;KPaowg.Qޱg6 FZIxb0\vϢi<aM0 2d=1/_Co8PѢL`QO8YuOIx-0ΐԑ:s]E30s;G?2MacciqYbCq$=0bIn/o#G?V&?56?=zn9""BїZix3fAfnj=A#|еqHƴ닾{nqP@@+꼙MyePY>L B Z ۥm҆O3K]B{D<ԚDRV}-'s..l^R[@)N.4@pcsD8 ]9UpmIYw VmV fP}}S.Kc"#Z&Qx@3$ fkGF@tm{!j_A  <,`㺗 WZL.q^o+!ʚ%1y7Sdw|dͦe$ʄ})=]\2T,̡?Xa9v9<_ 0K _bHr88("\AדJZ&J #w 'Sj coE;e۲2?+"/d=deHjFfKQ^_JɊ5/^E "(;K^O%ck(Z%Qh1t.lCxJIT<ٍ}~xMEՊF =aD>v^OckCSPFR}%!CcK(yp&5KZOck(Z8c֜]N$sCTkcb -ZFJ-jfT̅~穾CfI.v<PJDQytc9V]E~^2z[˔ԪEZl(ӹߦ CQp2L9I yߝζ'AѵI8I KI4g.+rY :?aD*Dm+~X@MkTJ~w;0p;t=Ibex;d+xDb!ZJ_Wq##%w@l];=S+tq\3/UW'pX1+N\_w9x:W8AhH+FS.udؕ7C}5݊KV)}[vm#mNS=阠ā1ŁMcu1k2K<=o> CFIРvmlVLD^8R[`zAOG\V3i?ӄԮ 4u6x%Iqt 0T{AKm-CEcܡܺN|a=\(g:qu~h\ˮ6'bbBZFV!bυvvmO`P^0Fɝ57Jyїui )}Lit'!c潽0Q81'0284U}g 96}drǛQnn;Ivgvdw^z[8Bnyf/{ 2!zx-wx:s]k\ьaMsE,>O]۩w^ĝ-""X'VoO$εxikHJf:!+KՌ.sbc: z91dVe.Yw[02v28 {^z7(!Wj(!\>n3"Cz!HPDQI cl-$K ܂\Wˀ%B8=$K&CP4156 fs=b:TvHh7>R[{g;i`1sUxxOxOM\hn],^A$ߺ1-3yֈyT? endstream endobj 301 0 obj 3325 endobj 302 0 obj <> endobj 304 0 obj <> stream xŜ_s6oџB!&K͉D)'qeqǵS۹N-@R0¹ghy ], ڔN^fxJV;{ ƒdĀ=*͏zsqMR`Ϯyr-cX!EsIK^lk(9Cym(ι ,i:[(dsF);YKx`K?gKpyVœk|^b+Na%3^in saɤ;) j'`| <(@vB d;/3qDH2/f ֗r |qn3D0RaۢҹQ^"d/@V;`#]{khg ; :; SW WΊ @z P : q|׸{u51nbr:/?))$#N vazOS(OBdӤ C\rM$S0 SBXn@̕N^bkOMeBҾkE i ib/Ujw SYTI|tQh°:ڡG(l1g`).{U?`GWUiOd*-omY,fˢRS;;k* Վ"Tl#.ýy׵±J;ll3v_.RPs't!" 4&x]luv6i_=ضQ92j70^;)k4 NhA-itL e)֦kTۤi#r F?"9 Oj"1ZE!h4m׽@fPsv[x`Z620U%>%+DN"CdӥbRPx@'k޶jѻ;F7$( f]tZq4"R;qkB Վ݄hPqK!3i.l׭AziGnm@c[nrOFqT >w6|t_ߒG2@N:Cd#)bw0sQnћ t0g]E; MMGEh8ntډ;]Kcv YFCصVE4/Fet3̦1kH10( =]cv8zrtgf4[<eGFV j/4g˫|)@'_ ݿHͻ́Y-r$]otyyG]ض ֘}M>]#cvpFFlje4%35`0gcMHm[y6ytjK6_Q/HvN~rY yhuOWKwik)雬y o 2;\AD`|{ ϗη{m"%R_<d>v>mCc;ɛj$ncd ]d]ksΎ1o=0 ։q=;7ՎzpjG[n4͸N/sT-!;(m0>f}8CjS%7Lz;׍F]v@|vy{|qBwӞ>~s noG֔GI w2ݦv{Y#fii*WJˣ;҉kyy%0g7/7TݒIo?׮hxy<GM1F.%`/{} DF;Y`>Sė.7um-qǽhy~R}É=xKmn6Nzat r277`G=rUbX%~ؿ==70*\L'9Ըeܣs PVX~r껷onoG "&%KՃVʘQfwpV&ae-#EaƲ~\!XEu~¬&ԍz~qsoEsVYs!endstream endobj 305 0 obj 3394 endobj 306 0 obj <> endobj 308 0 obj <> stream x[[oF^~}H/]Miv02mD33D"X ;/G_G_?K?&gwmaSb|v53^Tece<Gy7g)=>qtA4',>=DBZfm|t}ջS*!H!9Q}p|6>0#Cրo'ѻ?fU6wt}=/ϾH Q洮UByBÆVj-WzZGĄ 'Ҵ;8'9WjĪ~b'&KX1իbҗPo3ILk"MNI8)4=?TW&"-W*LP)WPo{PI3]vz azuR>Z\9xS ڧ!qSpINVUs I#I{fKǘ./ w`5G2١1ArV1xMQ]XCS~䣯&)(&~M.Jh=$I]>_Z4((Wa:s3mT4ڢV͢}y6;CaX% +gȆ"rfAQS~apV@m%"*b -@u,8:>{$a ?&럿y0 a=zRf*]mK S JMO9[%(]]Uo}:KZաcu|+L .n (HO`9\KLd7Hz?< ^WN&.ˮ([ EʤhGf'<U a' z5 .T0mQjQj:ۃO lfZIQĎwGKHɡbZȠ>;Q-cUM|bzז&"r@^YH ~~)EE,Ü؆I2eS/)Ҁژ8`4tIӫ d6',!-.OzN'(#UhʹDZDa(\$ͱL QWlVcPWo(,lK ^Tן|9!lv h&Ψ$g<$p#G]HIaǢ7W݃ U#( kpIuj7F+< ]nS&y7qmuztZݗX;z?+6䠀!0hD\mՁb.f!e|tKl/=/-/&ZUUQ:4fZfPWj6O- nӰM#,.,|Kڷ Q}t?Nbom?xdy/-j!"wW*gOT(9HP<($Sx1&G]!hPDz벚׋H~H7uĤ[)k)Ἥ{"&[tT{1KIIj0rK0%Vm]MLɴQ&ӿN"1IĬQjdj& 4w%i=AzSFzjSR̰[f?դj2t &N(6w QSJELITciތe> oe)#&a6:BC3fWa+0MlUW1ÒwU$L|Sz#b\n7Zm=}6ʏǘRWizx]'GQh z 'ր;w ؔi:/*ݽ;z}NzcL>Bcm7+iԕS̜..D<4"hR}L'1Z G91(ט}HOoYہ1sc} ء1)З! ma͘qsEuEV8a!!La{zDŽcs v=Ϣ6]'o'C<^ =Wx#"\ÀxlOiT?|IR7@YMVۚ7eŦ[slpn:.%{Ϧ]n),՗M}ݔ0di8>3Ӱ<`yT˺b.HAyxTzI]mP2,۠p;ő43-ZaDsw!jB1Ҝ!$u#+da!lQ NU 3XŤ7uY#|19Ӎ/ѢwHu7 c_`9SM<𜐮tUͤZv&G hH0EgpWBֽq/,R6_])w"7]=/餜K?Nf(*œg2R 3xa(Rq6Q#í ,qTf/]F,)Vګ6m3M (δ3+| 4T!V0!BŵRp4xwfǵePX/v{ ^Q{ӆ;bCM&g쀤imJ ~CYUFmW\?u5u>C[S}w1U5> endobj 312 0 obj <> stream x[mo6>פ]}r5&w>.mo^m:H~ )rHYZq- " yl?w|֯č?W'DlLK*r}lgؖ̈l=gho>LQ 4Ӝntpb*+M̎(?vz|d)(!* o#:c~';3EXN߿{Me2LS?>jqEQί*צ6",=]0TlL8>39񃦮K]\]]uC|▔SyYTuc&NڻL]B[Qx* 9H"̌W9߿6_쏂d%(L"aE=6ST@3LBy;$Xxtg&"+hNz2evYf.2.QiDqBA-WY`} wIM3bg5 lzxaԫí?l7lql>9|?}-[.3j%_ЗA2_'BR3mp W$Ŵn3ijuc: ̓[v:_ Jpml$PjV]:U* qae" P 9O6 \_fkiQDY\,E3Z>Z#O\ Orw>y>7 Ib:^La\)Jq=)7 2eQcrè)k"nծAeiUchuӨ Ȓ= ~?+)v-2QiLr"SLc ;\DI#9 'YǃBӿuANWlSt[bq!#!24*K~JP=LO5>INM9اOAqb:2.9nrY^_&,qcyÃlse"["FP"NDV?^/4(X-fV˺T X d$Zx!!gAm-.%h+y`7_f~‹PUs2@]╣<ӌ/"/ Xu]-~ " F(fq\>fs k:kM=#|vت0PH,T(~bgಪo *'.QCAo|'00vpr-]`ri0;z-XHmjWMw{󸙴 /'fVbB]amR'ym>LmT`S;m(ozلQBa*ɱjZl;d W-`8NY0|47/ Q!E v^QKuQnрhH⅁ U\ǫ6wxntwz*wzRG{q9gju ؀o Jd)  :ԶD4O<(5X'G[K"zਸ਼]j`KQԯo<q<{XFqi;Z)H+'Y] ?.Ȯϯ`Eb 21DTWy/EmU=Gj.ǹMF.9A®9t~S'rn<6fǟSӧ;o8ȇf2s-ﺥ~̍m[/yF3~6J4xy!Z`xsrv P ]_OɎ0nhdϒ )5hC16dSe]Xm\1\RC" ѹzPP6>;&VMs6z=DsMnhCq   sĮ rG -iFa[G]=!}Gc4MKj/oZ`OP U`~NP'ZuycS=r)^}Zմ5 !b ?VIppRk-$%bJ4m2jp8qЊAi,IBB`X tw(_OQY` .P˃m6e=1A"1ex(0ˉ=6sZ P oB$p(EcolzuZ◨,A:ԱI4_X%!IL; 'n!X:0ei%0-fq"1=rp-*O_%|}7]I81YY.yᵏ%` ΜGGi LX7,@[N獹j*TEbar} _N*`vRG{w|>BDRjQWc3Yr-{iF>vsYGg=k(E7^`>&xڧ켪)tPdqjjnκ Z3O = -9 02nT_Wڛn-uw7;m] al /ܜb}GBNzYc3 Ё\Ro,k R=M)}Q4oyEW `Gn`wL.O}l4M5@u>vVIm%A({@T;G8lJ^ !nCB3%zED+)B.d<˲$L98ᣭgjP7'8 a1{?T睰ڲļXNj;A >x!?=?Mj%qдlC-)zU.}u3E Ϥ@w.6\}q"6D|~jyhXi2Pdj}6) ,!;f)iǓ/0ƽfLK3B\)ŧ _lڄwt"KU2 iΔ*~ ?"Īmc:agc< `>Ij,e;f}rϒmfd(,ǁǤFbEݶNA^l ^ܝ'YeXcyI|ޙ[خ.eX-΂bxBf[k c1_wIT<SE|VdTzN7n6XO`y ܜRVWJB]5c0> endobj 316 0 obj <> stream x[[o8g fx<趓 P(6xֶ\ɞ~)bv(3(D}<<;ߑ0"cۘg.d$|<6.бC4cD1qv:^gqU7H . Lū_5{xr7LcHh5Pfz[˥+8C+tnpĴ0ap{oà~ L5 cvگGDMX- o70RzhBnH!ho~))RF l\iz}f7E.n)N~غ1R8BJĤm.`2k$M|CCQt8-ݢ+ޖ?/+Q&=phc(sbgGů?ޏ13DI7QH?mv;O Q} +Q&9WcMH G6۹Mzbve= []LE9ASl6(@j 2j}ook`ݲרBx2%vɳ }bAw& P8(㈓fKLt742Ǧ,T8GIp` Pr,E:*FC" tzYqXT7k C™vV%өsQ%dJasl -'򾚔!)v=aLp=NՔ(=TCyFZZ%Jͦei? ` qP̑P| pΖYQM&ONctED~fII߻| ؿNNKQ1`pdt4umv6(yXFCl^#C8Xc毹:V嚈!DHː멢Lq7 eB!o)11 ;sWe}{""t?q_g/? PÞ%re'VAhZ;L($2^iro8_/SrDTFm)-(L:2pmm*1#05(Cy0P} <©I]vӒ̀K3T$1\eKV?7kf.lY~h^W< qE134nҢAەv :R6!#X1{<`po2wt3":>qo1'Ma[*5>}u@?ML-w\v(!О߆@ʈpC.:=D](xX׉Pq"{,Y:bu`cj܃~i~ԜpW{ȉt϶'V]-܃Dğ]eRjoqun x,cn3;մB|a(I3yb3" 8F9 _|Z L3P @ŁIk_ڸ*ְ@ P g4. 2 $ -^ӊ=;7zSҡ>y18"R#MLG(Jr`P(ikO!ʡQA%>yr` liE š!Ik͋HgO?\݄ZOk Tɐ50Gޣi` gC@Cc'ob;T̓c;7428>p`MK.LFK[PA^C]; 8VlR "* "HS%yL'ԗ'Oy=f\̲'}SwEZ Un-R75HM2Љ&nA4}پ] у1O`{;GkNk FӃM!ѾY؇yܻrսU# 7MEVb,+zL0m+0VVT*gerWsmxS@R% {yki:6`Xd"2eRunob09|wwWl+oW%(?C 9?9"~)nlHNL퍭Ir-ao 1R 3npx_[J0 [@EF/ߠg~vJu#$V%C]er|QWnE ުkoqw[805x{6Uݝ"HPy3@iS0M*VGš"[YJ҉:3Pe66:HU9"n!Qwޚ4rQVoH`}[7 F}endstream endobj 317 0 obj 2851 endobj 318 0 obj <> endobj 320 0 obj <> stream x\[oV.oa[foNm. Dj$!99Dɒk5(Zu8go gD :"w:8B>)XJCʫ* 9:x?J:]V(hjC]N> /anU j9jfMkVBeZ6l]V夈`V$ZTbSmLaLReI"-a 'РSJKJ8{&B(L)Y`e:<ƙ(Q-a==mST岧{Uu?N ~mMt$,ˮc+&9LZdEWMXF¢:)a岭""Jdr: B0DRPW6>>lzujI"e3Ȅ@ zxst6vۻŲ=PujHp}+4@h>fVkM89Da)zZ'Sr6&:ZH-1vL0w5p%؞'vA-p*Pfj7pptPq\VP'jMhKE79|:Wx!Av(2\qJ!*>O,DS @ 2nnYSxfQx^v %1&.=qf@!O1x!H200.OO-Uu#=ifhjӅ Cu)(lR3&QeRIJ:vJWyt[)a y[ע9LlyL;'P yl((DLoRp'SY.ϔVwڃ)-cJ3>Lyd81ٴXvRtj<|VEX`9ؑ-ox+4Q,6_qaF%HH5[Y˨BZڕYXT;+HGj_a{걅r*mW}hR^ 1+dSB? =m{/YrG|?[&D#SXc=WqR=9;ƃʯ<\ˆ_Ft6K[rE F1:bM)8x}\J-0*um2Fs>uP灅Q_rw64NV3) %c A1V-6+ Җ W(qn_0T9"T''וJ/BN`Y< ؤ#@![䎝_qa4Rc5@~TiBN0Y4bvqHAO8kլߒ}FLe ‹;a]b<^m/b݊ZHyJQ:k4 אHP- :ݶ#ft`7b:cS.U=\Fʉ8=8ϱEwl-Ifw Á 4w Dm-xu{]N]ehM@6@*?B]/IH~;s^hz$ByPpnO[}qTRtԑ 8E[55_+oBD8T0 \)V-KKҵj;8"5NbYE yD0l.iJAesc# /!C׋'܀Hx,ypA"L ñ8 !eWh]oK 6E#:8\E7]:U$ U& s3=SKs |f@ASIspH#m]tƑ of86-]Q[ -Q!3 zsQkA`AД!wUmc Qe[.c!Ll9/a;oMͱT|=:~fx={s7kc%q^" "lw憊qLOa\]cUEdL}81׹\T $gcWf?D~[ ?0YȮ$@#O" YU&:9DCLoqIdYduS5L85\?WOp708.<4OWF"reifV=)4wuBмuql@L/[`Ţhm6L~*ްf{GyBX(u&> endobj 324 0 obj <> stream xZ[oK>~'K$4'ċ 3e~oc{b9 D==]U_}UO(aScO^~|\vkLL k)VH;_NB'I?\||Q~/?2u5l+%%Jf6\LgkaۦLK[.S3hVۮZfJ_Q*1J6ݷ׶:OkaUBe‰dGm;˓wuYY0lvن`'T<ڭ6:m C&D><Z֛fہ3O$ƀS %QT4Pԏ7iZ[U \mV*<^4٢Ǔ;X>C| XL F3g #ffxfM,Aáf(?i7*ü'vۇBc_KI w/x6I'z?L?o6/?*=p yt"A$p:.o%1CX)'Jn 3VRpl">Xʪnaby? H1D_-vCx:CŻy| m (nc{.ì2Ԙ,?ܠћ0@n;g2EsVrs\--_ȡxB̀ m 7(pfO]W:$,HϤUفD;HHTE#[~f< 4xޮZ,rSlW/mB"}(ԲՀ,CHB ĭFkif%QH 410r$Ì'%;iٮ;(oE Ê9Le Lo|N;{~͘w,EM`&cƇh ~iĞ'sMNBuJEnd 9iޕaT]) (|PeNu`E c ep_U!mi[iNzӑ`ZGhC枥Zpr>DgZjQ,6Q1[V2a(0UamJq0X{ IUdhttza<6,O+>z e#Wjf1C9?ՏzĊJh,&^q/؈IwfidZJ<ͅ',ڹ\uX/CPVVpOՇ0] wGڲh}۬SRc#9Rxf]Zd:$ҿؙ^}Jk,N@{MbSoAgj,AF}WFkG.M'q` "/*PsP#xAlK7?aUz,;}B֝&=͔}5Z YHr}.!Nnr_ȉdO*ZMApJ#31 3J͆sXEa> =3"GEXX,YWjʖoX˻m~Y9Q +3A٥mER΢6U>nOd=N4TOA a$LɅ#-|RGk&I JKpyuN4dR 1\/Ev=Mg,'50}xwУjѸ]d,Emw}+[vQ6"TJ2EUYO5VcFJMjv]т'MbSjvuԊwlv=|WNjOO/t  |_>GH#ESk=НpH0` UA+qb,|*2aZ&)Jٛ%E/zd&dX]ߴI$-(;#jC5o@[,o%p2XGCoZ*cN]dM 4rxzBeHя꿹YpXu 10~5=(-vyr'9|y qZ.rwuږ[!e!hRR|۬j]q>ХYb>ąJ^?y;\l&/'//> endobj 328 0 obj <> stream x[moF>G  f}w6A=qQ `$V+^̾̒"%يC:XgٙYVcx>zuuQYF5> /70nd)]ϞYwx^wED%l4<}59{& `8O8(x!D);i0/ ɴš\4׋G)JY8~cVڌvn5Ok?( xlG]!tq ! tZMM!JL(1]Y@'׍AYTV_2ZV 2kY-&?-+Zx\+SI7_YM0>Q R .dsY%}-ѭ`zVJV9~搰ބXwMa K߹z]O^x -UR?P9Od**t5T-b e,Z|Hw.A8tRiT8E/L7t\sIYoV& ƠHMw4/ieszim=*I^YM7qɊ!@oLRTS FМ K ,HI_fS~=Bo񕜹mQB3ТEhG_>+Iv𝕦DQTyɪBUhblU4uZ5׬HbiQ;itpk?zɬ[SN_Fe 0!!B;U':rv(l'^∩\.եNkFj%)-[oǸ|.f~@9Qi1E4bbq%Db(VG(#'T_Æ]BZ)ruYxT,#4f@[ZCV5 N|4;Sѻ#1a+Kh_={z^6g/ao}.|OÉ`IdχLct< :9l wh*EB*D pgBd*SRh(S(ΫNNkPJ,%8A C E|BUH t5^N]A7d7o.fJ 3%$XBydybHA yӻxjLH"0݃5g^c\Ww4돭D93݇NYf̑Zى1)<1C>@?טcH:zi./` ngFk >A҄{H(ra;]^|A(/ZΘ}}>^O!}LF κ#εM-&Hd-V;- .N R62) i Vm{C\JߚO!*O mL `xۑ=XԠ^1lK$*xB U$`SUxbL r4EB-++$R=be;аNjIkT ;9T U3qQOt({Ę< IAG fS/ Do'wb@ [!@ėzO=-Z:ԄI^=^ty\GTu^:5Ӭn,`ZIͬ;7Z ѫu_[_`.S"w%-!l{B"^+}NPECMuj6p¸vw$"WR[]mqJ\_{(&6IpsGdxX/.u|h:`d}WY4_v,ef+f>r*n-u%|h}ۄ 1js `o*&V%;6 :=y-u3nЌ=س2,|YnV"HCŪ^^k/f~ik _az'uC2d~W okIݺ+6^@A|fRg hZ|Gz: !VjU*)nqEM]0t岎vEVaR@ cZpޓ$pO|MUl)])(:%MrGAPT! đ%wjwcJ2ئݹ)]Kɧ*64mh`QesYs!`a8xpsut|6?Y:5ph:i+/ _IԐ+e_zҟlz{>d*'=zO!t|)3pӆھ'oSCIp(QL{yku܏E.MBu̻/"=BV;M \rendstream endobj 329 0 obj 3778 endobj 330 0 obj <> endobj 332 0 obj <> stream x[YoG^Q>H;yr1˜Y H=$}୾{!)jM/ BsXdPs4;ti@Z .oH*`xFkR <( CRKX ggX!Ѳqxv8>{zx]f0sL T\|]%bkkؖ*_t@Ha JTGrܦP%<7}WZդ,4&oTQ*)dXW>/ \](PGM4ounQu(A"͇]'Kf Ӱ2Rͽ pZhդc>K%RIY0_8O? !qK \ 3UݺSK|9mC)n=+ y|9և Fy +Α@LG%CWY=eTHK3[K΢*G<0a *l5j(e&T2֫vRղ~9&< N& VOCRQ@Jƪ W*hm\OWGG_TiuȰ@qiԔ"J2x-Qp8eG)9-Q/^cn[A+@#$$0(z;.Gda+]q]Nh%ձzc'bdN;m=9;OΏŐXz 'ˆI"2S3¤'10yr)`hƠ*c婹e C2n/ēgzw7RlFHlRK/>d;CqQ"@|UkSI}C6Kz":uV0ȡC -J% 9c3@\0VLX`ɸL}K"6(A[,F(g͸8.J? /QF z>/tYPjc*kZQ>(F(gC@uH^63@!D2WC/g}@ %;C H_u"E &5d`fk1uɔsqa#@ &ͪKѓlG$u +H8۰XPlQIhI1F)Wtέֹe%!dGGvP:7SF],!`q8 ?3h*xTbHwP?F@^ћ_ ) A5q q#kw*X,^ -,{#:lA >A=R7ߗyA&/+=#"P౧rFSw0 JNj‹ 0JG?[pD2{QB˺nxR\+ԉ&{|fI&r$&Q8 bJ,Hv6O% L's;Tak *qV~=GxfӱlAPk]sWo$Kl0ys;L82m44& { eHU3kȸX׾EcHz E)ޑXNi@TT N|_$mQ̹Ɉ[7CRoН #*B&;ii;6uْb/jwf|Hj PjAKRXP`4GJx"<˱WND D`*^CF%hZj6J;~,vQѠmb\ב _’2tqBDͣr 1둎 6q2m[/(ݜ+ <޽~s?~\FbQǎދ7Jf޼E"믮hTca?m✀MJQ9!2@߼hY65m/d=%zޯ㎅( {EyL CaF;b+5S4Yl 5yUy$g<>U f ]Ko;(TLY^BHnLﶶh$Ԫ!g%HW&m wIT9ZY#zN &6ᡙ;{2"0qN8ol4Lo4;:? K^n1m :I2dR -FgfX5lˁ98 ׷cdw}ZjNF+eTlvXֈrS d*RM &!i2 [ v$^)8IЗ%Jx!{I~'x$M#OsWtsmb9/% endstream endobj 333 0 obj 3318 endobj 334 0 obj <> endobj 336 0 obj <> stream xZYoG^#< ȈL# @#iCϐ#?xϙDFί #2w2||L7S"I%/2$#RKDp<PE7Sd8mt~v DO'"%R]R#1,xX.qn+0C ]hu/ɟUD4@ @J2mIFT¾%nv龧!r-q`EĔ Z[7AC°(qYk>FDcd@) kG2f"sw,?͊?/F72}o{NWqtXμy(" !mX/II0|5vB0V/bU;{N#vI f NWVN4$Mι.k!殆#)rH)`E-*L'0MfHB3VN‘hdWLK7R(wyG>Y+YybN@v-mjI,^qr+g/etzar^`lIsoP-Yrc Ȑ@4С's0Q鵧Mų4M ܸk.w@ZhpPc$Xu fZ;N/HA sZltY [ȪKP^N"%0`~U,rp4F+D !ZdFZ),< ˓-bhXHqI :ASL؆4)g3"?rS,QdYX?dDpӫC7|Hv .@ǐlC!!9:z?\U|!9yѳӲ;BbZ?r91W@s{?TeI)d-K6O-Y »gBa[70%RTެ*ُV=00(0 1h'(~԰vPXl9(嵞T2&>fm4O֫|>AMJV L%~l|r3CG]e }vǼA[q6HUFtdJ;>8MHUZWp'fssAh=L! ߨ,iRs\u@ypPXɎN8TUH𐬹PݓIz~WDX@gN;ψU(ښhfl EՌ64=KȫF}g}GB 8h ĐGFqOuXguQ$⼜d`쮮 n-eMv'KXeYquy5/<'uR&pi\؄pw>ĭUx*L!4Q,!郾1Om[S\,I0`wc$"%Ugo*_ZB:T]z1 ca)ЃR"P4'v1㶄(a*NEަ2$!M,dFmK7k\J8EGj'^IW{1?4#RFδk&f.#3Q37lVE:"Oe4o-Q(h3 LliGu|{.n=ã(H;}fޫ7R}@s|ngJ`E nrV4 mV|\9 R5X.OsP!2 zY dNÃu /+_ Z1cHjM5nl2ɲ4֌4;L{-\& 0-e:4'8"âamfm_qq:HeEU Ɗ&IYqGvH&ӹ6&i*M>mdk =v WmziOwBnLweN5 }CX:B};A*Ku/ʹ"$,ĨG0We#qendstream endobj 337 0 obj 3003 endobj 338 0 obj <> endobj 340 0 obj <> stream x[[oFg фs[mFmv%ѡ3LJ*y h7~s0՗zJfiA^a3 / L(f7o(ۛ߮H ޽Y^}㛛?ǔ"Ͱy1F0r4X8a4|0p t6'X!r$ xCm]loB f~z!TD gsZ;[ܓQ!mLgꡭuUKӹnWTʾ $%W" W||)Sv*HLdz#) 4\T\ P q7ۮ*p妵H4Šwmjۄ eٕm\}hZx^՝cxD5F0) <Z4 B\\n/j *pjKÿ ( +GO`@uW{k)A;i ɥ)CWQ˭ʊsU9S h-/1pN@zu(D8%TZQT\{Ji* ||{^pkc!Gyq\QBu:(O5.};L,9{\wKCpi\=c☠SяYBt闠_Ċ[ rQ%ְTOMFEG|3#1GLr2۵|Hr( @=2fU( ȆW/+4KrYJ !8O@@VW7/'q"RuhyHy42j2/9ִaJNױpJ/m,~ډ8> 5!RdB WS}9ip%4E, eD%t!8ߖgL rr;^HP]O6*^2К^ .ԊdZz̬vZm>}*̨FF82Cn;)2"D C.T E^"6؇@ x\3񠆞1bZɩ 9iM2L $Sa/4jSZG Fᔮ˯aCh@# ߹% i-G̨gT\{2+:k$Ǥ\_#y{&1|_e|VGңhτ!.E\::YH0sW;+^=rjY<($7ii$O 1(f<'K6yH K0P9qf/ YȷM7ȻyxmdoRCDDqz@\yi8V,v(;_!RJび+xfWAtqOsɻY$V1IGG@A?'ʀl{VK/ouЍϕ6."S AɃ#KmrCJ|G`wlͲB,u`FPeJm@+! Y>Ě\ C`SDकPpBNgEݵ%4x∹&gVx@hB{lmΓOxi裒_VoCR$pJG?@"J8 o{c}o"1ݓhM`T1i-J(z;@#F`i.J-i-@,mRFSbr e1e\ɮ p{]&{${h4 lƛ<Z&l"^z@T8t"Y*l9{!:0)s.i[PRW8@ ; ߎ,E'\ۅR(7A ҘR֨Rݕv6yi; p1υ5w,g5ЙFv_= 3A1TW=#k48Nt&mTO0S.6hx*0qhzrWDž;W3SX0jd -:}C^V\xhm;Ob[VeDNx$c7NIkoÌ[@heDTk3ǖq #䄵1Z+aU!;cZ8N6A-0Vbܱ I GzUk.V0j:M=VEy3YX]}.ZL+endstream endobj 341 0 obj 3486 endobj 342 0 obj <> endobj 344 0 obj <> stream xYn7-X I4ؖh 0o iժI#!ֶ[-EȘ%s93$1"vp/?I*m 2JgvɈHLjI0+a9Sd8N} L0:1$!, ÷NH ԰ :/!Ӫ ҟNooPMeqU< BRZ{ak LY#b.Uy, 01{Nݮ@?0I+\B'#pUn۝y7'ƶfL}vq l$!dl\MeڂRbb1]-q$W]w.nr kئX7\BlZи\d&ht-duj)Z3b,C{U1<}/ƍv‚&_vڔx=it5C".P`kb^J8tb8>0s? #\"@\&L:t1daprR6LW[Q !$fm)ĘfҾH}^猥=Mlm[1+1Bqcy1r MؘSD3Tga6d<҅  N "+? (l[s:IMM(Nm׀ODٷ&8+'9* 'E,fZDZH nR4'w^ xuf:T> endobj 348 0 obj <> stream x[YoHg  >vL58GLŚ8_էHM @ U_ƈd ?׌c<ތgWfI%FIxP"C3%,dC1q8<;xo/:HHMOW__pOq*X]슈\s:&%De^LT f?aX~q˟+ ? ^ ^s0$a /[ @Mlwz퍷"_m>qv%i1BP$-& zr/0(L e.I:f,,Utp ˨j1^O6 - 5RdB[VNqI#ܮD)ў:K"CTDE3U>=)bCEz|}7u75m*VeqhA"ک{IG8R:^1ApכZϿJvO! M۲idqkCj BGnۺib]N*v*ij~S #$pp-䲚\0/q]Ѩo-2D!-bU4 V @V x?Ogͬ@>MV=_{H(R-m8L,8{ 67E0+<fVCF !%-d"\Pٕiz)ps2*V(3_} FE;e0$ImtIWptlҟsM)@s^2Y ΁"rj0-=JpwDn)U#o>%t6 46 @GC?|UR$Je3]|'/Ωw(HШB8a t oAZYj&dz~c0BQ"4C#g_v(Ă1N]|)!YW3ki7烳zUddpoߛo/?Ώ,ɾ ح$MjϚڳAV䧚f~k'FGRz87)j^,֝`5,duF 'p(16`_:Uaְ;_TJCi Ϟ5r^K1I~-߆QMREk9^MSiCyA0DyI}ωi='x'qy tIyjXE*U yvvQ0yH<&l'FJt`Pl f^~U&jk7[./o(Ɲ966Ķa~Vǵ>R1y k5_#LTK;+ [䳧N!ZЩdBTwzjj4[nʾv:N?PR "vdOi 7ԵbkUe9 ]BpD}TDV^CȢSŵo떗q a$`O SVӷJȱ*3xyWATZE\=3̠uWE^v!:k}m-YN*ISkeUtV/r/)N C=dkR|K+㡏lRQhG}!px_`;l]]c]GN)PcRgÌIj7 ZJlZ- JUBY"Ε(M (]At(ƀWnH8(lNr&tojv%(҆EI :Muj4^Lb(l d"[p#SI-d•߄Fz4dcQD!2~#惏Q$- ^[?5ӘI@&3xʏ\D'^&ni/C43y0I~Y$!a+@ SofC?j4v= O@PL7iF(T),˹앎#ehIPo^hP(q m^Q`X*TqV ڛSpx1[5T8V$u׶V{H1] )WѥiNg$Ȯ\(wq7wB섗FZ7A(E&D D$5xl`SV;q;hjOrf'Fp r[Ȕn..̴U?Svo0ȯn06ͪZ dGsj3%]8!m죄Şz-sY5,'K9ԩM&d0MK,UO=@Yæw3ً W 8v{G,z\:p)zYoeP^QN~q(bTeiNZ)ת'^u>//YD6(Md\Q+Jߖ?S2(>!NM(ZkB-h$rtG#߈&D:ܛHc)ufQqcWN{6۾dPt1V})jhrOv;!å^>b{l*hQox\Zn:TO\kkXҕev9?0Fendstream endobj 349 0 obj 2870 endobj 350 0 obj <> endobj 352 0 obj <> stream x[Y8g  0>Oǃi Gfp"ۓd-"%%RK L1@Iůŏu1"Cleː3[_O/d$|8ȐHJ-rL?}F(q ŏF\!-Cv0%Q;H ԰l)U<2HU&afCBV)-4>C"2uSK#M̞֋r-{9LHQ>q|T` `M:_wsg%PJ)=AK]5+fL>fĈs>e@$\헟Խ1gIrz ~v۸n tr9MMn3!d6&[/ _/x2`\k&9H}"F!#@|p߇d7#9esY{'Pl9 &1 e *CR!4C"Wig>"wHbNE.IS1%b\Ǚ Jr];mP7,fh.@~DS) a_Z1S/)؏?jI:`jK΢6iP t&dL)$|3*ĕ!ӲCQHwP80!*`}7d=YFYEXQʬRHpUX#µ{BB6J Q*e!Ib)c9Շ|d&C}M>u8cG+~%.,ϔbےRawS)Wu'釈 +P0 `0gJ [H|7]֟̄B*n8HFifqM\KP*&Hƺ Lռ[\EB==#cUГ/J8_c:,+jo+O42^┊l2[ 7IzNw=[ةƩVM#$8[V<ˍ/X38D%3"M6g?u=~3|RKac`=p=ygdὒ^m6I[au-{v|ń%1onZ9 x<8jd0j+W7g&#!bU@%`€;Uݻ/p-1wTi& ||u|sk1ST>O]#&]ϒزLl`>r Mфf[0}.>Z$4]3n{i3XOmOhvMָs.VC2cۭ<AP a&"#!Zo LZ)plvyE İ e">c9xwvR<esfb\7u~& !g8 H-3ʤ5]9zdl|  q IP'p` Pطv*Y<O YH=7B̘i=\ǹgLR EL9yo  H4>H-ԭ%9ƺ[Ȫ&LFM7*m]j]zfUճq5Z߸_ZhP`M,b|o}Ah.|TA^$*gyAoDi$Y\[rHnyD Dv'ߐZvCDCոMTz,-sQ5xϞ16tLE:"q"Mb_Zc[HjP|V7> endobj 356 0 obj <> stream xZn8~  lSax`h36@.MbGC3&}CJXc b"sCbDlѬ- fA #GaR:Jdh `01$=׌Cwtz}ʶsԤh?:|>pŇN%թrg? 0qnbRHQ;a )4J78M4݉@286+ctm x?M(IGlyqL ꙸYF$Ƒ,$i%:1L9(_w`,N? W>'jϣx$^_ڎ IhUe?א2sNDC4IoGTK<ӮFܺYCP4EU2,S!,}LnAm=MH:ĘW׆{V[)WoF ΛJMdx=8|7-)>C!(g<, ֱ\fËI re{"V;?k%8f!z1pfxڦVV>.`UPYFN0]ɭ!AMX>!+RXH9[#\BPYW5GhQ7=Y:,(2V4U#M1Kl4O'I6)H{K* b}œe`5/iɽ"-%>Fϳ7/A99&0<$$q9W}[Nhř&W/fW >lrLIDž# \ @N]p es 0#v %p;9 tNO^x'PIi7D. " e ٜKQ ,4$lLќa_6RZ*^,b6߭AW)Őwdj*jаrR IL6Hv s+@f$gp9m5*U4(n:.7[Oƪ쩱;fO9u'[ٳkD r=CIr+Qvˮ^@{j涎pRY}8(-&^pÅ|Y=d]cULMqwsrG8Rm͇8`C,'_~F]2>*CV3 yV:fAant+ vXX\a$5,h HpP$رvyTM,-zc`Ѱ4'ym4]ꅙĶd$һ=d5;ɴЈU9Ejk,G2[WCڲ}B) 8ʚWHL%1Cձ=GťŵPqT,)CnbȞU)+{Q^T"*=Q_Z竌O"WY]9ܟPH WW,)5Lʰ2$9В;vH+ l (/wi"ˋM9R^a (]|Z싫ٵrkDw^AG[DssJbCCШr 46(EeCq+[4[ބ)Σ>Igx[cIjPquzPA\]qoΎqQT).> ƒ[#/:){ =4k Ŝ{H=QnHSԔDB:3([,u+qq 錇D'xRL9Vӫmg&Ә7m>"x:\=pNWⱆ. s[,\"JXx3-0s?/+=łd}W^|u]L:>r}eW볮9q/&oj$+Ջ~<&Cg4ǁH0^1aXfc J:ny)iendstream endobj 357 0 obj 2157 endobj 358 0 obj <> endobj 360 0 obj <> stream x\mo7>Rbr~pl1$ 6zzqVR/o%+Ym5J<pa{79|GXs7=&gTQ=%"7=S<# a"iɫٵ}+<==cȎ$ʏ J WvH!R1a;d" w//ߺGDBFaBR)HB#Z⟍od)`*FMݔ q0W# ꗓ>oP^\^(c{6MXv\\ R}NĨ&~2;CK5_Qqp < w4=PdlCl>ϋg'ŗa ~ݜ[|:̿|L ^W>`\ ~ &SaƳCEHmyD͙ĘyVzϯACBZs8vһDYJ M=^.w̭u@B9%1 |}9$hh"e!f}MH!!($qtTNN?~rlJCΊIT[ B;FQc`# &edyE O'$$pKK,6I˰8R"ANPܳ6)Ip$Rq@B0$ѐw6.UX牢}F /S@}/Խ ;N|=sc@A:i~xXSGTˤ`x,%=[Don8w6wx![U(,BX/ Lp K74,}_@kqݎsb d/]\" gܯTn9ɧpJp8FdVj/xT&v?Жke/؉$=O3R? C.yFK.2aqvγA '&Ki#I$qFڦY/Ώ-e~?=r׋s~e BvCTv6+=1*$թsHARARLDž_i^B)X tIS =hqjl6bSuI Mu@:$d<zeܣѨ<t E\j·ԡ%M폮$Svu# {ʪOiksIvgא !1H0]-NcJH:\O`ɭkB |Y ph+u MT1&PHLfmspq81lvG~Hґ[hH]`?JV= r-MGР=Cd=|V@8$-@s`iJXLO Y/%7A17vFWy77vS^L1r]3HQtR[HfL.l!$&fβ{ɹ;ڲvS嶞) &P[m ccKpRR% dȑJoGͲzR+_-tm j[_?N^1EdK*RRXj|Wdv #9k PĶ@WD_rw_!wTk1+4#LCm=o>2X:5̆3?nBƥǂC1V YnDUwni#6}]w B;@ձ:lZjo._muf{7wWSendstream endobj 361 0 obj 2994 endobj 362 0 obj <> endobj 364 0 obj <> stream x\n9g}}%#c[ޙܞxV]61Evj٤Zc 0TuxXUpCkkgc=v^RՙD𮃋 0Pdt;|輡~!(c2;9>?>g\(\>ޟ_?L1? v8O__̟^b`btf|oؽ)RDp&.&Rdse?a%r;o_>GNom[C ce™jf(a.2*iu3Ce/|b+aC2 6dfl2n2c95ޟKEd7lL۩Z$Tn΢UƄf-{ek 3RTĚ1 uf7=FbLKZExt~~;r?&{S@J6F`p3dgzWV5;l:XKĸ)aC | 3&z@s=BK  Ѥ/#;t R TC<طmPEߗV&,ik.y&^Ľj!%C]x;_Bآ.|_V7μCZ˸,Dky lSO 0Y8 z\˽iY [aq8oF0zsLojɓ!Gp,Od/^V v~J12KKى@'b'dɮZW&e2u ?٧a)oa+h*IB^V¤yw]LMx&naM2я>av!W-yZ`:W&:58d,LwzZR$G(B p*ObdZ -Hk HL錼HzGQF3%DTmPE= Bq6е9_VZr$FI`3«0 aw>PLlS;3x<mwaA.h k'%gnCjHC;z &@HWفպ4xys5qN (S ? H-FOגVH$uK=)ueHMG6kƸ;?Z`1FnU]jb?^X&&q,_֒b!X!&a."[M&OBlnC@M9Livg|\tuqdh9! ^>=括-܄wiX4-pgJ=W~6 H#\ 3tyGEUTB^0gô\! ŷUPǣI^+Ǚ_y\ͧ?p@@Lo)8ӥƘyǭįͽڻs>=2LU|͟5֊9Y9$DrC }JDFf_a)Ko )ZO&A$t1S \=e1U@)w<YF sg3dow * M)5U=H[6.Gwc9T["FyC~5N'85aZLȼq*/BBRVq -@- X~:)g.E5mF*pj,5&:ihj21nM:n>UbEnG[A$&M T%"u"# 09& #Yc׿6zrUvl6/In~/d,R@S"2VC&H{Q)ݗ1EufVQbo1fEzaHM\UmK3&p [WZԥeK̻XfI>ߎ-7Q)RJeue ;-'_iڣW66*q6洬mm-!5ܣuz0޻TaWq_|=kaӥGU _HU+di^p)>>mQ\m*K)]BbS ,mJ( /Q2.l%s fdR"`= +D?5``HUE|* UJq4q1KM0i2r91,`vs/gq> endobj 368 0 obj <> stream xYnH<5dV])t\ T"!&y>%ZE x̹|:w8m|o|] ?ito 2JG wDDb$u$DDFi@߰~آ N>\۽$WH ݿi0T$ʯ]u? J bI!Gİ~b EKW_.//V&a0)d&"HB#j܎S{@2jĕ1R'x\t~\?[4A([Up~q~OG^I]qTfIzc]Y5]'}qd炌Ƙ]d--s`e7 [U>&P [Ę-0loD*<IbR@#A`gr?Tx B AgdJzʝ|9ׇ^Iarg.ͦY7^ ?di%+ /jR`iwGzMo< bED 5ZIWf?Ijr8N.(2hMtUo}F!jJg#IxQ A2L=[M"%@@ζ#Kõ- 1}i܄M0|f7Bd38X+O]uHl07M87$"g2?y| (@XVWgpA`Y1A$8pVp0Ja z?ϯMk;͠÷<U)[g֕"hY[$nR.BTsKP:2H鳸߳P2}MWOB-e1> L2m/Ѝȟ0bQ/wORZ;uJS)9tQdAm0_] D A8t.n'FdjJޅ @xXu=bPneQI땆) P^R5@FPr=F(㡘c|AtE=g0(q/09Ey c[5٩P;fp *&̢'^XNggE4 sׂ A8xQƠ|am[2@`|TaΒ9S= (j jW71iZy:gg ^z~r%FzNɪϿa/t .(^PՀ!e+c~/Yendstream endobj 369 0 obj 1762 endobj 370 0 obj <> endobj 372 0 obj <> stream x\[oIg K_'0 0> Elwp{N71h'vswN#2w||,./ǃgd$|8TC/JdPj  C 6{@1qxw|5x>H+ixE $<}z|}47NƧ>؟'N RH#C„/FTi%9nٵ}puY3ƜldQ\.x4aXڧ#cx<2+cu4 cPc\+׹!co>?f˩{RuuGE|749m ogK; k_ǭNd~rh!B6ZWṗ `欥rBe'M|4o`L^|_db=:[~qֈb⻛t=+Uw#B%B(4 QMT)Xڎ+@)V;31_'> 2paer(:$hTAh'774 _H"EqFGܮK'C4bLIE¢ǽGaLR-|[وjVDj"Ѱi9,HzU.OwtnUz,Em G UXD#AB'ˮڜN1}-fS F}}&V!UO^Gf fb0Q6 }=u0pw9_P&CP&Hm-U-55-[~FIK (Ls xF/>ɣg߾ugIqXux l# "f~Xk() E_K?o >< qDl)EOg?3SVr+ږZ[l^hj2+$ڼ><^{!έ*T`(eTLJu:$Ldwus)^PL{uޥld:c1F0ެ&(Yd#fMSF~(P]&.["C:HP QJMF|]e@Lت2ZźmRq; 4$\}IЮl5%MߢkauDgKj*x0P]g(Юp;GU# z:P_/g~v&N8s$l2mKvzϵ/!16yB!(O=uBQIȲ(oѪw!t;(=\M/JBPhmnUNlg%:%Ǒb; $HS']>zej:l05ZuroIS^IŲ''nʪ]΋y&1J,S` ELGJw|u}<)Rx#%¥2UbRuo2M_:BIbi;}9 @begڱpd첚!MՀr< @#( V@ŴI<{ѫeqIk9 n,SX1Q@QI;ydCxKP)zF؛dށ \= я().KOGUtM$we'掬-9iqC[YYzG> endobj 376 0 obj <> stream xZ{oJ_D޽W*,x%Tmعs3O۩ҰB"09y1"Cl|!kg<> Ήj%|8ȐHd2DDG^B(xq4헎^͛\DdǐY! aI_{{,R(/% 1Â%a8,}wznei_9!#C„ Qi-2wG}ѻoW?>l5Jn?\,|b)>? HbMͫH&<9rv7c6͊bрpĻ}ʮU!G4KyVb8_n٢]LbL/י}DJTPb\2 c`MkM ;ˢ4Rj@Hy!_3BGl9/NIvs1]ʪcPժՌbeygO9}>- 2xB+./C;%%iQ!.{ߜ<xKGN@mJ`YHt` Z5iGF0ы|D81쀊 (}gYZ6sp%i! 1#AP!S@ hx.LB+V~"(6'`04lT "JI82+%i$Oie0 A*NYe9""YR.HBvMa,],"_;x8 Յ%CqҮ%$rşb9y+&ϻVJ !( @1x5C3Bh%|MN^bC88jY5sHL|:հ._C28xazzz?'φ<8-%D(6 _XB$mmS?]-1IMsOGoJ;K/I CQ:1pB~M+T\*\scWȃ :F9ca2$3CMU*x^a+Ҡg ɝirY6Og̕ECѮ2H6_?Tرt H/FaGbȎBawXq7SHKПH AzzM j&."NY,Τ`q h{`ylL8rq{ )G`N&7ɐC#ۀ#H~Ih8ne!b%g)#|=tƢU*PgFU#+.}tW)]l8o91BtjDHZtl@C Lq$pLj"xh_B(EQPq"o4*vJ(p= IqAjvUYiWbuo#,i'hcsWA$1ֺ`Hu@0 "dAI22XF$dHҍI6p&|zЌFe<+&+ꠝ8^^x18) {+>h#q#[1/&> 7d:F p_e˪.Τ.š5˩:q)'9&\d>1ܯP +(&QL7e(AE@ĶIJ@R{ !iuu dL@ho[̻0|mB0_f?PmynC0ǮD:[ UZlJŶYO ɟ`8\P EE1&PJ@1TCT"|Cyb  M70_[qt-: [o=k-AێVJM7yYZ&ƨ' e,:TZ!ӎE_De2ͯB'd,ǝc96Vm n\'l*Z8nZ:K۴iHȿ!Z.LAe&~ѡS V;&V| (|r*͖} _>MizPB%-c)zmshIY t6'P .yQ{fFPٹ9\87p~ gj*k?3_Nk̴,Nlk"z1Pendstream endobj 377 0 obj 2883 endobj 378 0 obj <> endobj 380 0 obj <> stream x[[o8^`+h/H&uw^ [Me-o1?x)ɶ4v ::;??ĭ>17H*yGǤD{/R?=׌oG%bOCC į.o~O"GOt}8H4 G[qAw?>H[ º/< ue򺟯6i>靾;0ˋzK'>j=&Z7Tj Qۭؗy׋f@Rr=6i]} VVϮ\!iN"˜_?tgKDםI %2e.%ؘ/@`gcY.HšKf?jpm:L!]I^; kKU L[뤑xtle!,Ņ`\LJ64䳣Z3f4Ya7TÐ}IUg݅!D]:))[bݨtl+%T*剳-Q#Ա Ҭ58q®ZS"U jXfyҞ.lx:Of5pᣈұ*$(kܘ(IeTNIVmʶY&E]sQըY<>[ek!Sf&F#VsIcLbTLE AԭbTkzoŒ0t6I ٤%gNȮAƑJ?׺ c0u.C4ζ<S ( ~rFV%@tFBmŨؔQBaE'D$bnu|wĺH~_lV0,Ctj@uq)ߓh^s69toQ@i'oA!YEmcwɊ« B; :6)Q @BNpPKsUb`+ QFC0R:r Ӹ,]M~N Ʀ/llӲ 1'$q,f_ ^ 9u2x48g4f~/<`<]ߔOSHV8 8'>Ƞu!|9!yZR0B~&ZD  vL#E$A{A*Vqt)klH<UUDU+4N\ո^ E|ɬP,&0j";֞PԔ߰HZ'ɑKJS_7lxZ"sۦq|/|b5ȟMړ"Zvn?jaո1e6)ERTZW>_,fiR;Ffvl$4lqSiIǛkM$_=ֱl]7W?f)s侞yUe,֠*b6+290?ꅞV/w[m6X|,!@`@'i7H0Ӝ2baΕ£BfRS.Ca4-uI4Y[ڴU&\5P'y\ h-LDBI.]ofA@tU 2Wi;ߊKuA!d _|gUYX2t)q` te{Q5bvgI(ݛ" d ,fy}wٱZP|G5_ȨFmo4 ;+N5h I࢘uM9!.f/bP nUGu-.ꎾM^, DHw-ҝ| te0$ n>]]g Ԡ (yʹډJB( iMK{^qa:m*yth:: ʘ| 9>iẘHhCFJXvVR촀{3no0^! qqnP1( #'DDB7,"yfa^ xyԴ!|N4_ ,]P*3Qw챘'xg#^΄t$?#y - \#{-}ky[ exӍ^@jRoyǝ_yM=]kRƎWّ+eބeENi' /\)%v~$ًӇiVt WAqIH"#j>o޿.>Ϯ/F/F?##[geMw]kN&jY]ށ뺭}UlXzaIu6_AV_::<-Ǐ5͞Pss0gˀ_ݞ /Rx&>͋Sw M6z\m3Ћ=lj[iyx_468󷯩wPuɓ'!1Rhi?QZendstream endobj 381 0 obj 2645 endobj 382 0 obj <> endobj 384 0 obj <> stream xZnH^O=1 u>21v.efV1<'Ib @ _]_WwFdw:||7LWS"I%/2$#RKDp<< g|)26?:~f/O#!, cNAJ;VqF bX0_;d" ǡ߻L" cadQ֔$@uWňpć#2F;IS@U\uX,|?`MON>?5h~1 XHQV d:siItC1˜C7rAZquB0xv0(:XwyDajaB̪uYdhL x}~Q$4eyT:U3eHqտ\*_wWd @2KjT|(*2/l8hv\hSS F(ꏻL|r>V]` 1d.O0pI>QYL^eu}1"*œ[&U~=+Fɉb}uXPwsYOC*B6/VդKkxꅁW:4QQ-#iZ7 zGE?乫<BHI6H#YGQpHd&UDXS'6DY-3a1ۈ!!'{V!p 4 #1g߿o{ LFxWu05,aFf)00G9FJ20:~f2U2R'(2U A-Y}vf$)ɨJ2)yr9˧+ DamWv ɗB b%⼋ls'òN @H@-0_))Lowd,Z7λT46K`: ]%Oa;ȫFꔡ`դl%Dq98[9*҇-:O,rlh/@*i]]vp<<‰iXEam#i#A~^ V:< n{u|~mpxN c= A =^R拤4LՆC@ҰWyVTB)~X Ԫi #J[RG1)TU&߲T|m5*' Zd jZ˸u=-zDY?TV7}bN='7>I}C2!ML'물ɔ=rL)Tw0ɭorEҦơfǢ{(gLɈvRYϘ8&Ru1ĩ@pI8k=4F]ܰ*!? j7!{dEvq`ߠ*Ɂk1Z_쨸py e),Fo5,7ڋ;oL/jnem9Plt}lD.bGdOM;63$1Œ41}ɋ{`沾'_j('߾Q1{geU}z/ ̖eT3&N4”61uLao#4]"Td?dأw –Н\]?Uփ(N yz& n?yrPCysλg8&Ѯi.KZĔb]ےRj_{D!wO5l1sJ5"̻0,++{r'a,~`z`Mħd2se`[ḲIRÄH .L{[f{nHS<>0K@_=I|S:GHo4N┎??۸T8 \f墜W{s;m *giaV1>a&yK1 NC^=4 fύBH0Dְ,ӮtN\f+~js}e&΢/!mW/DWN(c }%l(=k2k\w9Wuw!2U]Sr2Vy2V ;7YoCpTF|^Ehi|gQsn0SusmVJm_ħ,u#1|`8HD[E@}H{{ =JYlP9ie"*%(2wv;.3 E6MQ'#*> endobj 388 0 obj <> stream x[nGo>[} vclItvabGxOcSUuU}`D~֗֗6qmg0n跎/md$ݿmTm%2-vzƐB(F\3}7g&b7{FcZ_קi,bWϻӷW%01xIۄ #@ a!iCq_]g&2}wqẁTFq$#͙( Qlr)GnnEkڦfGJr2;h|hk;B›ӳU?hE8Qw mu eyD:.ﲥkUHq|/XJC}?\8Љ̼a,]mO rPGoY +XZ+|0F/x5O>0xul{) CF1&,b8VaQfTFCL]ET8^-Qg@BPI.~q.`Ls;$WC<\da$LG7'‘~:/`mIm-A,H[bH` 4 dM i e|#%x;bZB`fse <.ۣ MwpǶU؄Zk|EJT IU8,.L{dLHw K;HF_H^O*oMZǯ^/Q6gI'Aqaƶ_0;?3Ks7bpM@ hHxx Pa6Tx-$c'mT):xQ|ԏL|1SK$ZV29TV3 v~"09!#T>\iX@[[EԐ CN!FI` LBA0lͳ?g|0u%pSkPܐh0NbFLI!yLJ\|HOUod4;EPJ:'k|qU@=3! f[B"w&ڇ)i SU?Ua kt1<ɖKK Q*K.%upXf0 :׈SGÇ2AE:JEQpa}lf9 RV ػK(J[GD)b^UB0Z"I(o*MEm`**4Az`F馁28E/@fZ1[*ʄ!F0RA7.l9V: 6T2$O' ҟeIM6Ξ9㓝4"I!EL|m'Q6ƃRE\{e Pְv3uoӨC2Ubg;9aĎņws`Ә$"<*znu@KNnV;UGϕUʡFwF=4IMRO RAk`*gІ * CMT\@0^Ow7{6 jN66yP" 6f:UŌؘ'Tk:|ï .g qy6\dit;}e52Jq Tj@?pz:I\,aDhXKah=t:´R 3D.̳E&U1<$sŽN"4ovQ:'8ݟO/Ŗ C®=Kvq! 6ik_|2 J[t?S,Nc?mup+4,VCRra)ݴJ;L W8V8KW\fKUC _ Ie:0 +iTPFK!hO_i26G"\?:U:Zrj5RU= ֐txbMm\ڙR5Ƴ?MG\ڋ;/E&)MQ"&Oځl2jˮwíe&VB˅Ʀ`a/H[-hH`aȠJOއJӄp|q(wv`{fZp\wAo`;LrWf] qr/b/Y@^gpjDچ^ tS`ȂdOg;|<#||vqUMKq}տ>{OzG/N/_{EfI~ueXozIF|፽.arcRMh:=պ-p/G*_@Vy{.U/dM@!l_N> ,i0'0+W@2DI0BP0Mm,r{@K;z=dށ 7 ʫt"tOn8 k΃C*Vׇ=2m(_ni`oP2Eendstream endobj 389 0 obj 2910 endobj 390 0 obj <> endobj 392 0 obj <> stream x[koFC ,tk Cv FmPR;O)G@8ޙ;1󘸱gNGO16H*xz5/1I=Z""DG_yFwG8EKg?=3}ξ^N#!, c߾ J oBXŁd C)pz7r2 34O"#c„4WM@ 4^\>seO_NB~|\6y"d Lu|zk&&MpGN) 3e0 @g( &"*I&\\)΃jϹgXTuB7]# *5ViV3Bů'J mZ!GyTՁ+-i.(D=c(-(Ѕa,_yH$8F$#z4>r[l*wL#0Xƙµ&nl\i`1偳|E%w} {e=~5JQe_78gv%&rQnQJf7VkYJwĒ"']# x\1 u}*C=J T "1bdrX0Nf.KLFeFPƓ-fQ;1RM@U: +8zS͋uQO}`q"F\nWY9{#AR2/֛̳Uq au|~j YWV!\<& cpLxכRCd\Џ**&YaY%s %Le8,T609x"8)$jUV2-ebL3~Xnާ $*!O,5&}>@r[blM yWY*PS5ub;H_CFr? ̶US#Y]ׯ` Y|br(G e`& H Kьs>PXEWItf  GV.Җ.K9==9xSmѓOo_F/}.Pl'@Fv"l2ae *?@ \:z-d[+L+W@ZVYYةg'T _W%)D>X `X8bV?p@`oM.M.[HɒDe Iȕ MՋ-^o&1}|'1C"DdS-\u㋶(,k!XuAsG  a,%.#ELˀjG^7\CZ: lIM(a'UԺߘb@0u-d*7"lIp+qtz_3uf 2AgLR5k `D=ȁܿifәP#,u6 v87!J@~Q;m)@D&U`'i +[ T(d:u=櫾sQq!6<8uSx;shH3&ۼz'K˱PM\G&W zGӐ0kk"AZp'w8ԙ'njm SQ~5t#VC\Ǚ)376d2ib:N?eCNc([wǮ?tcϋP1fŁay5͋c"sS'/ιH'xtǝxIJz8S7)wufzWo"7V\jsL؛mU'Ͻ7}k۷h*5#ָ y>mӁA&t`Lܺ#$y L~{hw2 ֌m {1q#3m6N_r 0+]ԟޮ:7dI)> o[9Lۉz )Sjw00 wU8ur IꃝL2d&P:Y3ƒ?x141˃ wQ[925ĺXg[߻D'\Xi!;mBaO '*}֝{s`dۥFQG#c;~tj qןu F|*pԷ o_7sGcB1*115#p:)۞/[^ `Oډm:N=VT< KDjV դ H> endobj 396 0 obj <> stream x[[O#G^ѿ>puUVc4H 30>DBM'0!#?xOu]nErsw; fַַ6.l>鷎)ikݿkam Ҥ-v:Hw[$ALQ{Wđ4!nKبNW/OEyجSh/oj->^5 (EY} KnHr&g5kv͌iLF+-yC4EUQpevjĤ/$xǯ\-M1%\;9 ϙ=|qssd$R{[Ohb%I. 3TPYܻu I"|p_>o.?ڿz'7߿G*?>A!Qb$0Eлb%{l(캍ᔋh:}|s 3Dy mUZY@?8߳q1nHXs9/G6b—/^ˆҕ0 B`F!8M5- o 78I#^wA(&ٚjő%r \qZwҭGאԠ1e`0[,༢n " K44~Yx$acj#jJ8 YO"AS3+2M 4sVBx_O|,Fc%밤C8A H@ B8"6pӄk"%n9L:Q H8dK?&|y&ԛBt0w?3zL_y_š,ߕF.ơ̻~/UB,@Rz<iO.Oد{>l n{Z_J箽0Zt8/-U@ԵtU FA*Kx%RS֨ |fJC-9N8/?,v k=g&g9"$d嗋 U)e| p2>K9rƘ),  }0͖exB<]Y3XYIHC*THm6kyUOA~[NeMSP6eLhRӐ5'e+elq XיZTx" ײ&V dtI s8dVKmȓ2ɞTU[T6= kEXp\Q" /P$t6\bh еFuzD=0&̇yf9sO֜ NaMX sS@dͷZ X~giLM]KK]SLZ$Hl傰rzZ念9Ohԓ"UVp2_0C43M)nx ⚣o_)&b╴;8JP\o?e:[GN>uib^&$%J]__Pa(Mƭc#cǯ`\^R+%٪ߌ 5p "u|ҀqKᙆէPX¶:KjmLViFW%UV} M΄(AqqsE(BoXWXٺ^7?%Iԓt[b7m4#8:9`xruDX݀3݋oFZJⲐ[Wj)++-\g.]5QE$L}D'uxO6F6*a\Ql')ּ/tDNO.Pt]aeU+5@(B5)_bkԤz X)O&P`1ױÍ 툽ELM;tUlW[n T0)zj/{p':nU7)fI[u͆ᶼiIMč(s(K3z1ow@mx+z64jqSVlZ/RzPT=5lBy+y.OnVǼng+5KLA<֩~W,o> 7wLCNoϳPp6!{( ܑO6l\#:`uw6@d"C>JB`XŸtOn'9fB= ~h6FRشN B*bj1+n A6\ǬX1}d0ߣdT?/jtشNͩıV__ʃZְdb7VM%ͧ QF S "(3QhnV3̇a̽dȪ7G>oII|fϊ7hRv ްR|eUX ! 6lDYƓWC=d3Yxpl+mZTE:jaJ#඲q̋DVǀw j8ISֆUb@ѨR|%X?.yn» ?ÆEr,?e=endstream endobj 397 0 obj 2969 endobj 398 0 obj <> endobj 400 0 obj <> stream xZnVg} Xw_:܊6Ћ0mk jj#+I-3%dSUƈ'}x7]7H*yt>IݗZ""y@7n(xq 퇆F'Iph;`Ȟ$*] J H!/İ{d" ǣ/ggݭL" #o@BЈ:G{BFXYQO:84T/rOV{B}]0 23Û9px]f;HNō@Q<#F8_ӲXNFsX;i?P$qmwt_Ww{;NN_X} " p r?A R DItXJW~yˉP H nK<[zu)9u =GeE$A+i;L6VcESyu/WQ@j CXU[5_Qܥc]̖`y /5A]m*B|kb G.+M%R[($} ֱ @l5Y@_Y5(е;mqR*0Z>/ MoZLb&MS(ža\`RtM;ͣ$IF6_9#HDhjYW@\R@(w>Q`鋔DLסJ5ENTv:ǷN)b1k&q@ 6:8$Cu[/ŷrbo @Ux2MƘy/b%Ʉ!xRbr5  ڥ$.Cb1IK]}W<+v,O`8_Q[T3r QctCx`~&[/u?[ו -3B8'|t4Rf ImV]fD%@aLxlV)dEe PR3,"4w8%ά)Wyu gM[!]wb)nFxjaMc& FxƝ{ܨqfZlgU˓'C#_.GW>'Fś;r8]|Y O.xOǖa1];?m-'m.9OyH߳SwyQ?Vs {DlI @y_0HoFvB % qZOB>!vt ^Ȱf0f*SKd%9'.@(2v%7lIkDI : ݴ^v.̓RΪ4%)z;=8Rǜl@!n@ i&+#l(c Ty<`̻oOTRx>N I K#dw;2.Wa' uE+#fqyebnzUނD/Ӽ.gL'2OWMa=0fT7PF."#[wo $0nəZ!q! ey;')Z zm{Vq6ř0.X0k^/SPjQ.sBJNfH&>> endobj 404 0 obj <> stream x[kOH]Hai z?f+AHkh  `BΣVl<طνuԹ#'< qucmTvEmR \(m% =4zE1qbҊa } 520z~9ƄΑg``Ȇ>8Zl}-pOR2|u/7="V9׸):o_@ y#mcdm)mO[ڋ2mMZ_ǟ:qzG{v3N`BaZ W!Pe@ q@0Rt4sypׯˇtŪzּ0q-&#k,(I^4Yګ_!PTh$HqQ3j*Ӵ'##eK Yخ-]؞|rK_?ϣi?~ M|a5:^mt8ktbFݿ]@tpF3RR:-O{O+g2;9CX}(1c.Ƿ=xyԺNF/oŸp-c!3El?~9 fʆ-,s+do/[ ?\ TYZO؁|[gv$> J>oWgLl܃ISݙd4Ӂ@pUMrUPAL h; #tŠ6֘7iNyg:K ccN)qen! yMgݶ2H2D}Zg Sn{Y|n%M ڧIfC@FZ>>R̻X=]߽֒s3JBU^95`d!mkp٪/3OQ.Z-endstream endobj 405 0 obj 2508 endobj 406 0 obj <> endobj 408 0 obj <> stream x[mog 7rm_@^lG@GWr$}V)h!9|fvٙ!Fd;||'?hↈAFRɇC%"r8<3wѝ0N4}חW$WH {4xe ZA0E?\]s2 34GI #3ZhD|4bN@ʨl*&{ nky9qj@S(GJ#S"]["U Gν $\H0nӼRͬ%S[/]a\_Í,Rla"8!%2 a$L-[.iVΐ2",VYPc4d:"e2^: "~WA7W*eV)0V|F"ʍy‘Gq@;S!Y4]#mD=CД&J-u#m't3@Sm rͰ\ůs|5N*r @6Q oK3/|M`w(]DSh- X (-` ^ee1)s%Roel%1wHOG0ZUYp( H__/ɭ`YSp+q.}A("r7/Vlx68}%dF +M$_Q!T{'Δ.v4FG["誟)Z8C{)F Z(H|"}upB aRL/'+/t|]4g :ATWݾY!J|yc LʨN5qcLlꀯ1?ڲEWW jE\P=A.?I}V1yXj:^R[do oC֪%B`Y H6d`ۙҭ99)+4YPm m6Dy(CeMiƴ?u%l s R3)i#PnS *`;5_5 ?~]v|@Ds(-Y35'q*#Pn`]Ӈ+ #Fʣ^u/BvԲjB>'ٳoD|" Uq'{xR#hzf8($8>E7{RFA ڌt}xxR~ 䱔=7sE k$-Uz `6B6t9zd=*I1 % G`PطuClu_^7!!ŘE@Lf ˌ005S()Zn; &iAb`VqQy,Zb*ϟ )}D1Fox Z.8[(15o\LQ]r(XB ho>AL1d!qj*ti  Ӗ|! Wbv1^.9PuT!i[ez ;`žt\HEjcgT C4k' qF&1qoΧe4/!FRL-젫á=iv9~~=Nt6t;#:Gj8w[cbv5 \_iz[8WƤN)?Ϭ0Jx 9a,0TxM--$e7` Kn;#4s>L^3 ;'?=Cc&U [O4r7߾q7-<^ꪹUb/,3ʷj>ŽgͽQ ae0ZTش"l(k1>ϫ32ƠL|"״~-w`h}T0D]4uHnmڴqAv0srSlZ,4rZ| ~L _&o\adB@ܧrD Y?\4|>5i4u7$\x2FoS1uoMxfm}qCu^=j??>v#1#}06u%[`q5w ;tȟ O_B1&/TVT/jĬ_>Ɯ+!nh00")ELuG( Pԫ~+xUYKeÎ2 :Zh7w\ՐT9W7Wl`J՟;µ;̔ϮO|h ^ޏn߾;/\'޷~ˇ8uܼ{|M{sqS鈗:.*9wUzl6?</8BjzV}ɋ hObhga> endobj 412 0 obj <> stream x\Yo7^`+ؗXѼd-و;Jv4x6i# NwW:"1"l ˋ&č?ųN 2J>}AkRM<(% Ln_1׷_Pf]|H+iz/݃I}}97W8D1 0vY{D)e|o_dyG|ϜkL_tԾp%U@};,),#'tyFvȜg,2U|L Ml):J}Pĸci=ۻqƑ<v咀 $R=Cd"TƷCBHzS-EH8:L,<29R R0d5 0?N|n=sS!LWCIF{@ű JPN bXP ֳj=Qge<,4e,0vaϰ3`x^L07ljn{ 0c[ycv06K/nul~7ŕ``Lf9k«PJ&4; 27SOJT,:@<=a]͚Dz6z õ9eLzE* Kf0~Ul꣖i912zu'm'V3N,~N-Dyt͢0:H/eF Bۂ 7 PTԪ/?ye"f݆agg,n(Ѵ1(ЌW }RZD(-L[˪@)B!+}YE@p`FBnlֽɪ )$i@vǍg^Iiu7]\v 76vs6PX6J4̚51mrz!*͸!ܚ&,8hCc=IiuېV'hQkC64tvW-Ra(cC;2H9G0P!v|zBi١?Z߫J<)SZ+! =qLBFJ;:՛v5A(NѦFhsJ51֘>b-{^AQR]Hj׉Ox9Ô` DFŭEQiPQ`a*NloRDžtm]mjm\p碄O6n5Iܚtjx_߽uG0. IsydOVS?}1ήl /:t&sIc]wF*]zjRBq}.6Rjr eƞ yևfa\9ѭV;߫ Ϟk=JaxF$5DDǤ2ES9ZHq0*:;Ҥ1bmetPKKk?t`54*]e`*_I]t Q lPi;CG5"yB4@w TC*L{`ެ\;?}7> endobj 416 0 obj <> stream x[mo8CSax;MSlMRwn@:jc;ߐ"i)"K,)(zp %lLjmm\[3^196(Pb<2*~LQJaj<x>sh @~}u29<${O.F{ ULǶ07&M aNMhih1܀oJ0ƚMhH"Qp?gP57Dhc'd]쏽}<<>}_[6OI|_O6y0G\Uqfgy뤕QЀ!-o)؋:? Ϗ֨γw?»7B\`^)3FDBO "9$ jivoOR?qEM|ʁEږb9JP"_L9`_]Wl2ZITF)El"[ͦL0X%ٺei$bm:Pln֙W.N@P~I'F"ZP̺y:1|<;1vc$)c^ey$A^ *C|ďAU``F{kLbn `0lE>KCJD$Q T UگZ-"lg>6qK2q&8O1'q\+ ؼlL Dh8_mOћFG. b@ GgBD$[-`mj\e-✕,[x\55Ტ›4OCbF' u#|!2z/lKRu謼 k2kg'uZHBd 6d%$hH&$/EJ92ҕO '%Ŋ*ɬ9c l-Ǘ PZ$\` յ_H =cv󙧒UkL٪[!E.&~c% 0Qٶh&NN[+ָXW23="+hRZ%Y=k.#UYӮSdaʼnFQ-r2mw bN!AOX)n2JTSic@{q15m:)zh eh=֛y>[\zrhG-fJ}{sڟi{s&r7 o<REhy`q].RtU#Ka:ʪE$b[ABo\pʘjr5`7eFa1&$N+fS!0GuyxҠ#bMSTxHMXcbTX,צ? )tMhWO;>z>kϡ!ʘN7G+S1e\;0eP6v(^@r~O+ Z8d߅kw2URp)c]^F .”ۃ?i#IGY#u=/}:Y4 MV7<А"ڮ6ʁr8zZ+_7W { nĽ _nX ˍNG;7IXNTwg~7{+1PC5{Ȫ'F!Y<1Znx+/(%ZYz&Z7﵇Q]>7Q%P=nP# ֮ )m! p|F\Js}QleJw=Ti( [SUOw#h-h廁!YS1Jx=09«|1DŻbGlx$SeLs^NC&CTV- +ީo[j_M*Nvx[):~}8/.=j[z&LpE]f+_R ZR847w>|u5 ވ~|efn*[/:"p:?$9endstream endobj 417 0 obj 2741 endobj 418 0 obj <> endobj 420 0 obj <> stream xZN#o?FE׽jDX(H1m 9svȎTWs\s)}l0]PH "X4awL>iJB4Po= (d|` )&0@%ܯzzh\O{oތ%sMi`lN sXŢ,̬ͪLIF<]% %tiV0Cλ<7k)'?ЈItȳ}9IFl?SO s$uPW~c>uJٷLSzh>~2K#aٸSOM% _B|݄X)ID4:jPjKuadZsMlv Ҍ(*DeCUpe .x K s :+Aa!db)\(iPH@cq*B "'mI inU,C!7 i 9jSJgeXܠpt`̼+8n#EI†b|T+O*`Ck\dլ\A7..y GeYW'r޺AI$!D;L !p. 5Y|UT~^TwYi/9E`Zf_$*ú?@9 <Gr:VSW˘ǶNKJq[5Gc bV,cP\]V4T̉9uƒ9֔ !@mP#&[u2T 떤8Z[(KXlNdk ȅ!I4.N\@R"ľ0E91eڪ>XQڡ> a DM* \ETy`/"YU/ wu2qF$c ]:B*GF;\! Dcv/rnFmVyy2:"JE:ͤ,4-;F o tlR䡃K'<]5H$zrz/ܡ@kF ~1]D&EpbKQ!4u>t7@"bR=nʴ_zC$]ͳ*#C6uS(Gؔ$PPj ]_ˮ9cQ | OXj%\D?djP*>d4ҖT5꒎q^ɭ2[4=%nJE /qS&% ^vZ"Ԇ֟Dw&E #)SgJf3A߃_հϢ+nnb4+u^D`k7@LzH݁'sؔش18zN6,tuߟJW1f_qUAc6eLpP6is8ZB€ٓ#Vd5a0C56и iMS:G&51>:=zD;nX̌xaלgϦhSwi\d/3ܢp0yP}0$]66 C0SG%Ɲ~e'qYTapy6aļ9|tSQk]0EZ5 󲃻Qw;"Ffslq@Ш;g8`-2ߖTPlª{߲#Ġt߽To#w(e=kXۧ% z/(?nbu=_mnVAӘN4<|j߬!0@u~`u j# ԋb P[G;M 7g3 VputE/}tƊhM,Ƴ x.nRk/>B9c3ȷ)7q &”ظ`Zj^clz&f._{C}7'FWqz[ 6,pxr,d/ *1 mPAHٻ8|\6ଥY(DC[_U2>Mp;qv= $ (X5,P0ąBv$)XE'>dendstream endobj 421 0 obj 2525 endobj 422 0 obj <> endobj 424 0 obj <> stream xSn@}W[A"ӽy/ZPW %;چ8Q+9sfAջXG="]HTpdn2 "0@2먥yq|FE)hN_'n#}&b6˨#DVX=H PYe LJ1W/i&0P4pS ZbBU 3+.߄1tKUPv7/촕v^􂴳Zoa|sclnfߺ&y|EPvv Ak d갗Q:ρ7+$vq<{Ɖu ;=)t@0_>}* BO,; gڮNSGbUSU]@*U 6pbAiFZendstream endobj 425 0 obj 498 endobj 426 0 obj <> endobj 428 0 obj <> stream xYێF Q_uQ}7"lַ%83%Q&L;՗&%,Aٗ:ΩjU/_{[|]|]8w75_#n>00/ vo?iL,^0u tń_o0WkfwOáǴK "8sqCfrϸi_>}WIiEc}[i<á" m4C[h[<\!ǸqfRsejaJpt Üt,8K+p0 ΔχEc1x(9h4N]IYerSEgUEfB&B$퐯=]dvz| y{R6IA2v9Wv~hTN| }dZXwܯǶvAu%KxsG (c'qF}1_5y* ya|13 #aH>N[ K}SPpKQ@J{@AC;gK ia!%+{꒳RU ~c4$IetW)g1@Jy6h֓1O;BTR`[~ƪ' ^wn"6a=r6CW+KOu `/:js6<8!CѦ̜XcٴW=5ch9e񖖲6:a$ae3?5Ƚp/ (Hfةt< /Ŏ(7۶@VT!ߡ*:%tHI tߖT)78{.Gm)vP(/(Cef,WHWq[ȇ$€2nl9p*M(\ ='Zzw\SR"}dSڄh^V] FC[gi !΅֜J<:uty))v8َĎWYA$%!]S\^pw]!a.䲵'|B9:.欇'AH5+9}eҴ7xlPTyGEmVq ar'Ո{8W1;+ *p3]!he8'fG}qSd f!ٗgVt *C)&u۳MCwx(Wf|, Bl'HG`p$[y*p&'ٺޏ=Bm465|Z}I- LqHo$"}.ҟoOy!QBCWVw9?䜴Bc姦(j3ҦXA[" "//`9h1c_ljJKYrѬnaqܜG悭;g(94}LJ5C5L SB 7=E;d:%$P'2^]R-Plj"ywqf1ZV+/zx}xyr|o럖?,^.6B ,?JH_+mc>v!PnT/֬"ǡ;C]$ Q6T{X.9i{B|6:»ezW*^pvp)ɴ;ZRN9thaeϏO0Zz (c"ĆCO@JHT&<ⱯHǮ?'#n򺪦4U:7^57 X!'KFlSU=K lz?$- ͶoLX)οyMia?> endobj 432 0 obj <> stream xY]oF-_}JX {>nI/ mu%f#{뒒'EvD܏s=wXlVz}3z=;:y+ZήnN ltYh;VLϮ'~r;yX9WH\|tXGYha[V()lYn"`V]XFB\e{32MM Yh=ZaEWM piL&\fS} [^EFYaI['޷nw"fB9צx:U-7?5n>$teS3Jl\V,*aҟ~6j |3+ opu⟾A!XܹB9l1g %nV%*:`٨(j]дUδSQ7Z }6 U%ptdh#4v0\儼ҢVAmz66J@6m2`E"XĢH3:ǡoybpABT]4=lXzLT,RPl>e՟1Qv?pGfPjunnc+J)(nB_o&j'V]]mELGi:#[_}%df< vH6zfzokC=dG~ v\,eR}מ&.a#<E3&3Z62Od.&Fٸ!K0dź(Ge%}W]|Lݑ/ʒ/S:ԦT KRfVY,{طH@J(5qzNSywwMzԃļf\%eDnZ<<i# J}%>rKöʟ %0O=3913aB *b:l] uUN2 A v)6hإ&)?vY'BC[H< 򽭛LփZ:_Ngv K9,03O. [˛okL0ύ -a55Lͪ'~̱ϱM`ߠ9 k;RSZGQF9I8,ݫ6H ҕBB2eAFAx\.I(m?xƌPސzQԫD~@:<Űs= x>'ߴ'ź p>-Zaa\pU]w9p8-MPH\WTҍZ1Q!F7Uc(P1BNW׻MxkV8Ib$HhB^=%wbRc:ŷJO>EsP_,٧oކ &|L4-m8#LZ 7`61diyi L4(5F!5kn)C8O~AdOcV%[h9EV9h& KMtӉɖN%f.'A*ME)͍#GG˧GG-FӤt_RsTz4FLm 87 JkPYÛ}:\ٌG0 3)M]MdiD0]gO?Ayd%5vCb"GSTNE#edx:~)B ~NrSGJK*"j.n#=o9lm%KInHtȍ.xǟo?u\-TxB%I-`)Q`H@AQFj2-_KY'(it>>/>b{~5{HAMl:i Jy듳?Ͷ]s;y9\0EkB3}0B3łak İx/z·HLE/oۄvEq}-։/4}H#N*dߢrϺu8g*1[頏B weI&e{As:CͣJpc`@5D][-]eIT,5n"%iY&8/6Vz) 0^u *Uj_àT"EO3Y#nbm˝r0!+$M9e&dJ޼b$-W˚O S> endobj 436 0 obj <> stream xZ[oF~}HD_Ztq$MK([]ITI)!%Su0ΜwsHJؐb! kx1<||\tc lKIyuǀS"r2xy4*"9i_d0)MZ}ja+%α|/e_©0EZ;{_>=m@)3(<ߔ KdYq1'u͋*,1"ͫ (JYٲebhA7:)Z&] ,rQwMYiXp7pn=ZxD(`OlAK=n\hI𿰄Q*U]=VoAP,s1ߔnюHfTA_,8C> ´Gσ: jmVڬH,kQMߙf #b2.P 1tt`(5Ǖ2 |[XZn.)kfуᆪ-I5#ݖQNa!b9 ynhb.)r )B ׸\g#fQ4XX>hu1Qg-vWmhaZ۬gZSQoy'4+&&lEVy.-$CX\##*zZHC!DE'{z;OO(FYXDs+ǔ @1Pk F8 {'x^@TU*t6&[ZR1yt qx;rݪ)@0uٓ =G:BRsٲ(*tbŸӃ)ս.|yyt<.˫x?Xw{ukחgѮnBx{S.S$[%K,z5dAeRX$`YAmX]Rf2o|̪--`AkDQݪ Ps:n.WI5FxA R3i}O׳\Bwh[r9ex@u [{t>ոY,^Ǎ&17M!ȕ4Q*i1ORFz[q!D,=(Aǭ<.:t*$>h%Aʑb;H#ߣ7wUȈ|$>Eռ V`3}sy.91𮈎Va;\#'x_Mu1 D< - <?k$aRItbH= % 7Tt$=Ʊs_9鹹2eh~OzWl4~r!kT+x;U*u!:s69T}bs Mvwn0'ibh7AhJ0 CX$VlZZm:zFG@#1<!قnR%T&Kd!_ikYso`} AG8~`F9Y'٭[2qWi|U 1_sv<Z);ƏUVRG_`pОأ> endobj 440 0 obj <> stream xZmoF."zw8DvN%ѶzTې(R;rwv! O;YqǀgON?P9HT1%׷':$ Q Uyy;lc?l 4au?:K#a{ʒTPF.Gv DՏ]]]JR~BT%MP'xt7˪ȧpp)/:zR*R6_#L"v$FK;J<7Oqɸ˃?vS77Y,>\疷,Α FTܺ=I@|Mi׀hN&,qgVLOʝ< լq 919h9 O)" 6kh]^@(_cWy(Y3+O@ yLY0+:e<]]; Bi͜o@}=\͊vұ Q,1&>'H C$*aG,R;oD뢄fYBZxep$> 0ƢF?n ISM&=Hv{`<Ȗ jKРHx(Ϭ=28w<20Nc/Uh3cEtlC,r*`YjfºÌ눈q~Ň?gzm^Cƙ ²eҀBd789Ǡ8|wO߻(pKACw>)j56Q]W,pT5ӛ|0d][WfDx^ \YGKo8I5{:!jǧMp!++ ԖCۂHm-糜RIV)"8%!X=2IBH4V(PtBh@*N-ۧn=CN8-xհ?'kTz_fЈ 0hD.@iL՚gm=g3vgr8AXھs"jbT#*L hIz@ \怓Z=^8ȖY0`O2OeARP[܇Vv+S1ߩ(GfAnMYbvAG~̖Lʛ]Tڢ gRԯV}~E@2nofG ېPCr.M1xiQOa1 r[r[}&_vI:HZ$5X|6`;#>Or I$QrxwkԊHȉL؜rZrZ%`f}P FGk^ՠ܁s_U `Nng:&l$PQF$&![M+ƷU=GP4nۄ*D:9AQ.ƺhQrP m0ǰ!߆suG@ӄcH۝rJ\͗htB:a{UV*ma|' 1S)0Ylg+v{ V.&b2_Nk:}! po:>Ũr58sl`,+lr;or|H{;,#C[!0 J@5<_endstream endobj 441 0 obj 3148 endobj 442 0 obj <> endobj 444 0 obj <> stream x[mo6g /{Mfs/V)K_Cd[@r c;}1cLX3}݌Nd$||s7"kR <(c% oGs7(F\3FxFK?zs$ Εt=Qx9Ɛ /v$Q?T̏|u^ h¹̛c_8aD# PU(E4ܗ%F?8IAZr4Kg9AD=aBD?;đ2HyHZ._j!np9)d:M]5%T6(?B@c4NY`#~L#^ͳŋSW!*# SK ,sD/R/ZR ` ug4[ ]Lb-˴U7bn<+I *!*l!5?Z&Rp"|I|ؚ/>APlY![5&*jfdƊoi Ȧ8 B^8?V 2sʦy~a $)&._,77qaª0:MN^d*RP7@@ұ GzL imrtzxYc2:٧|% B+aD)ڹ =PӴKi IPibz_x /_=t`)afL<EŁ,|9UTbcmupT"7@T)(dPX@HPyzIK^ZtN*J$ ep<491iӮKNCC`k5$40(I4@N";P|75gYRۊF$3hb>K=0u89coNߡv`v^U̫1]g{b`T6iSIKP\1vΕ:};}Ϸs0|kC5O= u;%ogN6!BC}%!I0VC~gc`X90k:9zjgSؚoNzd ڦ 6D v?KoXc,v$14"gluwe~+@vMNC+a,}dƸA 6[_}?^|Pv?FPHje n~]5W\AA2TS{v9F&V%y  vGPif&tTxc1%2ٍoyB$VQ\إRAļXIF1-Zi,}%/RW2Y8)\ i㷼-4NdIU-7Hؕ yVO@+ӓE7eэ/2!? nEMA>s[ ֑3[g <=iQ%`ĬVxHj{ _^UL8ۓp.-ue$~{UBaǂڼ,qӊBVU>Rݪ~`!Į+0S`I5uBY[}&˴OchEc37mHS elepT\M+uHW'p %Wrc_S^ټ?0dml0wDE"6mL^ig?1 4U;4 Θ=fJ:R V]\ DFSskUWH`kE,bhc4vFX}CY봤q4m-dg.Ǟ 1y.jþ`9U:M] Xj~n*{6(;Tpu.;V106*pi $\mb82G躩Xr_26Zӹ>N~(me(7[n lZ'.u ֛I`,n=֌+p,$w]lJ[$ҧ6gZ,,_-ft}lXͪtf &.\>A`qؘ2][7>kIrr,IR^m[x͕m[>~ڇQbȻf?Dm-&l.66:TP&W#'pwϙu|M*5'~,Gumw\4kY|> =q¦.u܏}m2<>y* v|}eAxcx6SS7Ր04j%neٍ?]jEzy'D`f@vH#s;EHh!pg'b_NQb> endobj 448 0 obj <> stream xZmoF>}pњۢI{5^ćE{T]߯ٷYRQ}g _[m~=uF.S9*,l3 LE]m^Тxy lhѰkJ]շNjyB2bo/Wf _?ݻ~?Wr Q܌g# 0/7lJ/V'!wwחoQ "9h7(Rh4\+> 2l6o6n2CA@!$^>ڿ@S]m~|oWګu2*Hx[zn dUn,6twBuêE(_# RM<ڬڱ3OXݯG QDsw]@u!-Gs ݕM__9#fjvUNH3A9Ȱ_PxBCtUih2As{Ժ&~ovgYN>No.NާEfXP&[ VeD"`Yvc,rIJIƇ%Cۘ3CLĄ>bmEO2&TaRKK-=^)\L=ȸ$#gB)Hp٣,ݾy}+ۡ ȭ[h9LoETֻ[;"̬2).:i:.M-ٜBlqQt:7Bx (t$24^Pd\}Fҋ:- e!X$'J <1F?A]S]cܺNywJctѝt" 8M:*Dtvn2 X Lp]w+7ڇ9N!suaFCîkoSf B~H6 4s.xiwJᤎ)d (̌c}R@)pap.Ǻ$2 X ҄#\Ȧ>j 0<ۅ| G1쪁hMϺHWuEx:Kr5~YF$@kVL]$Յ,Q i"IWe42I b(iV9!~/a}5P|1Ki;u_E")vd~?8hBϴ|R`ޖuLӋ5YH$_SsPG+H Ѩ b l۫O.BA1zfT[`fZU\\_8v=;ksfo/?Yn?2j(AOꇌt- Gd=H)dft#3S2a.v,)APu-(PĪo|tf||g zi ͜g3p&\Dd6@~Di,!fq8RFx6q [GY~KtB#Gs".ʾ8  ~3`zi:(HAOHGLܩAlX\<44Zd mnطpyO_AԽR԰IŞz2&Ic'u#E: gǥ&puAQ QGOp1-WR5ed ݦÄ``=N"tXR)e||#:9#]u bȁܽ+(#=ۀ@5q Bq:RQtqrhگqڟGMP{Hk\;\Z=aYfVe{ &62U (%-cf.yGYSp}نӠ P:rTgPm·0<9RḆ⡗ \u1]œo"Ҕz*XNB9ѹdLNnPH)cݏ}\d^"C =6sRW̶20}jplLbF a>= а{ߦ8,JڝmEB0H3Jjv`$c<$ysA6vs{-}BM\ay"ryQ(q*4ڷL~ ]f:.S)ʸnLF$ܭCGS@2n.S$`<%D/@OEza&V#ps_`h#LgʶJ 6DwOg^endstream endobj 449 0 obj 3095 endobj 450 0 obj <> endobj 452 0 obj <> stream x[]oF]ѿB>|>55MD@@AKt̮D:"4?x g.e[bQ(rx39Pf.gX,ֳ7qk9ߜ1mf n./$/gi{˳/^}s/Y"P?R넋?W~F0&^_~_x&#"R?q9 3 (x8:l˳g[ χy 1bh:b^#gZ:x_HYg &԰ WMlz]u+OKKs֪ދI3)2ʵsLv"P8bXԹ7&)xW)$q]'$T|=|S-lDZlW{C*dyH-3p5-MRZ@OGĐ8:X媹~TN X{XOСSr堞"DF8Qt'?9^Ry =TwW+S5ArAng:"o~lwsӬVMlvP8NqI(-ʻj6DJ)c\xizU-": ʩE9+I{Rw|,{_sb1% d^n3B,f -}Cv}E^T9:SkܗMyfr-@_/VAM`rLD $s+13G }DcMf1#!mEPhC@"f@WMң)1ƥL|49}@fQ.:UQΫ}>3)rK>ipEv(bjim SXvHW-Ai*~ r8VM~[m6Mb(t;Gӵ_R a2^,6eѕQ-" .˜ X"VYOD;<\gMQ ko*Ka.cȘ)b*$PԲmU/NqW112A{i3ooŋ])ۻ&)<j_3ୋ=(W_T׾1m98la{TuFClſ㜩uc.QB 8|ȁ.U%rihTRs <"v^}D\Oi8 iT}}sCZ,z2~ewPgS =DZiŪW6X2dt[}zCvΙA&+C bdO=&6ƗTpx|:V$eߎNƒp3֤+} WJ/uO):-SMyq䠢gzWujT4P皟ht3G`+*B?}%dlJ(c}m~jH60=6?9hg Em SԨm~/GFl 1jg1ᶹp&ͅUgk N7F\?hp3O͏/~M=) DC?96ɱE<'Gt5su CTj٬cTjMG8i;rȧ AX ̡id@KբsoS2]-0MQёT Eb%JA/œ@:#ē҃S<@LCG$ћʤMf2EC zld:0,i=iH9\:i9)xzCx`&m 66䜛CY2P.>bG'}Lw*m]) "7`&xUб{)6O<貶[{`Y~pjfbzP#,)U/лm{YI "qjlPpO *زS%K͊dI;66޲qcL1 M$en %g稦Rc0?B+ p*T.7X /^3af۟(q9Vu!x?_- ۔ź 뛛* Ba)!wE= `gn$A QDbN VI،ߎp_2oU<{-<)\q1ʔx]yתqMp~-лQ;4on|"T"]$؊mo׉&Ygtk~EBL@}I鿵jٓ4?}Z}J6,2%~$ > endobj 456 0 obj <> stream xZn3b< _$U6k / 5'Krd^`{>WP398 SUu) SAX-AFRɋ/ I]H-d1zE0a_X0G"嫮~zs;~gWrٓ+po/(5p,޾uD'Lz%Qct*d4 n ƹ a u9TrFC{' G7(KSj^mIa qyWn[0& >+_Tz&{g+ CԒ4%OFQ҂d֎cjR\c!qDx}ݿ5CF+ܮA3u|V>l8HI\HŘh?tZ&{7دHc 6P68(F zi*Ɣ.nq 7Tv5Pr cL dws^Θ"g5;UV{|\A E?y1> H(0]}0 F"1vK(̾&Q4=  _ = u^n|(VD=^B(FuSK«_ Cô^#GPc`ur.n} q]vI1r E#r/:;eWz:/n&="}n-KUޗY›.={q9 q7q-N)k/,bap͇-T +Zp!9^G* ~.91{fPa r;$SZx;9wrztOrZjK]^|S Q$ /&DS}XTSdžҩ1 ot>w8~NY=rd Ӽ o%2$Ej~^1N)'B.zףf$I۝g.TƧ.u挭=nۥ~ G- 3U) lӣxWq7"ׁHj&*Wr驂 <暾Ñ|ˣvo$FDcR\\j®r9Q]/b"I4p8ǿyq\}!ҽjPhg˾M f* a_O?+mfq {vkU%G9Y;hp_-q#[y \ f^ 3f,rS79D*>.$4mɵ Hny5z9 R/MT4TYL^G˧mfByFL5J4 ܯ% p:  E gQCH7ofr8DHc*mM<&dZV] iXQ8U.`)H.LP$87+[1]Aky8]#鮏(\o>Z[Z hbƷBA{778ess \Р"7:U2TFn.ڛ냵+}:- *sps H 9Q2Lps \HTkZ'774e`_ly;vNYB}믕!Lf"Ǟ).!S#2t7O|Də{t@IΗA{$ <[Dm w?)_GB#endstream endobj 457 0 obj 2296 endobj 458 0 obj <> endobj 460 0 obj <> stream xZYoF._AIjѠR-ӎ ItD);{IR4B`E=#a7<'猸̳AFRɳϤ(|#Pf_ N^s{p,髿O/Oxs&W-38{o#ӌՙV`&[- ;exh!B1 iG&-ܭ!aInۤ^M˅3$EJ+Lvϋmy _^ZE^yibs.ZlJ;P8$3i̝grY.}f 4;)WV*,Ay]<'[F>GZؐl87r@tJAJw4&~.Bj O1’;gif"tO w .8~Q|(*GH!JEb鿀ǚs/!8\=Ҕpx,b8aFy#H #}}8t$̆Re(b,|]VdC&0?P4xQmCA+Ȇo2˽Czӑ;H*eGkv(Mʛ< vT.Īr6.;Lkᣘ877+`OI SMm) 3AwS\@fIB=x`?ĤY>=<}IȌ@pIl/CzA B3<-.C<|-yijpz4Zѧ"ln÷&v>u)Q<%n5YN} ⲩTpS]Lͦ$z_FPjIRvSvsIbr3R ʘ,_+J) $|^r' ͑;1ˀÑr~h_[!Q|tc4jUM^K41o^IH)ӊ%R9$3ƬM7.Œ6>4 UTc* (!:`R^FBS:)x#CTN]d28S-hr ;pH- s0  MEsTTϧxNPk@lL(y2Z=i,59$B `2^-ڗG:RݐGQ伊#E-teH\?Dae&ش}V\W >Z$׾y%Z~E24ezp<$X筀iܷHvSaOJZG* uP[~^hoO\dpRpeq Vt׳^2-Hjg) NMOۀ=N{v-Ԑ)6'оŲ0dկz m!T7r[;!aAm3@ "bUx |YZ&!D-$ImNwlA$[;hn8u0UݺК轥tg%)KrQ݂POuGm JO0035z5 ˑ*L)D}6ncYV|V4o8}#^jR)VZ!5"t } P J>j"wj>;TS\Q U8(ڻhan VVA66o E"z@'k(}'I-p<_^ԭgҾ]AJɈ<_C> endobj 464 0 obj <> stream xZYo3}XZ} `JVr H=$ؿ>P3I@Luu_U5Fd_ĭş|x114H*p0!I=Z""`fog; >b *X/o?n\!-#B(2v J "˰ǟ?~p3 34<3 AFŽЈ:68:"i*#Y5p>1HxbV K[FI@ D#EoeK.) c@cӽH6,,NWNa%"s,_iEڮidj8#CDX\ Sxyxu_YE^gJ)?E"<2L0PMϣBܰ-yOKC3-OCe0/bxҼp `LD`\xI14`8 X(iYܥӬ3:QA$ 1yg~Y:FH Jb!*Tr5]zy1 : /ڙV2N& buMr1LVɺ\ D⠨=)pO]DKV$ca5jiun׮F!Q* .CJǑ ޔ K~7i!B%, "> p_j7LRmt/#1[BhwA-`"9ߊp `Dѽ ԭ;? M {xMX}+=>]yR] ?<]~¬јO~Tiɼ k\J=^TK󞚨je]U_KCm\Y$HԷh&phjge^8♄vAPSB/HlH:B옞e]GNkWQġ3bG+2f-obU#Li0/6w[ b_h(1E*kߡiGfx{_C8*tv!{$7W z]̗3R=R^"E#6E[MGeꩆ~2lS3|m㛼QE\{} b:7tyLm}۾=mtX۶N ,H ,6l; .SSE硁DZ*fb̶cZ,JB{.ߵ/Q sS̟x2NsjvCDj8LW}bA¯?nBߞ\vbowE yvCekB0|$Ի |rQ]ެA)yH&d:P@"ј7hoJԂaƒoux$JF_@ @vBu\Ro{@ 'oܚd(lEiuR*tR$!,.a:ӁlE>HjRXz$PWJ NC"'PɴA̖|I S?Mp$ e" >σb ybfE-KFQQ/D &[L#,+*( Y+E^*DLA Z(G5%i>cGSƂN Y["9Oƶ<:C-˘otʱekI]Tv7e@?4H~&8jAL8#ّY~ƭE46Q}sQ*<ЪlߑobSxVQ+홅s\l/mJwoVoZ}e.ARNœϛZWR&+h#L6BRPM"#dJ%&`j.ǭba~EyB"[%Ʈ,8u*v]V;EԤ2^5\d_`Ӗ*>T*L y4KZ֕B&~{Yc-nV7!GazeA)Y y42#꺭tl,L,K+j !CE*^{Pz4 Y(L(w/~rţ@%t@oz fؚ^fnE 2ȗuc* ?3lI ݏ(RsFɔ>TսAr~~Oendstream endobj 465 0 obj 2855 endobj 466 0 obj <> endobj 468 0 obj <> stream xZ[oF.QB>$_RXmZ-%$=s%u\)0\s!1"cl|1qkg:_NF緌 2J><&՘:Zx2H'(F\3Nfw_:H/D1ݝ]>%b\83%C vd.A a8c0c)`7_mGw'w5;ANwn6#`gfHeY=FĞPALcm.HK*3 b6T0qe"џ|֌S\`$H ҜkYJnEbh!h@hXKx5Uhc+ċA ن^VUgQkAƘJA)B%0)wّƐOCID_2Dʕ"1(49H 9a@EOvM#OiJ8f|:/HT,h]qdWF`%[$1Eskh-BdDT@ž$?n"W1ܺ[|/Ep^}7gS K6ۏCMzZ"Dug1IA}J!񸧪,Bxbم"jx\w2i>pNjji2ף BG RJbIpe30bdPfRquU| |zЊ tm5վ$CI6d^I^Nݮ"8i L)+x뺪S#-Z{NQ-CYW(fȨ͗[Hd4fy`:f))7*BؘR.&5Z各)b<%᦭lj ipLOu5w`J 5^pB,fD5$"gsb!r&Z-߅Y QcHR2jg0<|F{|O˘A p 7 T*]XR&-ee5,TX4Ay@+ p`FK&9apgZ,ԛ =Bo6gHLrw{{+{Ũ?jJkmo}kwi4s"A /Yp 6ś~s7i˪Zz h >%\, { CW!)TVI977媽{mLC&K(y1RHƲ>/TV JspHdSb$Љ19п@G MZ^CqbL$j8`8SMekФ>B!@i/l?B|"1^ @<(;}⽑I.|A#8??Vendstream endobj 469 0 obj 2402 endobj 470 0 obj <> endobj 472 0 obj <> stream xZn ȯ ـA, pֶ̅_#rdqCrp7NfFJ`k` 4{OW:U5%lH91da-9SCGZG׃2MCm5az8^1_~xxHFN~yi?) v&WƉ̤*wI>}8xZE0[Eje 0F7e8gYq]fUXD;V曆o'ɼD0!lZbDQx$FJojz5+ޏ}HDG!~Lj>rg7gu9xuo~;tgÿ ޟ}w[`q @)NvE Q{]<̉&b^+?PPA|^S.FEW]lq'vn{dUњC?UWj$+M(AF ܯUGQ|(/-POӟfk[98Tv/<*vhp2nQA2huY>a5׸[N:&bƟucB K@ W_oC23m:I8 ˬMX,P*2;jTF!5 L3S AVUUKS*j , <_P'2cv@F.OA?Wo#WxZR%&&/ q/d͛ &%/ą見o! g])ts=il$kU}[yL#.P?&UJt?ƸbHݐdAn jPzZF> īj]ofǠhEzY)o)Ŧ)YzHßMu E 𴔥VQ2W F`[X@uu`-8.r25(b/ֳYt =QhIRЄSB4]vV}1QqD+:1L0h2>.ryƳ/0@8^lSQF㠇?04%7_~Y9$E>Ij,a4ޥݮ'ƈ5ߩE>94jiGrT!Cź^gAG7E=vvk*[8 CK:-L'㡓a-7^ j(N3r$abėEh1N}lw&SzL)'jģUaEo{ю 7z6AR!Rl:nE%(&UVdYl)ѓ3YeM 4lZ@#ybCigm95.y VC+%B)oa1V@380g$kyU+S?@}=bZIae9N:V";k+iga[}~SJK*蘐=:ƛ/P?!Дq9YaAzrKI7F?Ȼ02۔'.M3D?yrQyB5klƖvϋׁTXo-#;M-ŃހֶfAW mis PCj?!|:Wk GP_8<)л\ŖmEj!H-&ʌt% !056BZC )ӄG{S#އRR'OMF 5(X(O$9Vc,ֳs[DgKX~5 IA7"  RI7(^ 3EcϷ=&\UP$5x/T%GO 0mMp~~j?)yX0͟T}Ñ7o>N'Oľ!P"D" ~FǫW/.NXKsc`DXg'> endobj 476 0 obj <> stream x[n _A kf/`YD "@Q#iQOMq(4G虩>]]umH?w8OXǗ FI%_L>%2/#_G1qx׳/n!AA _ΏݨAbFϿ^|Ì ×g_ "@@ V# Ix4 Jy~z4ݰFҘ0XMLq}fqyUOfFK#Iy\ͪQ>:npkK (YYIooف% B;Aj+07TfF:Rd&Wj)/ Qse1pۀ1݉-sD URPX$J(xۨS񨾹>mj]c3iirp_u-F#0Ϋۭ& [?IA4}a`N4<>oLqln鈜q9?h!)'m$KdXbkOۢL1 %3QgBahZ1G0F!נd A5Nq7o(F. zbaR1$L*F626Q9ɤZ6|09Y&H|"xG-'N,PrHD_ DSi RS \ܖa-!_}2&z z{B'AFLpRMdO0"9boT16£k9)jxv@oMX g8Y Yf%ycHєҾt!$i,ZkXTU~tĬdrDjo))#{10UfB:wL@KO6^c7DEQt:EJcxb 5*lJNb<.ݮ0P4I2,JVUټ̫b"J]S %[{!"Y`Z'r}6Pd bՠ&&S4WX4fڹ$D޳HeBoʇ"6/,/%pmmRL$]_0nkR56 jCN:-&9v#25^6@h)`2~ |# K2*\fȁvM>)k%#AAb2iϛr4©;GƀU3LZX~1.'` 7K`[E᭙P>UæJg: nk?' X ̢m^5 2!H ː}Un7cC3c j"4)7a L5G?$bCc:%X>v/R}m^jdeueOaSiJXB_0\ӍB R؞E\k_=ɥQڽtg *;dz/, c3HSrP>ypg̤k3bP¹ pLq(B bqߞUg̚3Ym ff׫EPE?ψ%mfmA!V;*K}HCI,'%"5.&aP4xr+@|Z6EjȖ|$vYT"rl} iJ)ϪqaH$Y5UHӨH< 3YnC;@3EܔO *ňlLP1zZ$b9Z̃SzVCS}ɕ҉\T6x[[m%Q5M\f"Yn5 ['7m|d{aiZv+BXB=̯c"?&.yG5$j? VRY=SAh*lMXcyd09Ll5!"h`س0' ;gR!ef{Mdl!h |7WJ5uIS1^R[]s2:rbSHPbdDo*: }ݭgB΁J`V']`-CFBu#@?VGvyz [HP]C26 9D1(KDz;^Td H+-E:lYcVd-É!eٽ[`/VЭl5$p5H{̘tjT&/U,1X"`_"{jgW0Y1&t^䊮)0EFs`۹bLe){j \A G9l+Wt ^$uD {jw䎗gcɖkTZ bT@>:^Ll=0mrybU)k"kQzGҤQSR+Lc[#"e"l֛X׭Go H$6|;H@Ko=.FȂ tjX7BhKCBZ۰XfWtxmA(GVk4P,IoB7ôkÛ^u*tx3PȤF;:  }n$w{7endstream endobj 477 0 obj 2812 endobj 478 0 obj <> endobj 480 0 obj <> stream xZnF]Q_!`_ nM2%#RKDv1``;7 61E,w׷7v'WH [ p??^UjXO3 34ڥeJ#q04/&W?OvSM=%o+gwwaX:&ڔ$xu6 Yl\@EAp1IS`Ic2LrÔzpۆF0}{,UΥsyU αሎSSl m.!b<'\p!؈)#9T16*G"G\q\1wiXʃS#sL?:Ui)o&YNu̦r* ԻYWnbHq@a`k)jmnRcl][u֥:)Lmn\&7o>]wմA zR @X$E{ASmqstǨh$,.c%IpARHK3ư}M0/ .`ٲYvE\;F'1YL8>{XBK #ܻ*iru-TdpgMψ3]ŧIS\ܩ` 9P !$Ƶj&)<=BI* Ut.M<}`'&Iq]Aq֫ @3(`PU ^@xJ% :^wm|?Ly$3X*ŀgQ먝fу9 nGs @q B6(j`r{RV,b?ZAʹӪmbsu)~E]u#Ƒ" ١ SŚ{2lkg[QZfOUde}W&ieyt pWxnC uQ88v^EL*8I!G@"jhm_܄"#Bdy3ƽ3U9/ڨwA93S~sL@u@0-ZfldPH)v!P ۣ}}S:?]q0endstream endobj 481 0 obj 2197 endobj 482 0 obj <> endobj 484 0 obj <> stream xY[oG3bm~I$m-V5m%7=sĪTGù|ߙ93`D2l Gnjg4wd#)=$24!γw67E}:4p8N:{GGJ+b>7Hy7l>;`UR -!!3 P i="b2('iD1.g7`E×Ld,S2-iU. !$ 6Brd4SܠԈ Uf ,̮3Uq~`\|rӐ 6N+&ܳ I-}Bs%1f5cpk-AՕwn,IS)Cc=8dL_˦Ϡ`)Yx3׎75&c S4UHIP;7K<100!wP/T!FuH0y6RMN)i>\XL #qq L1Ţ5 !G_Zi$MttPIr 0o/(Wy\-Ofz$x a-dln3~ O{S,|".0M>rȉiDl²b㲬1n#E(aa4|@Ra#YNv/7mJ•Pg3؇]_^?3;x}{s!B5l!!Wu7{Nnb:czMe0@16@zs:9QhՈ4ŪcR%_۳b8;e|ȖP[xhقXl_Mu NYn^gN]}D"8!nySCdvIq]V;i8Z8EY Jt?Bm'KۈYm*?qʐ㮵fu^j;Nm̷a3j#cc n.N_F;UjT=}iĠ`3 .`:NdQJI6PVtrN@&zy.ʨīN )/a/_7^r OXosJ4a$e°x2<7pl {~)g\7\%3< ?}8}\rOOŬˑÄBnI]f@ ,_{3:Ʋ`")mބ44'"aI-!")NxG]$ESFQS<ɕxR$&@g@OI|tp7+Fll*=&m֩JʫWkIǜuUOXiTa#_S(M{Ri/Ą`@knRWPwrە֕}8Κҽ [zV?lJ[f8!z+<̆m|eh-zX &2+d /gX9lExҀ͖ e)jk.r;mhfDk 6)j endstream endobj 485 0 obj 1739 endobj 486 0 obj <> endobj 488 0 obj <> stream x\mog 7r- g 9 Ʀ}j⣨^ҿqf+!%:1@gf癙 #2{2eJܵj9}1y)<%9}5ewVC "V`Ak4|*[CXyFB %8QwTB%Fm cΧ)z}|-r>؆w狪VY$L~vz~!02t6e;I!W5zT*%os0 407 0A'YNۣS`N::9%k)jGTbLDtC(ur4ފ];o*C #]Uܳs-F0 1_A*Ys긳a7UH sgv1pfXeEճRDW"|V*|߮r[50h&7r@0{!607{6vk؟;떶05L]R0v]櫲Qc`pygK*#nS)TLc]}F8D}yK(@ ūƇ((=B .:t5X+J*w{]N C4P!vɢ*+:|*Đ(>EHOdjL%o(9T{`K`q&CR÷%n?9Rc21IZӦB SW A0!΋0{t?i4ƓH=(jj%Ct2`9X+lxC"8&t~TB!fO)96n'/ kNPxpLM0Ucbs[@x[v}Xl7e}GN7}^@cRn 7hP* T:!\"#8,qӻjadZNO#eH w_.(,2ADgf.r![S ~'"Rzw>ݳuhN=~vGD22s~{$໪ƕ2bd `RS~[da |F(t Nmˋ'"[>˽5y 0@ .f~2*+Ϲ|;_;_ܳSkyƱ@#i^V(ҚF `U[&(0|+i'z;OOP{`%2/[gH$HXfU-wyuX@`,N]Ԉ4qjgIXeHpuC`)}Un2+'(]uKa?_͒-SZC*ª,jp"&GFm&ƛSwۅ;t;BiȹA+B=Z-> endobj 492 0 obj <> stream x[[o~>tsC;U/ j%QKRq;3Ù&eI`$~s.߹#2?f1mۘf1~?\2:6H*xeDǤD0.F (F\3ߝގx T᧋_.:Ljj|ujBF%x a8 =zwqz5=+fAggt~azӅ䒈g[mq&d_t0HoO8Pc) :ߟN?rN1&0:;wxD(@W"3c" LpxSTiWB\V6Rqvrk/}*_M q7`QzQc M6ބMt&_ l[VTB^z^iScm7t/YX&K 4Ư>̖wNQj؅0_M2We̽i@UQUy615 lhY,`/S&1Лu%lĐqCr, jgAN)B\d~ ^*|gU;$E?30JF!(p p+M|;kd#BTK3(C"eNC:ik\X :ݶu0p 9|qa{R&*pUU$P- +1E}[[74u)`/[n$ .:or!!ᡪh^ ַa? b>!R#%xAA7} h]7h|}Q̟-*n?Ua~|eϳ(o)j?W STJi^P~1k^$IƏ$CU+W_phug8v'ν nSGPT>=^7W HF% )g \ mXuyP3u~7[$a?B5nOOvg L- l[ENg$@(1BM0`\BG86| X_îi-ANv/U(Tn(nHlRŭ[pjΖb`&OO!_ 2uJ$p4o@}Չu6C-˶C(2[,| f|緕o1l0LYi"ؙҩz*[׵OS2.rW L3$]-1a` A*@,](=!VLuzubts6nk;8X\gT۹*V2I^huoҍ7][SCkEB׿?ѐāEm_e1Qx$ }PPMxjcZ77G|Cbjh !@({Tvj-9@{l9B;U$Ը0Xu(q5>&uXPY7yUe/€YGPrf^-v55OX_ $^:[Vuݾ$ѸMFl֍LWgf>bDt"n )p ΫPA(y*& */e]dՄ8U klJNhڻuL"x,>DP˻c6.ĸB(z j}&I׼头^uH%%YlѶꠘ-s!! Oq!PUjeam3s AgA48M-mGb_9K@ДFyL.{w<_fM]=*g]d-3qɔ5IA(7:Z^:DVw|*=ɕP8>dG1bFo @d&C"h;;FȞfW2 @x ÎN혡Tv5KqTKhYݡ*X½9ε7,ЄJ8%6)NVюBtvvR`0`#Pj['SAh ;'[M`9%)np J\3\F΁†5&NxIT='N"J`&m}˚,I 1BRL'`VStB6 X_XĈ 7SiPZý-w95$CNRM9[m97PtgB^Y/zdv'1̝/Ј8slLYrhP%XP6ldR?ҋ60Z+bCcT^Glfk')DDT.ϼZ˅ a$SY r!cLf&,)\"Qcy>Oou`Rl!X V !+G0|r%㨞-:BŻHF=xN8BρtJ[|V_c)[,9F`]u6D,B |SSÓ:!lv| /JE` eR%1Y,(p)@ j1Fǐ*'uay.73HS(5:_f+;fpbdGQ,`R2j=H5R)r6roLKB6hBx lM'Y*d,V k`EH ՄX&ɀrc" I|L[F L Sݠ@rR%@c$>1H)RAVVUi3] b=Iu[f>54ї.0DX¹Xnʵj5OA@?m95PMm_ \2,W|!<{\ipyuvY< "[AvXj'Nl`p-\?[j Gm*ZnU`ٚKpP #j*@GhR5Fh3 gB,n9Vk% *`GÝO (>0Q4MB}vb$xX)t Z ڦFij}FK$|v,_d.p+OƾTbڳ7fB٦$)EO0IkZa[S&!]\fC%wqfҴ!93X*40#9jҰv:= ylM1c)?5#OK[1mVOխ.8w5u̳4NԸFvu:~g)c;QqdY3"+aQk媦ҙV0ٙ8(k8[6AW/ JJ4!UL'\N`)ķb /j6CSq Ti7&j~8b(sWoZP*:YXlĪuKV5j܄NPyNAJyUM>emOY9)ɰ:{;{C1FZQ~G<OLg}kf0brz3*&PT߀o5D%@-dD>:Ծ0d K_ ϧCPD'إΨgLT-)7(; @aQ<T3dMt}}oUw_>M3ZGTVgо18DYam$ND'(Jgv\ 0"KF,h֡(5 QZjb;J'jƞ(=F V5S#=N}c5],ƉOP:dlLA ]6c4mqnU3[%dXg_jAb -:?tբk8:kz|%}b; *d\쿌6o N 0Uyn_肩0 . սvѬc.9Tf0Spԯ?Z4fx9|{cy^c8UU,O4kaiW}+a j(÷1ImXv*~k*YS}:Iᶈ1l'@ۑ2fӼ✲NxNa+y0m$qkumP1)Mq6p6m1W&[jwVS#}816"vMWi=`M4;`'XfsbhL]g^cxp^Z=q+m=7x_?VZCw{:R+ : e4;V_"ݶ?,)z`q0vљTy|& 0=x?5d0˖8-)aO+9~3ē endstream endobj 497 0 obj 2720 endobj 498 0 obj <> endobj 500 0 obj <> stream xZKoH޳~LG{ٵv%ȴ]R(j2S$)cVꪯ #a/&_'_3*{7$IIe6LLh8fM]Tof(7&n'?K;tVʙ9Snvˢ͝"4箜׋u 2;AaT?{(ΥQCYpk"U]Q7",E`YN4&J.a%X,<QaDŶU^EhJ|-y zW9| aLVVrS*,fD|ǧ$(ruzĘLDL04`<,*wg I@A:ne洆R8~AmE"x,z<㇭2wZۅXJ)NJi4EMVqMQFXЃ"<蹆 D1 8_y߀-訓m]{HоoY:E4""ir^.vFD#)",*CM~Tfg+ o@˲x_ L@1?3pn.>̲_ϨiGXSp0^3Q[{w59jWLݿßoW/.GAb+[ Y;FP?aw16,8Olr91ntJ4U;&zW$V{(fʢ=4/Zl_ ADA˴n_H5XYVNBp=S6KQ hón>V_atnGFǰ;G]ӹ }֢cJ1V4pŽM~MY@Ȥ(vv>#RZ=(v Dd3 V7h~ۨdLg4cF ٽGd|jc:=sHZ7dWuZUe lP{"GIQݮb#顔)={g @XzJgK%*P-o[8 V.c{1򒲺6رQBxw8g,"wtU Feg.{S$no"@$k8.c8> /-u6ny AcGòoc+#Ǒ$gf ڇf>I>dnfM)iIF?6z ,݂ "h_~R."~CD]>@<3EbW叕 q![_tSnF OUp] կ*06A^!Is:/E^:Fx"pG?PV8UPBBy\:]Ut# $,\@'#T鎙bFA| ugAp/@Dicz<|$7:X "Lbm=>( P178>*H,둥|Om]zMVn9TF_T&~b}Axt1>w\?{*5rSڛyO SO#؃V$'XF'd\t)<6H5 :*mar٩I9{Ꮛ |Y,^(CR6 Su!iJYO}zI o=@.l8RJl5P[q%4؍e?- '̦B^|ѩ>fb+a20b |S8o;۩S[I kp.Q@8&܁b|.0s},^ 0!`Mvm,*N -@sN0[:Oet} I /KZJ-H_NXN>db_iRI鎛)=Wu|Uz2vnSNK(yj` ǣ]u5٢)57WllzL<7WaP(\5Ҋ(gb,Rxj--Ӌ ۅ΋ TIq<4)C1Q)dÝ1i ).]$qN;?jHZӁQ 6T1NwK[4IȺ OTbtH{{_"CY$+)K^oP_4Q ԆU3BX_'kendstream endobj 501 0 obj 2478 endobj 502 0 obj <> endobj 504 0 obj <> stream xKO0{#=dڮ  [%BPq!JH3̺akn zv918tZhm5߰HgHqBRǩI=|%A;nB&3hlWwɑ7i A&zHt?B#@-H:T9 ~ʒ]0R(n>{Y$OWr1--q,i:EoyN@ubJF )(ܖIrmg—Ì_endstream endobj 505 0 obj 292 endobj 506 0 obj <> endobj 508 0 obj <> stream xZێ6]x+m`Z;} ;@,Z#O%oQ,]a6EN:Ee|gya+2cY_8L2+ۇ8Tw_liL^~检uTfs:8gy&4]Uևb;Y-i<nprsԴN2f~ghm lEۆ2rnRfZ?e9vPMLIfp@l}l)\fxq/hwRFvG@5M\XnVrً#dןడ \eLk:e9k*zW=&0c )餓`ȸ,eapHdt?!&AX.Lf(IdƜr$Tr9!8G q$*1R踯OktwFk4eU#AT"|Fptq!,11pAX`SU8X*DSkf 㴠̄s?_ EUMaj@%oD4Nui#d6I7eu0^ <4<零?Pr+v _zغTۧD%LҽgԑuZ*22&Q9P[fD` $H:ۆ+!SӖҴ _Zefz%Ѥt|/w<n2yS7k-m7Tm"Gf]¦~?cc 6ḯ[" AlԮ5ŜJArC+JPzHC?^}u)YT&|7t,1}[9-^o"}> dB;ߐK*Eud11igXo<(hbM8pݶM @3v7U` ?S;w#d.h8-$mSC eHnOd1 LkcA|K}?IC#zr%+scvS[e죨&%5j兤NHZԺD %nu̮b|;0" wcxt4t^=ehCGbto\ʽEv6;*Wx)>+>PxB` i.%8tE|~P)OfĚev™K']]xDOԂ#1yuw_0 _k( f9p .sP~o&I9sG>]q ICϕ?خoo=_q}s{usjߛow\tZ|ZH۰> 8kzG >듄O/ k}Qx$ҝSWevz7kk9+{5&3sBGQwVbkcLS@@8:Rz^Vm5ߐAb ɜo$Q橆:Mhfqxɡ]_B>[mE|`> endobj 512 0 obj <> stream x[[oV^t+KO>9qH'qP` %BU79W)E"@93|s9 Fd;~6&n-Lףgd$||};1I=Z""Bn=(x 8a^|~u}+}==QȮ$*]zyx+72\$2а~rL8b\Ҿ D!DPD9z\b"*|Yb_ҵҙEg">w{R$\wUkz]លb1-wA9# &IXQ(1<,[ ־%8#qu1R:zs$0aJ4AM4QIU^g 7cqWwSGzL%)Bѳ_uG~ѳ_/^W,> EtP P)YqU4llїTO/)ϳWO1ц-6&IC%Ke% ю>ĉ b]/QABy TXy#DЈo:P&*rXf a"YoꫣZ1|zRVq҉ld:_zGQR/ACʄpɸ8jSl|X=x2wAD.<Ή@rX\V2f_BD B|Y|bF"] iS0[ȅcl7@MFIPPHб|t֑@MU3f'l<ѕaMV-}YR^=[/y`%FXp>SGj G"#$#Yyh{L@)dcQ"~~ֳ|bM8s`,V hZnz|q@iәfE f)-2 2mP(I זG޳vgiŗɫr/O1ÀN^?|ReMEB P;'N{-Pq t\ RZN& #5:.#1}s% 1Xl{; ;@C n"QO,Ь4y 5d6<" n]AH_Lbesjt_a=]XOF*AXu͊?Q&ݼئ`PPwOm@E,S;f4OjT&s`3@ y>uPid!<,3GDyT[mLPV#Ow7>P89@;duZ CSVY(tzߢxULn*8kU%z Z&xX|Ub̈́rF%`=L·3I!0J(Ĝ<ĜL5O#A܈>#PNRZ'% "Q\JYlQ,׳,: }DbۧE@l\5V gfKЀh. p b[pvwn50 Q"X,<O'e5}<f(82+1L+&%:@vKSBoΧX؜( ,-K (jhXV{ȰB܄G*2i1vBa ۺJ ܣGK4]Z8/7eDiuUq$c|u^|&vG@-PٛT& (%fM/1DN6Bެ)~਴U^S.mPzS|d^f&Q^E|76T{ÝLoIH'IHl'UT?zgJU2 mҐBQX pZ ˚)L27f雇plxPnV<5-AH~iWdxk,yl%{L7؏(;!y :xz73^_0GjjchU@u:ڻ<Ϋ1Ԃ=jqGr=l*amz.Y}BKCpTQ&hm,-S_3(+9t 躚TEO;8僔G=xP?( ů"}|@ijq>OˆY^jVa> endobj 516 0 obj <> stream x[[._@k+>4ޤ]80itH!p%MQ#\>s#2?w24iHܳg2~5x #TI5$0P"CRKx0R?׌>wWt`T|շoYL$] jɴ}eDI#[CDXj:~s!Ō?}:rAl^ϗvH!՛/EL\ ӗfffVwP!#%u; ]:1m($8F$LjR4TR(/nAӠ7C J.&=iALMA#ҦTT_x Uy :N& @`rv8\mjuwajfoeUa!b2K`9uԺVM  W|.,idS,\ag2bpwal[$ZĒֱ6OWa ]Qල̽- ![u~ŅbY@[8%;b}My2eSd{qF÷q+[,w{weX(`QP> Aa:$&?!UkqB>;'j?=075r̓0LnErY<bPmS2hks#0jTA}N~zI"Nnel(?l~u'EÇ +iP2mZ*źȦ^WpRmb`33SY1`JELv4n1ILQ{53iVZ!6R*L2\,M|7/F?Kz>wżmWy~ u8؆ྑl[ۮFt*%cBpJydA#a/^MGoݤw xחauqW<U[LDq0l?k:/ 0[FUlŴ6Sk&:<zA]W#]W ӻz뻮 } ]W  zG嘹c/P$@O躢)T`&]WJ*<]i~y:`;N`NE]tHU|UiU|U<T;;W@4MRz̰#Ob}cXbиj;uPm* 2i~ǙYQ섉ڍt ۉ]-dM9_l+apk`*#zh;dp!]]Q+e 2B"4\^X{$:\Ns4't|tU7y2y(_ۼʩijWWW_olbn #*$?-U,'`>õE*аiɞ]ofK&Vi|ppidf GS)֕N13Tok I*MW&.uߋ &DFrRװ_e^lIŊ&8&L<0eooH زjYK1۸,:㶍6HfU%vu t,0 |$c\`=1I]jZWnbBQ kendstream endobj 517 0 obj 2933 endobj 518 0 obj <> endobj 520 0 obj <> stream x[[o.7b/n@@\+ڼV+Jfo&w̕\jPL^OL3`pc +KrҲ0 -ѿ~&f'/^?ߎtrN :Avq$-,b:$ipHg*<g8:fȖ6`)Pb ֓V#(nS8 @Oa* 5C&p\_YPƕ| 1 зu 1-cOB&Ј(Cc! C k1gG6@Sk< Q%Ce5ӧeh32!N 490(G4T3 Ԫd<0 xdc␼J8V0GISˣ7K 9|tbS۔ty/5P֭JV35*$$s'ơ!i*Ϋ 906ǐV=!{jfȡ٫&TKSpGrU͑CcXdW15r3rԁ-K3|$]܊tRjҠTV3 H yNF𐱌 }-d:0,GTR3LYTL}¢u,j+&с!q Ъ9 y&SGgôrTV3rwki2-_`C̭Dw{oݎuٔ*GM뤴֜S-5o\{+}jZcTA3_*vX y#i^k4_߷?l׫<) c R+n*?&HHu| mKt7vlaf,;ʉϯ6[ql[dW1*L#;=,p?7~R4_1^PJZڷ`eei{uOY L+2 a&!TYXTvXc#(v&=ܷr, _ϝD8kAb;Ezj_6`5Rk (tC}ۇTڢ1c{ :jCg}ބ& prT:˝Ŋ<&%l괨XZdZp팀EJl2 Uː&M75@S65>nBqSXCRw,Wy1I)MLӞθSVyQ }P}@f-SV=XS ^K@0`L+eUc6UhsBBLkQ({;qHw%fΈ`:ꌄ>ڼG7 {G>`#] Cb̥ULeL[[^R8BHXpAd+mHCߺahH#CJRNkW8BءpRqQw #bUTd,FmT*zj ɥrMwv9ݚ˔wn(C#1Cq 꿳p#p k{6OK*N=d5G 2O8Y+ !eLg_t7jwSVs,p3x0g3dkĘ*}yLͩL{wLY|s-F۔R[f11UP#"ՉVsǔكئ^m@bGL\e=~ 1O<$$L{Mm^ecQWY)f`L^3]Uɱjm1c:䡑5έt8xOnw e TH圻"2 |FM:S3զ:"`e{dO)~k)Rj@khk֗:l6ů,l ,9__\U^:D'3Tכc%11h{lW<:?vJendstream endobj 521 0 obj 2855 endobj 522 0 obj <> endobj 524 0 obj <> stream x[[o>Ԣ93E|Ijھgm@蒦#? $kJZ @ p g>g(JKݿj?\;κXŔ;tp"uQ8;O4 O0I'?w0_М (e9Z/_} _{ P)p-Z&VSJC(n߸ *|pAgW`,=MGAm>e7É&*?:Nf'Y6x1;$RGx%V^/6UԱp6zʘEEc(e8MGw`PUaqg8]&\Yo5iM^@wza̔e+u@D*q1/lT]\(6ƤqNrئ>Ad8^% ec~0SD1q|Ku MX+l0ZeH12asW 5$-gNf'ODI}.h@5 y$OWp:,0BsVni 5 >B$s9"P{y[|z3BK٭$ }+!03xh&=Wb2&ѿIK?ϖ$`' xU#ny@J0|s?GI_NFK`_ ~(چJt]2t`C6C•Dt>}|Wv=[2;.6DXjz:MC)3x 7caǹp،\ F_X o&/?0R21.U1]I$Ƹs|]_N??t^\X{ M B GPu6Ut0cɧ?TFĸWuD|ӝ{O71{-Xic5@EyT Jk(F(jMG0QҺ#D*Tj\u%`<˫殏mthZ,eZpe!Kü!o]\-%kPW{pmP ߣXWb2Q:Oc٦.gf]$ laOUgؔ%:N_zc6T꿸(NF5Ar 6M'y/FPwH)v43Po&Ga'e eQaVUil@FXmlLGpRܘBPPYG-L]`vμi\_z6ԀGz-<%̛D:PvvKoiE+ Ilc\VaޙesQ mn78pۤگ6w7q>+,rEorwXkjͺ%6ꀲ\bXVL$C ;-H2X*H'ejoȐR(m!yT@UQ:^oʺML1 s봍J U&1FTկ%}Ó_ lcU zNlb:ʪOil|p^G !m[mHsa 2Jw嶸ViBR MFk dUP{؏ե9}$~納 'm,mVinc&.$0`$Ulv^*0 %TmTjj<3wZL0 2)0Au} uA Q< *H'"SEd+Fͣ`b7.[cv`Z\G@9%mTByyvS&hKv$\-i)[+ۃ4PЁj0[ PXr)0`ۈ.b:$A9T5cOK&/wRW8:V}d1h+BQ;~p)* Myimyb&UTw)$> endobj 530 0 obj <> stream xZ[oG[70KQHp["!'YW_(=s[ɮC93#a/|{z28;$"3H*yHF$FRgRKDd ޘ(Et֓'v&WH xѻ! aIT;+{1=_"wAv p`] ;\B;TJuql1[Ge |fwzGǭ۲!JkZCvSS y.K R%c6I2f %0c0φs): U0!ZY| p8,ڤh @41ٳ0+-ÝEI]=ةR8_dT4=1X[9ɍpY]N q(!cn]J<%|hغagR ؔѤA u)|2k5U2S)\́<=:b´F ^ ; ՈU^W_`L6)|AQM.eJIQ Eōl>DQ {DxT{u)^ muE+VTнP[^]WjFsXAJ`m{u,^kȶֽ$ي-$4$"B%vWא`ս:t T9iu׽v9$w.^ ZݫkHQJ0}:ݫQZU&>RbK&Tqh-u HP+L̲:hڂ*s Mۉ:xO^=usyB*SӲd9>:Úx! kTUDUJz RUCM~BydY_۩orL pPwOg~( LGbGqq7İU$hUDg3އendstream endobj 531 0 obj 2132 endobj 548 0 obj <> endobj 550 0 obj <> stream x[[4湿/D=,be"v%$dfz`=ǎ$M%v&'߹}>RW>kc<8- z,M> WFB8҄IH­xjȈ[R~ݵ[匀x"pbC;…=o~zgޠ'K" p0hx_O&Fb:]eCacHU q]w4[N༖Vt]oVM71@ě&:*t hOAg #Ԡ+_yU"Ψ˧_Di]ob:Ofçeu-M$+z=ZgVV6V_oL_%.1{|{7BfeLKg$\a0$/ll &,V,-9,-҄*-T,lTFod1+ytk`(&9T ځb"ā3*O7J4L 2[Bb ͧXuTx4&oGY"Wj1[tRpG-6N rrce9Ps'I3)1Ou @JE% ," %&lB *Ab:KKEubQiclY|3 $-v W`r%`Bqy}ӻYmo}ֻ;{ssv[~oup/ Ir|H;Uh}Sm T^$~4-IH~PqV@-͡^ƌJ^$ * (\=Pt/J@@ZF%6mA %qKw;zz,#3סm#Dy˜3ڒ}LhȗL􉃙qgx4%@c׀lwgIZ:jujFAXӉjxR FqO,YR,uLà/s(Q{*pHgYprn5F֚f}GVZޠ|%iAt~K#7^nHŇM%T-MqC@AܺgԈ A>j w>6[ZgQ/*[mc$ ,QGꈶsܫ#Pح-GY,tX|beJ|`]+B Qs]\fqF peN*Bjr9 ymʣq9V%.%*0/wA(v,5i~2 5N4ucȈL{Q}(gZP-VzdwRdӧ@H+ \!8Ƈ_6LIi^p$:=~#e Br0 %qF@iSʺwr;tRu>#T>Ƨ`Cp?uʘtU_1 y7qVPwBBv\q\% xA\"8 U%L[t |'ѯIMȝΜu3'΅‚k@7N` ?v 2c LֱsjU;I0y!ׯp`߷\F'>m5 0ll;kaI:] KgXrAs?I܌endstream endobj 551 0 obj 2281 endobj 552 0 obj <> endobj 554 0 obj <> stream x\ko8] a[a~̷4`t24], 4IQjd,N>|w-,F/OA #ۓ2"#GRKDzqP/xѝ1A',}׳/Or'OWCX]s3 C"KX`I"=<^&kT Od! G.ͷHEH{"mnlhKCmSÔ85 L7[: 20*&AAXN2A0 i?V-38",ߗb14 *EE UiCmsAc?$ K.*C,l/!ꔎq[Lt4 )G[lFEDyJfJdNr A+0I,`5MPhbV==ߐ 2l~5$(1Z,E}}4 EӸHM`,DWMvɵU[?z3&p]}l!P㡢)$PⲴMKxg0ƛ.΃m7EJ!)BV5!PDi>.TW[{"R*zC .-~K`9r PP(OPtS$qķj{361l/-7YB /=EPbbg X|Za*o^e<6["9-A0`2=Q-w$ T\ҧY~/Ar <)(-"8gt'":CcwmF Us-wi^;tA|{ఘ8˩(Er@CFq5ڙnz^!:_:)z@\`&+kF4~S4-o j4K\<& \(q^}\",q0ØPFܕ]qj/3-T[ j"]+q&[慟7 4F~N(T8%*gL>3$,3?H`X٢sh3ΡPPf*nIs*sHrjR6s)U@C䃡@ca0qvץ?qI6 cYIq›yL>o5wE@n c3 =GHP !+}>B]!S"GID.DPDX~"N ՈfM--T[ݚiC&5Rl!X ͳ^7$""IEKʔ0Yͷ_6omy0ffM:,:I%*6^W0q޹*Sf5ci5kr2S!|R$1gKB"D:}e^D!uՔ 5Y>d~Ί Q/ A}3햽DɘnGEq(Gx\D2,GO$b:_ !IH١cڪ`ϖA^+EO矉 u~YXɼۅρRjcm5v(71& ;WJlxT"kM[kZmoK> !٭(-vTrhӘrBMf݇,E(yؘCͶl[=mx| @HMh*RBVC)eV&pǮvfLp-Ri* VZm3. 9lȂ(=$xɡ{ǴU+P?FI Thx(IK9SW@u+gPb74ZV\,|tа 1q>)=iaJr6 }(hP[<8*nNqan%n٪rhĵ>U*$$KG6_vW L wL})tWt:pqtۏp[^%(gcU{ QzVEh E|Pa Xl|/-|vkڶڵEyXݶ/"2NdC֪3l_A MyY RNz'*{$Y.`qo"v4xv?.i|<9UIj)n4ꨶj5qO5(׏bZh^?74(+x&U/xChDt4  n +j$j%"U+q 00T?ۂ6P;,߮[q YSb_14E[,'~\oINp?ui)㔦B_A֛Һendstream endobj 555 0 obj 3105 endobj 556 0 obj <> endobj 558 0 obj <> stream xTN@}W {񮗪41mHb"lH*vS;wvkBٙ3g$D~gkszcJ|$'M>@$yӵ Hdss1jGQl^y21EA{?fbqHC'c bh+C1^ ]PP]3Iݡ/D3!mzLah1lBMQ̸}!ةy$_rc@eѻfe]OduFĕ^ v $ {nWyncPt4!85̆v: 17Z5kGK-@2yiuq)[ŭ!k$sj\R'![W)Fv5ۻzB #˜KZ4bB"IZuiNVUQPp0Iϥ`1 Z_bVȞ~ KHt\lPqոߵNlnYdI0b" #ܞF[y|QOV,7T=wJGmá&oa"$f5oԭ]ƣ+qxi nI ۆQze*" zw(tGwW*'Se/xƽd> endobj 562 0 obj <> stream xe10 EwcYLN3R $m1'(b@/$%/Kb,fX`A^ӌ bġ+0$5J-Ă:CkQ!jOMݘL穮ZPxJ->cמe ?B&)0c2endstream endobj 563 0 obj 157 endobj 564 0 obj <> endobj 566 0 obj <> stream xXێ6oz ;7g,d_ȋEԣiGꖻ[|pdغm? Ⱥ:*ǿͷo n?i3FMMyN2)7wO~j_ocZy7o\Xsp2Y*\K5C }*z _x%| ͌PvmIr̃*^+gzmy|UY^e/;-qQ6nL(NOTt8.AN+<~=4LYf6:,)ƽyizγu Cʛ:˜t0UbWťeb9s)vۣV)L{Y애O=ƍ^ 1G6]<9*+ ^NqV5cfNUٓW۪@PeUFv۝{ @_bJCEa)+dC\ 5P4fl&"@u$Ae1zSV:ƩVY;ͬtN$dھKSy_(Ji̮9LC`vxHq`$k,ZUxAd+0w\ /YCnNŔ!?gd8=wLFȨPʵ08R@=έcFܫ9aKp9#EӁ 1G_J*w}H'W_+hLi%q2"5rtǂ|٪HЋ$qi3Ԃ&L(H:$~"DOPMiL`{f N˅ky֨zD 31A>k̡NH2N#9jBqrhֈ ! I C/oz_iuu}>l㗷FX?-ׅnǧ]@ DZER;% 2kYW8ԛL0*R3ֽ&.uII%0c|Vgh ΅ƒl\ @>eլ[ũXzP[r5:<5MG&咀s3OM.R68RVUrb/t3xb!y֒$O얘}[#˅p)y$g+RP8("+l`&\k(t)( 6 qR%> 3@: fHi"76D`1 +pBsE'P/ $i-z٧\r=p7i@]^!3 eO*\Q"&R"~T$%18Q =)Rqb"3;ܢjg>mM%Xo 5Q!dpG/)r2 YևKgY˸^QpB{vS3u(TK=].XNkq'< `iʺ4喐HKX]dʀ&@Ěٻŧ~;&Wf5nF)HڜKUX}nri*-'>c ]9 mN6{ow0?>Ǘc&q~8&!U9˛;l9RF>'  0F ށY)_ަ38 \FJK53uVQ~n&/*U0lgHeBOa v:Kw_w)~w,Sܗajy}F w;`;X8 k 1HZ"Oa{šATMljLHJD=MC@B5~rfgBwRV^C>A+~=pXuSOaQ~0<+up"~endstream endobj 567 0 obj 2327 endobj 568 0 obj <> endobj 570 0 obj <> stream xZn6]_oI[#q.Nb`160@ wkl%RGR⥊TdKթS, *ݿw;zzusɕ-Z|9 SeJU0ٝ}ǸW@ qeʊ?psyta$}9 E~|wy}ڿ* ?qTa(E|2`tۗ}%\ ^jal6ET+7qNwA̿Y &؀_>%CKu~,\.܄a^R^$=a&ةQHliЈ_֍H% kwx`.wՎaUhCtqJbH\CdYhkjV{n1n… 2#A]2Կhf%A kcVP0=m. c9s` n 0 EyGi c웎BmQ8} AT<ɦp9vDH1H20cQdXB6T %0ջ!>t74>ݏ̋R @vt"ȇ0YgY56;.P<=XC9dB@sd:Jo){6t7(}C [U޷q:4_@ Yݺ[7VzۍSS#BH(EK J82w2J LU&9\M750NFah=3HE00HE2<*`Gbxj&).=˒Ѫٴz ̅r|')*o (e#O%(!G>F` 0{HCsE}$vǁ)n b61c a zHI71xB)OaYc/RytBָ.ȁ&XM36&Mӂ %?XI&a)ܤMʓ9hʄ:%BJiN Cߨ9 sKtu G45a6QeAIKJ*RD`\6éƐe hVګ7q$H$Iz{iD G06]k)uEqĘh8h(Ѥ#H9M* P54c9%aպEc̠ >o|\TQ2U{25N.~p):}b*O4c7ccY?a 2{nE=hpIq=',_l˭V腣j%ڹ OT'% 8I14| k!/-&(@'qG+3G%0; Ȭ27wBD꾰; I $RmNP'7{&keѽz" 8J5y\aPv$ - 3);(Lje e1@^ {;D+z8 R%!+qP9fEV) W:7mG%(B\:!F}[>`(CA{rb I6Z+ ocy^SR:qV)*#,dD1gyëJ}A[sΏkY3 EW XHJ<R7tPDffK%'T|wn)4>YSe􎙂象.^n6[c5$v[l@tΕ14.wR_RC" Pl`ST#Evaj πEה?!٢,+3?L-v]SwsaʭK(}}^Vd8H^SNGiw,FgUߢs_i[T &U3r2mbT&櫇a/;'L'ڛxxcPL(+Z;/͒q5u t 9衆 ѓ)t $,N Qqg  q!J>zAycw*t6`/ uDNOq3 OE/1>1*+-XaVcj ueL2 W]'N:8mN!J%_ee~=kz= xo ;vL*Tj@[~D ';ڔоM:' YȚ6ss7}ċ B;fc0l''p.Z՘A ;A8 <>%h0vX@ ah7P^:[1ϏdL̏ZבAUU:ҡIΗؕʎ S1qmŝ] `.VJ'MR* z3_E#7ʬI/Mڟ؇NXLş*# UbַݝOdݭzC4~v*dv AJ .fLy;&ckcjTLe.uC 王lϷDtf(d3m5w*S4dA@ZW!}Ȱc|]! n &l֮ *U1u3 F/Q.򰇖ݿXr9 ՘˩ bV{IMA(br pKKD fJHxlItT9NMzߺp<龼Y}t;!nDsMޝ:{qv5 +v'߫՛.XwE`f rnA khݍ?]=.T 1zm+~'kXf閬Kt[@Imb#7' Y+ Nr6dT<KE՛  tendstream endobj 571 0 obj 3933 endobj 572 0 obj <> endobj 574 0 obj <> stream xZ]o_&rw'm뤉(` %$T_Y,i1n{ ?Xc̙3* q\??_v۱|uk%Cxvw$׬;0A[oax:z ]HJ.? ?1!~Qx Ls%Njٛ7Χ)s 7NPN Pmo3j>T:S-TYҗ;4О&vzT* M^TJ(Mݝ-l)h۴,fCo \āh [ҏѯe!4NFU(BvQ/'wFxSCKօ/1xzS iRxa Q/+ƥ)JmuvТa[4",Mi $!V`LUV k?xIY.QeM`>UJ(Zh/N$su"'k[!(wctQ?h7m5˺HjqscdSI Up˝j1#;hDz%3[J2<%X2^`SxөoXבeꮎTUm{k no-D%a[uo͑"(s-T6)` 4d,CGi `3KZҰ)V"YL[BB3QtM$vĨiR\4"-_4D3k)$QHfSI7aˆ7}GL똛`x\&3M!HmlLmlCd4P6ۋކ>+$KAiW2\tRiHyM^;zPqP`L&Uth:XRxj ҧZkJ] Y Rw𵟥V'I+  %aY?=&3-J{<1@|kAHd1DL38tuz"&YwLl] 2+M5rDN +m*6XT)S!ʘa~\I 7;d\,5d!1k hK%(#cUM0XHLfVM$X@&:nN**Sz?*}QٶzK)].wԇͽ/7#a#pe`Ma^oطaTG|gŤ+cEQސf;Ua6} ^-sHUCRg\x"v![ @B*ML0VI ۸22vKeaRrQZ;.8ѝltO~_hJ:S*M 6 \x17D3E3QvED 4`F0]Qc#j[/2^ݧD;e|c"&Ih;55qW@*Ηv5.4z =?JmQ3t;(akiD?':c32p_V],+RԳ@xc|thW~G2%endstream endobj 575 0 obj 3171 endobj 576 0 obj <> endobj 578 0 obj <> stream xX[OI~WXy!#ᚺ_J8 )jLC<¿Sn3 $uwna.},GGΈd$|x8dD$FR-ş @( nXWjz1YI{qV#B’iz5OV$|8Ki0 K~yXZ%PX]-$9EJ&^; AJ(ꓷ02R(LH'J@U:B# Wݠ Lr:T]iIZ^ܞUAq:|(Grs?8ϩҼ<aGch"4s2KC~>!k#.!)ER$e>*XvWC@aIq!8Pwپ6uG^qFOBi>|.qdxCL*UA6ˑ찷X>IP Oyh}aP 3}A{6cpPU?1C/S#*?f.?{ZfiȦ`a׸C،]w6!G0{kpT4[48|`"g6}7+eeB l֬IJ෋mye3@LZOf`z7P3D DM*~\WE{NQ:"PnppٕkǓ>d*_׷ܥ]|Vn qYA7t|:|ljg l/Jn1^6orDCHvt6zόm|Ml#]nvo$Fۉ5c @b> _fg)]]ΦI266tغzlyypsEIsb(ei 9?\_/|@B${–6ݑxCNC' qaѽc.H!}O<,,mL=ڮKJNUum吇r-tUSeH'ZZoWˢW6`s<%c!]|O  ٌdʎ5}hN#yiJ߈KL,a72lQǎKJt4E=\Cf}HbsZΜU] 2O:N8$LBXR k!"'iߵNNwA!Da&Fչ-E`zp 145cV;&I bUyB['<fC0vpmߊbwoT-ϽLqp$sSeNf^;hI|uc0@!萟bOS41pImL^VsaD".PةmweimU h:ÆwQnȎG (O0AU*aj~˰_2f`v@med\zS͝jՑc)_˶;/zm/HryIN>ARUCW"-~KTׁ5v g0l D7fxJ!1|_{_9 "a%C4~Bg{P$Iy8gѧp;dGaP~F曒PhOhྔ}}lNd5T q&IwYM`3b&v}PfD LǛ*QO@׍Ovރbk KJ[I[C ނU?@!D2ZV95`Etl1~.F7G7G ]{endstream endobj 579 0 obj 2208 endobj 580 0 obj <> endobj 582 0 obj <> stream xZnF^䧞B[__mbM׋ Zmn$Q:kgngHV. p8<|HAΖSҟrr򂳩-bJL/o'4FUX6UFr992(^\{H! r>9:p[Vȸ̟@ 4~m}޿=xyA垌 Z̺7N83zz4|W[$R%AoݚӄK}Hrˮ)[পWw^/ ۶Gm,mdigtA-ImԴpB)u[mYw%B)F: 9fʋ`O>ݿ'Tmmc)$gU]pÓś1Jݵg #Ai_RRժnVAC"=?(!XI2hヅB#,Z/S:~<~$kt5 6!($O{oѤFaZ%CbArp>6]s*~B~xRIn|ߢ uH$TmԆi_6f^m9DIֻ%Iy1Y tѲiP=MZA'H|bmEsuIM!N,4[b0Z!䮝̞:0Zh0dA`kլ~f Bh2l !1Sh1ZY.Wq04#HCB[KM]H3 S&  %+ Ԓ}] v@`nprt%jJ:WyP$#6)9(i@q)6TZV ,nڶYT)WGmb'[b4_mAU031ob0AJl>}Νm2"pR(1)ҤN,'CmvOA),Ͼtk^\C}0e$~tMhZ c-(#I`ry nU:!]bmFtwBY B Pl_ѲMe@A*Ac>3+lP?=fP?q:"=}6rΠgb# oe9RQڦ칌 21!Aa.hR!2Q3]oe83=\t9xnS1}dY G7]dx̎\f Fg&8(3N )vw!ERp;B0]%W=N ^9mŴI,ܪ.BC@15ڪ8J34լ/sK^G-?H<_Mg<[c _Mds<=?&&)z.+TpĴd0\ekڽv`,_L{:Ǭ0uBa+tOٓZ oݨmy<<[bh'u[@S݌L!.bo9Tr,Q`>3#_3z81I*9>ݑ)YƃĖ dGr(O4ͻ~vA<Si0ۀa>IQ1EnsശjBN(Ft㮏NeЛ`=L<ȤC=\*f:9kSmꃕ '_.>6>Qf"A6@%64XsI#0{Hgj1!d:ޑâz e dsclU+&r^Գ2znI8IKH]If25!HjK>Y3L⠀ EXtƠ>4<}ߕ=TV)iQK4S1lnqJ)ƭN?B'jpP)OYMWZ-oYT\)H̼[տT܀ amVGD6{>w4tW"P}̕{s/'* `Cw,XX&j]ξwq ?1#93-$ >=1͗rlW4 &)0uT[1go_C( JѩڟX`eY _U&vhUdދ4s \7>=[o9f:o6 VfQIĞ0ł yi)BEmWph?&Q?%SThZZ0b )JGjpq'":jٛD`r_}XVcO:Y` y8sSEwg=뷯?zsvK0w`3MAlko.ŇWϏ.4;vg v=TS7H.ܦx!;]Br"{bAG2m{[Տb o$z \US&Rބh6EѪW\q d;d H6O\9ٵrCOѐ#!xP|T' on oĠr$j:̼߸k솬EW:JP=).(] xf;y~v?,L/INθ_<[N^N^86jS:ysvɻpk;CV} >> endobj 586 0 obj <> stream xX[o۸g oqm)7M l3ե^%%OqPn)r8oa41z?{۵Oϖ7OS "ty?q 5J ,_p`CDtxbyycN2BfS,ڧ/7s#..̒@҄SA)旖f#e"®3 #*~i F*1_?ݜ^_Ͽ|rV&I+DF@z4lvQTMf_@2 YJ6N.]nMP"y+9sI9aߺ*Kn`8ʏݧPțX{fXq3b5{K ®[Z&2MZMWO1crYQ͉ BJa&iork7zUOv5A\^ua5Ώ"Yu7^$DiJُu>4.s\^]54 v7OUUXDG@*J8C!QJ'5UH8}_>p2/5jvum4(G PBS~Q)^f C`umtte HIWM| p' l*͔`x_W{Oopl7ǩGC]ubO6!I0r]n>KـuSžĬ~ʇS53ѐCam/$I.!O_(2ځ0Â!2`.7cQiPtΠ^#'ߐ(9`.t^2bpef&1>)zO%b: t."`ŕоp92X5ƀ#^Vbݵ3]ʸ*$G#w;-x*c -1)ӀXSO+BUVJˉ.ߜ,ܮE]%{ૄEI'2揗nm~;g[Wy}g)ؘ5wq-!uQd:k2)/|O1TPՠT^@l{>7MYS RwIQ> endobj 590 0 obj <> stream x[koF]m <93Im 8/[AQ @AKTĭ$~p!)ک5@s=3a1_؞qnjwb;{=?b2\3>͌Ëy,9<ͷg/m;,SV*xw<{ͫwW?Τ2mfù3 G^_\?(IDU7-'*3K咇/r1ЙˬvcvgypjiK&*M(Uˢ=rNvnR1J6ܦ10 8qP6qlFZUAێ҅, 9͌LeS-l"IT\vc9Foh ınW.i_Fw.wq,#8Sxbyv@,6uw)iZ= XGdeyga-$x /w2sY p-(z q;7W4˰Ó uɤ0{8@Q8H/a9:c*M®h:n8C|)!N(Ĥ/$sd*w_]E]A19XU(,bq"RizC' -k'%ܕMm^zqj*!d¯B9]Y.h1'N2A(y_̅+ C7"MuWUqx1lR>LKR~+IRM,n~ {u)w|: 9X~W7[ r|RTGf `}~u?`wd222u! W5wܱby&FxJA\p3  <{s(%4U}V@)8VM@%JhѸY i9|I0 J4{իU %f4h(K z}V.ͯn^ݧyjT _vcehWo>F 3֛_~~:a޽GxO77NqR1]B~Nfy},ti q吻}|ߓ*0D;޷7n_}Beue?10n#,!y,q^c[v#AQdI0 71w$K9'!0`s(O}ݒR-&Qh, h,0=i ڶx(5f͹Kkx{'zkI?YDndK4(.D@$ º9@!S*'~"ՁعQ|Lj("qE @T!bۤp >ֳ\SC Z :!#KNKNeub%ƞ ;ghTXCRkb: ꉣe]m9cSR34}ihYn3.)c mbD`q8=, 6c}iyT}Ƀߪ&pW".'݁MN%e`~*F*t7(\#m߰gs|aǑ$쀱Iso!S[,>EN͘mlSǁS]-BhC|Ӈݡ<u-!frx HFrM=@҄}Q\ *i$&:JTO 0zVxD̑$W >^,X T DR0=~cj)^ +bq~gU+Z)r@X#w%>VŰ/  }a 7|<ϤE%KaJjiL{U9H]wFBCGV 7U B$`YH!e =>FM OPL5J/K4ǽ'25[qzhPWs %Pq 3Oì?.{dQ$"ۺZ#;A-$ sG| fjWE> 83qPOfwHN;u6Yb6VOtƲ1Ex#[ufsMhPҭ-Tmq¥#M 6V1+ E$rJtI8 f!1Cq2b~l{(@!6An}jGSč(́<jH(^!90 |WGި ZH[jDL(ee,5^QH' jәb#\0hsT(qiWARK5릴qG+B%mmm<p@40X"k/MZֈ)f V,=buyB+&ͨ89qiB,ƜM :0DvR&ayl[<ēۢf:V$x-}w-N"ely5@g1vHh\L>ɻ[yhh0,)zU9s|뿁K(`Q)ըrqGHb8j#IkLXwboS38V] Mz}:t̄TIQrKU]K{ aRBt!Gk[oݲ:lKK;6 GO9_GXЬQ[.+obч[UI=rb=zVːw'* KdhI`t]I&HmrLNA8  (I5lÜUr3)._|ݗs,n$j';bF1:o8oPO5d] ,\jӯuWG=z!Sgs_L> zZǓAor_@ G0;Bkcbm*kI/C`^OrIWv=c)eSta{krKCAT҃m o)&.&T'?hQ܌=M8]r5\L!pH9Gu'ʞLӔ.^ɒ\VV&M,\x X 0#I#3T&&p}b+|ܬ2]um%Ajxڤ j3P |3n? ȠI8ܴ)fXde*׏C&%;U)?M-^x @9=l)!zr}22]#dHcͣ6:*Bl0Ng2)SkjOz̓uSX&<ajG`zdm*SW`tex%MqٞY:|v5SycO泏B>@Wf*½C\:s={}}vyvvh/3~vo]]&/qаm<0?n~gWbL.J(֟tRiET݃+#ڹ,g<5z1ܰbǓz]ƀkp)qwlEŽڦL3lJݔt&=ǔ+0yzrE0扈 Gvp5p?6\P=Jxaރt xXרfGnFBܱDNO:'ꊛE$@ijw8%ݧOR#QnQKdJJTP c9Ŷ(?Pjendstream endobj 591 0 obj 4076 endobj 592 0 obj <> endobj 594 0 obj <> stream xYn 6o {w,/w-lf9'KáS=U=G^C`zRSN E~ϳs>~~z7¨n973nnaW\WR,9 rWRY4^mf/ #\p~Z^. S50diu\* f\ଳtV,àL*krάV?Ew vL :'(nv||-` r4r) wI%ɻwhqZ\:0T1+r =C49V`Ipznʾ-00cqX7>CݮAj))w4MǦ/S-߶aTg8 m4Ypڹ[ A܌tCV{=_@6{Ki1MkZ ~4{40[e19?]^/Sq/ \Z^ODr!΁ 6o^@X4mb./CI3ϡ\#1^KiO2en4k03W$t?a T jK/G r6:`4ЧPmNߧx|Wlos`D,^Jw"%!b+ǴҞSn1  ,9J( |0NP۾ꚲS2+P>&r2$Aaۜ$! hYPop Yc]_5 ,&C A Ai:^fbE{ZPE$ 1GU@TJ =Q)nDAR͕W6U'm &KHp1dU,E%F)&닦$+%˞[cR,'( {B rI<> ۤhjͨcEn1hcunv6~fDuS D/I;u<16NK ZhXOA9,;>ELhmRj[j`pE#;Mmk:jr34sզ.#}T7NSM!d4&™t?fڒECYr_gěMfb B]7QVj_Q.0]Jza|Yհ& Qƚc0P`LqSeO- "I&~Bc.eZ* lZ#|A_Li?b)}ٷ=MA< b)/8G'o9(:>R d8SPL lOM/m#Փ G89M|w1 m4x9- }`8Y^OhQ3|uFt$'b@,-sbM&Sm]@=f0 5I4wᑄ<'w}h[>t4ܔ&ꠚ]U$]χ2 m,6ș,Df??&ǏkM5\퐥0LFS|@0F2k]IR(O ny϶r R$*YMIJV?g2S7/^>U]L 8C (MW9+Hr\McXDX Eۆ?va.G~rG>gIv!j0;߹F})1.8(ԲEJ{jE* ]_f^<Ҩ U< V5ˊ.,e+d(&a`Iy4#zB:cmi[}V@mTq O O|o&/ 85<6̥qY|bwj9z;{~i<{MChQr1"Wdbu!AWMSn[)@o-;e .%#&ܑn~ew,'ugUq`8饰u٥P67 ȷg s.\ w3OrzF7?I4u j!X:TH 3~<*(|qD endstream endobj 595 0 obj 2331 endobj 596 0 obj <> endobj 598 0 obj <> stream xXے6ʣBoFqeIm%Jjm‘)2䃷 Ԑ̖lC`/O c|߇˖5pQȘ1lM&üj'e61?.QŬ|=; >[u`gLLf4}Y?D\o= f2s|VsfamqJ؅52<8.)9mU1!$n w KC^E˸͘xdܑe Ƙת<} HM]eΐse(o;%F?LʬfL 镼Hϔ ݐWS3M?"`_R0eMJ3kak9%8Y3"?5UդbLxE{̝-olȭұuc4H5[,S.ltC[oc6y0c'T)#ZZM N>C\k*?_ `!bu˼}#~IwjZigN³,3m ?KA냌QbWu}P5Pʾ+%9k Rqo GX}_\}xqQJx” 8Q ]4<']"-NQ^98Y.V\Y-p۵=0^ DjB k욫9vrii fNjWaf.cpԒug禃-5l*blF'ڤTBZ5(s.ʦuiik.E+g~ ˲)pxrN]:(H9= g~+(؝PA6Ù%+!19 m&a2FЗJcSnʚd6)4؅'="uŔc\6Fzq8+cMpSӦ|=!VL_Z ` GۣfRQPLӢ>4Ⱦb*#j@8&X88I<Ц:IsE0ݹBܸJslG-O,P1 ON5G-ƼmrCtBz8NHxQΨaᾃܣzTnnJPSD#ۅ7@tƹHKITaSi:K%Ƭ.C dGJ29hsPD( F;[:G ~h?6:D]nh<=!d#gbPj`~wPIw[](=<5@O7*Z ܾ h6SUR,\Sh8rS3h7]gjn;bR'1r)y%. ůUPSTy唞}PL/&ӆf7́?^p{ܫ >&;\5I`b&_= N*bUpvB^f7OI/@.CuO6أY F_;a4M(QD'G@i3"TUEdvah5] NBOٹͩs ""duСi[h` L襆rI׫7R/3`:(LkjB/T[8@_XpfLٕIhӛ b5'WU2Bt|bt=e.SL6[ KYסƋ-02C-sQnCTpf̈"GWOo((qIr[ÜlTn֪!?otne ]]ZjJk "¬Z5Kp5qЎ降U iw" 2[\AqEx@3AAͻ% t?-{3:TJlk[tCB]Aܹf*kĜ4p|FRsendstream endobj 599 0 obj 2032 endobj 600 0 obj <> endobj 602 0 obj <> stream x[Gr8}I.&d@M@ %K0f݉HzHjoo~Tu9KK6,yꫪf]YI.g?0cXϞ=yUNs-gWg6ci+gGL/>c#!M%(z//U0|yU UI(+H^׳_xիWep877 ie+r~ӆ9.! W}mڿ2ʱb{Wp6=ڴwen}8tc8qمq\e?0 nh6f6;Ϯ~^+Blƹl WU\YWqfE jAJ^I ٔBUmgsҰnM؀Q$|G/]sla*H>mW sCxij?'f׵ADRWZ(wjѬqW/ J0hLU *H(=mcr4ٵ AB G4t@fIm\ UvD8𺎃ټl`=cp*ӽd+-o?d2G RP۵6[A܇Ӳgյ?$LbkA Q^~Ea@ ~ya;.ʀ x(?q~ LIh+6[M9H^JKV+43 M}ܘV=-AKx}u2|6@b HVɤ"K2ٽ1dw_ sp?&nΑ-:bm9h@(nʘckFw{<99^|ƆI$FFgBBr>FƜ`«4 {`/s!%P0D߀4y EoxV@mP?Ϣ_R5l7)h pxFaYI]2VVS JAB\_1E]oH P&JM;f"3NrrnNp "UYCX'FfRRv9?YW{"IG: hN#t@'eZ29D @WD.b G/bp!bɜ` 8F_LGsוeAΠC7*r 򛷑h|h5шаm&G"jAa1*xE`{ UEwGEXo:9Hs##}& *y:T?d5) [3ɚ>Jg~H(,q>D ?:dS p6@KH@Q|zw1"3ҙCZ]61}g#,R)&MSWE/P8MI[!û$:'%݁֒D]x# Q4I6y9dH݆y1Tn ڠRw\ )k8|}wsj}">(=@tPE5^#=&Rqv聊!)D#5)}IVbc?/$:9G=R]qS*{_ (> YlY)ʜQeh}JA>mr M{K6xI6!ȶwˤı t 'kGI*Y+3eM\%slP;c,'&S*,Wh%_@Ng LY!CI>uӶ9Ŋn !RwQEYڨbfŸb6'G8^\8Ὤ|qL`H)V0^mC>ihh<}2ZC%.`J'rxn SjyHl^|?ZT|\9U|E6 ~CqZRv׍r>V( 5T`NfZ+AHAQsDM:5KͲXv9F'9!r)L"@DWD(ڏK՜;,2K.#c3P;۵gdX#2$$E -CQ'aTP%QDBxvsZL`_{`(m5Q&@#A VTL"$qfJA >RAI'EGj'@}pq⳥:"؁6eR|owCj KqѮ[#yL"V9[@6yR}5W󀉦Md` lAe/S]`jcZ ^7T}")9NpʜpL'M{)"(sv3'gPE+Ll@tA$]OQPp)i8AefbL,Xlv(0܇ez (t WE"MM%?lҞea6[ bEk` S,'4x26Bz6/1f"'٧}?|t1|}M"mrG'?r ux__mD;`/~:/ŧ}o,|{.|14ՁC >*QדPq,yܲvכD}X'B=}E2V'  Us[GBmj#]."_N>DZ5";]&d84ŦȩVN8. Nhď0G:uVT H;N$ZŸc.dqZEJ`Q,]j CiCQ?%=mA78݁uK, CjYb46fy[jl^.O[DHk~ҋ%?&؅뀠S l EEm?IÿBZ1 .v"IQIAE'RJ^=ֽ>QU$M!HJQmց!n=k9~Y#מRBLӽ Vu h>aj^a3Xx-s ,>A*܊6x\lcpmr[!+We P-<5Tbxjj:g Ae7'8ŜojetT4 qDsCcr|AW6cQg'yuF=Qp: SȃR9,"h'{yh'rZ49։gYDO =tT]ɝh2_^ .;r9,8X|l Ԕmok6=;>&ͷܾi:n.FDyӵ'6ZvBCaxnR0i3vt.^rq`ܑ!##w`ֆ]]|##4tV ŏk~ ĺnkD[#MZI/vI8Tn)UB7Jw? a0eG:PftƷx8%?XäWgd`}7} '1%oo Z`j+v"ڒVX!GQ>Y/>Nd敢ɇrqM !ƕCLC澩P~ =x)+Vj2 ~Fg-(wr bQ 'j|\O\,).sp(O嚶?@WїC8jEendstream endobj 603 0 obj 4487 endobj 640 0 obj <> endobj 642 0 obj <> stream xXnͳbOo/6@ ^I(@pZ;Lr;N =:uNucDV߲c駬W?l.>32H*j|A2V&JdJj M} 6q8.>槛[kX!Dލ2ͧ73`3%LDL%kRT7謷,^>)+c1اM(%תa7 A\A继MU~(5a181CEy3)ԂcaCp/UtTPͼ\۪~˫K4=r>= ]|y19xxu|ǫ ה!C&)ŶC%z~C"*D iiV^mS9"Xi@a0x|aȴCδή`,la i]='c$H֠di.6PFaumgS]Nj"G8ߚDm"tu!If)!hrtwe"r߶=Ο si:jʶl34X&_lc(1;"Um) ,b@rjCc &cJ|%j=iA<>͐du^b ѩQH}q Tm*iL}JpZ@+K%^X Xs>Lǜkuʙ |@*3_ܡ9`G8#:=vCKN,,%ci g%}v} Mw ;ijo#`TCPDAY9BiLqR}$bYĔ1idk[A?G]xdƝIsG79f`2Tr(v~5OQAj9 LoX14Su Ԍg 1GO\.y@n~b]P :g4<*)LBD;vU1Q\r28@C% Xf}UWY&FuF^bcM~j:26%>.&L>?nCjʿSu2l;۔&+HjR J $-Ys{GHaOi_샛&7jCsҏE-iUqǫ<>=E&sjygԺ/jE5+6_Ձ&( LBI]>(?9*Hom#@}Uow1y)^oQ a6ֹH(Qvms' 9U+0;!)L1o]> =r~$U=9?se0ؑ9@K*6@p,k~Rx}=1+9`0%?feZ6e.&@ɯ'eq8[D0ٝ@CvZƳajR# Z.r05e1l>i-;(.*>t7}lO_q ؐ:GHT]ygw=PSi${,g*`~o% 6yZ;ݾ #\D4epL8 9m>SFӶv/opHȧB m?|,q@U6*L0x?!wSPTTeAV m0h-C=mdE1/\xMGq匟>4 Ptos0`|iMe(g/Gq6rpT5zMMLKr:www?KG*% 2^)vdPz޴;Cx"A2Bv/jI*b 4Ȍs`'])ΕCQB:: $/,)*:^=MA&+Rwwݏ[Ū׼D N`f/iendstream endobj 643 0 obj 2204 endobj 644 0 obj <> endobj 646 0 obj <> stream xYn 򨯘؀{7H^ )o j$ZS}jE7? {N:ULxWGߎD|/gG$̬bV.LXάYo3J8Ҏ):~OX}8zVD(ƭpY\%$SFyᕁcpoJ ƒEV+xÌY㙌,:aqw:o.u~*ڌ>~~SxroAǼnU_H˪Jd뾜mMtgJg-Rۇc:_I&_/|ۣg.f*'|h 8 \R[{)}A `:,Vyiqc}^:x61B3z>?ΗjKeo%JkkL9.м#|}! Eꋱsx:KJז|٬RT)斎ħ;i5җQ~Th)5ԠUJ|P&܉U &\P䥕>Ѣ||b1cQ=UՇC'` )@8EEtl;lD v2]|Img0u ;;rt䢤iĀ^AVԂ*ubg8jeҦLf5p",7[)}m\94-|t`aG.J7ЭLH:_*4dh{0 }9{ȋ }80M[Ju]uEo2촲>OVF|㧭ӴOIy&w; ln%JaD(?f4{/1yxLh|[#+g+I@ҕn8  _cu8|+&YS٤)3qX*vQx(N_ysr9 / $p7/۲\E׭2XZ|3 TKmIW2Iz]חstU% %e>.j;u_[XCшnQaR}PyL;*oOޝe#Cebƌ8X{Hɉ<s0i Vv*D{rK `!pmT04vj.oRRcg Łq4w ڪaKv|aodttlJ;fx}6x2endstream endobj 647 0 obj 2712 endobj 648 0 obj <> endobj 650 0 obj <> stream xZo.B}H '`bmYEQT@ݭ$w3ɋ3Iv ?#wwf曡BX|9r*X=5[ xN+d',t4<{^J ߸{.5dxߌx+Y->"W="P4*hM,Div|ʎG1|fg S8qnEmw'+GVÈ4]{ G'@i 4FlZsX#$P~PXLIvsYP5V5?}|CE4?Ü9hvlzS EڥQ@&N[Rl: S䫗@NSľBBW.2_c6 -< mjvl~qRe!.Ͳ[_މ #uD:{W쯻]7MJ1Pu Kf6*BMaJaݬVx18؄9'ն a]I~<UX@zdTfL}%A\L$T@`DVU%z~k8Qd*&I4GQ$\I6c۬2*UH|3ЌK% O =$2Nrʈ@r'A$?6+:r C;{&l/0N}f \B9Oe\6>OJ3*Ss[um PyAQ` ~t {k"̠ 9:'mJ(96 P](:!d20qk#yĘnf)2t\9|-)Ŗѕ j.TQ)SX(NTZԎ5`y"fl#:!S6]UpHN13k&}AbʸvM')7=yl5@AYd fLP:Tc#zNo2bAPJA69rsQŬ\[Hv`RdHwrv A5!(0;~3hݞ&PM+,CUZ/5 2Smkظ6;š bs8*\oެ#헥sQ^B E*nblR 4J?%랿TOYRR\h x㐘Ap[uܯƲ8oaQHP!f֎-%6 jttHʀr6ط4b '\P3t>V c/L{d9UfbeFy Ϋc%X Du:AY.麱<+0)@ Ac-\3d1/H@Fz?ۘuߟXpRt,MЪ{u޹ބYO2BDчs y6Vy5GB-;hBWfW~w!"ɂ9_=">dnsha:c {:v퀢ބ}HD`fB}CdTd/{)v%vF4t0 .~p;1: PzWB>-0W"!ecu5W갺J:`%:T<7'YU(T1,xZb $L$49&Qd6dJ~;4YЫ<(A˱Qv Η`&9?:#sf= Y'EfW0E61(ZrF: ;j'mCɞc%jpXײrkQṢee@4:48 fJΔf|s%s7W*>x3h|t:减+*G~xF2<q7z(RW/^2ڂ|\lq ;jد~u*eop7iYvwh9^LMWqRQ edj?3t& ZQcIfX7!՞MgG c!S}ݩB1$ƥG;x 9;|%1˓"`֮([j u4M,MAiBR!cU3B bنbDZm'*GMV|J<"Y&YwNOOk}Ǥz "meGΩǾ,}B1z{ ?ЮU>sl1jQJZ&1r5KB6@5Z掍\a\.SkPi *N]+S2 p& Xc8'Bb)]h]6G9=&d|UqG?[f *弗kSښC,ߊXr@|c~8iaBD9;d$2Hwdȑ)~81Eݯ6Po $9~nhղ~E3BKFm9YS.ߌBC ; uv~?T0R!;Uɵ%u5G*eh$"Hd2X:dU!,Yۖy|ɼ T{e/B=鯮( "f: r\KQx5 3KpMaJ)bQqyJחO>$ endstream endobj 651 0 obj 3112 endobj 652 0 obj <> endobj 654 0 obj <> stream xZnF]Q_1 `nRo$ Jxf8!9*KUfgY]uԩj[ws氺xɕͬX?\؊ޜty+5q^H|Y]>uEYA}ڕ)ϘָhWUo1\=e&!K>Fݶ!@$0j>YKZl}=}DyHpo۪h`6st=¸E,- ?{0Ed"κڔYbsXbS}Y#%FOS |?>V!9 Pb>-|Uq]D͌H3"3 n] |8MBsXHGj+mP`Ȫ*YqLE67aXusD\s۝ڞpkM?)nowùph[Q UдSQBYV7LQB;*C_m慖xyͥG5WtButtf ?õA$U*H?7'u 8)C,GHOKeS"tW]&q /~h.֠ٗmbx %Tֻ TZ&-{h=|idž͊hsGLʶD2:DfP"݃whZˡybKK&SՕŰz%HBCV/BnYGN@=!M6EZ䲃6FTNzSNTfqu +Q@LS1I9$,}Ew6=*hK[W ^Q0*^gCtypD !'yTj kns/υ P`7%|jѡ:vݒ:f |[=,{/yb]6$.ǒuUI)=Hn?.Vds()S^,)dեmu8.0Y(@ X px*M54Kᄛ lWۨ@[Npe?w'("pCa} y "J tni<jL 4]8Ǒ#uazXS,T%_ݽvBK{&{6)RpEH)~ 0S,G޵+X̵GcW=-(;oG΍$LReRa$^tV]-S&%ъFO6j'mݕ0 #}mwQ+y4ωRwur6\$5Զ9bc"t [?;1Kz˹"p쳠6t &PujpjbtRy-*AѰ /= zj-K-ᩩ=x1(PM?w12tck7P  >~nWdFsN 3m -;rƺ g@oRcT<~nLC JAk[X 6΋C<{WКyA3$NC+^>Ya+Ύ spL]8{}4m0:,H' QgNIl):S㉊CB %9VaL46 -Vp# dLIOhJtmgvC(;0;$thI]pE[_zX9Ж͏pȂF/r]vqKmr"#x,*h,m6~11>?s9eǏRw\W,eT(ݩendstream endobj 655 0 obj 3900 endobj 656 0 obj <> endobj 658 0 obj <> stream xYnG [l@Mߧ'b7ˆI349|U/aEhTW:u,ؤtſ׳ҟr[X͵\ݝ6uaDW 3[կg,d%$=_dVcQRǵw[gI)T ޘ ^ԓ)7xm]^o?)*l\YV񇺛QuXֳ/qYXÃ߃BumQ|T11^y\{EQوJyOf +DΨKN;X3e6c2*,OvfӮ V{UZ눂 .!J@XxrV8-P)@&x+,>LHn<n>ݼn2Vܤ=Wvm5[XX2˿0!R`=R–&m(rGzU'UM  ;Nxyۯ d&^ tZZvladZ![e-B0+m*NQImyG3%gu3K3re-"-V_/+Q齀J 輹9bJ }] ~ ޾ʢDy*JgT Q(mJ" R5D2$a4'6fb6 \cBJiFJ%paU r" MDm<فCGħcp:|j37e (G|ɚoVv>|/ j2bΣR6%V[@Kj("S RR<]#qPQ6TCX*y!Rf{tyRSXvH},TgCG.5Txګ_B .nHSs+Go6-X>ҏU&=G圧o=X˿/U:pn8gRFwz wZQk+u7&2Sg s>W]#2Fmf0uP2S1;y94זsڧr]G?nuo,QWIpQ@ ;%uóSwVPcg&_![T'Qi=hA6V!yQ#8eT+ >uA j| 8ldѭ;j}!Y"EuʼyyHoVìxGʜZuƠr6j6C'ǐɝSh,_AȥvUlwGXe4d}f#??$A.KHC!>)u=K$<$>N3zF5n"Ef 3y?.n VNPDXjz9:eG+:J9c xR4A9djƹ9>d!h* $=J^%g!$ED7A+z7ag[QV4~L3o+wRU9PC}[o|,Z KF<]m]1ޭWx̍Du@bu\:OPHl^İ03A5E )|(fTQkaH3&E\2Bh~ ƻ63,΢(7|[7X>g]hs dɝdYs M/?-G.8FzsPUa 6=I^ȝAmA1"F(&gJlhUO*Or!Jw 6R˩̑.6 \*4Y6^/.^@<> q>1aYweှW¸5yl5JpZT:8YPE34㟯&0*CUrI Y[Wgo'zۜ]|z.|weU.\U;ݳR}64NUԔ̷u#zmWA~q0Zuu-b?R ZG]j_z?^qb䡫"7@oaH9LHAca8F;E.SC FxGV4h`U$;jFFs VIGuN%IY`IR3tԋ9<IG93&B\'Ey0d5?2^1^+晎lQFTuin?Jqendstream endobj 659 0 obj 2976 endobj 660 0 obj <> endobj 662 0 obj <> stream xZnF)QM'c ԈscG|V!xc?4N:U4+) ӿɇ||l__gO}0$Oaqƙ\׿ R,^5^[}uu&4= 3ܦg*. L.7]^4hOZ@B"!u Lᤒxjێ[ӳeQ8e[0$ו*<pN< { 2x朻Šqwa/,Wq_^H\zZM)%lʾnۏv`%לAoq n .51^sy*W28kbRzDEUw׏t0mwSݧI19Tn<~E۾/_~1>vvu)8sD컻ϳw_]Ɨo!mU\ ! ͌Yd );wxsg9`^w}i e71he<&`3ȷ#HGH-UCU&&w Q%ZE舔 1\"j~z\h,ijzGrd/p5U?@Pƍ^؞6lR_5A'ierwM}A}H%ne3CӤZe{ 1#Ρr{ Gy;ZM6x߇ \z"PI SY|RԀqT~]y-m PXbrPq;!\($E*  w:079dHq n]([*)^ >ʏpA\riAuAIUf%}fʛG{UIXƒA6M0UruzNs  ax]f|h!9ߵM&1}9}<6q)jP$N$qL47A/H\tv*xuIr^1Cp:eG/.FN,B!92ffDùNė%VuR vi3gC3<&Z&C PUe\?NjᾫR4 Ф+Mny[$ ś1Ky51e RJN1A}9S芽HS6R=>1Q27YGzH=p~:7dmg Q)ހ/`M EMFd`#Ac\m Xr@TrJΐ 8})9[$TD0IyV%B[ %U i"i< ]P !N`UJpU?IulRìK;CC%VO`1t(3k74F[Tr> \:@%;&R!&J̰9 g yF<;z"ɓQfTD8}0P8V$R7UrNA,-w\JPSϣK <0JUGD䨣0?s楡莅'IPJdG~E.{6&%p~\hVabΨ v`1:9uy8d1wVs(cBEP1{PzduSw˹j <8n G 51uBfyh4ReHG=Wiqԗڒ/nR|d(3~"LQ촗r9+HH

CH%/02,1fE[ɬ5Kj I˦"Hn (-.Tt8xx }rڂSG.y۶!LGM 쎆\/3765i'`sS}{ޖɧg)\p.BSDP b =8a_]4e8(So$v@B&ӛqS \#HE$7K&5(K>ەMG> endobj 666 0 obj <> stream xZnF _Mþ͎رdDHf~V_KM PfuթSgl?? Y͵\5m .4~8[*x%6Mqin<պ@~ˬooզ1gέEJv-2!eW*Sĕ QGv<A;{W58'rL^@EX4΀@\~\Ž2G|GӦ Zwa b_c|־|<X+(BdrσGfǻɀ4>姸/g [e=]-6.ϸ[XѬy+WPGCBIggsQ"!$q0dK=X!?)2HPt}v5h Y`\xȅi."'__}Sd9TCWpm}(K?YAdyD>"O _< ?۴*BEJ- A {>~*Bd*rTNk!>ɚ7]#T@ jќ&Aaq𰮗HB)GFmUE皜 *kGƑ"dd.fddMY* ЪzӄmHB>F5%ɶmOxBwDJ)U /[鯤"!.t Fzc8J/OJ/(Pz)8rT S~Bt 㢱^VP4#|o8`kMezꎷWv*&AtcVs$ 1 c 9Ħl=:1L_!'I\ן"HA"u pT!f$SL5Wz]yZi<6Y$X9^ڥGH҄GUN 9ײ'Nk6&TjBL:ʄ4/ob+À"5!_ .Z@rˑ*I|YcavF[95O y$z3)gp(zE})*^#>r5ͦø:  rL6__@A8n*6J"esmIQTz,\4Nmp#vC9$1gDO7`H]*ոQ/c$MThvʟ :(Ȣ@=C/n-A0P9{l}]CȊAf*˪wI!Z\sY:.;cT$= (qnR|QRWAȋz|7-Hs+8/b29i~q(C BHrTN5=c.sɷqeSER`82}WHu_qOhMz{ <7aQ&5pZ*5" zھocvA.$2!ط$jw'|Ô!Ri24_ J/AFe"cM2M2{uDMTUsIY]BOWroCx}|7vAbNgob74.-TgWQAZK=jjj)IWFփUıG9Q`CN=uO"/9@H|PEdZIU+?-]Ks7"IUBZœ> d,T}\ j.y1x{˩}w-pW)& :nH03Y`TVeľIxm%/tf ԱJ庎]Siw썐(l<4ѿO$\j16 Q{5OQ 1՘'ڴax?znendstream endobj 667 0 obj 3152 endobj 668 0 obj <> endobj 670 0 obj <> stream xTnF|JW-vژCNEQi߻GC@յz`ŖXi]UieU?lbVh[iuU(g*r  i@q\uU}qTңU]o^;X"(i4)V, )vϻ./'Ecp9O# +DzRw( <@q` XNEϹvuf 0#ENvSwLwZ0<$_7a}iLm Q1A+S8!jSJ*xBT>S$rXI}HF@l5"(.-(9ڶCtX@c0ʍB5FYt AL>,mm6G)s~&%AA6to @u9` aާKNA bxDKIy]htьHD+S!*^֛z?5c3ts7FWy I|6ɏ\|w3%02G> endobj 674 0 obj <> stream xXnHg0OHKLL@Q 06mk5=YE4rΩjXձ 9M~2%Ko7!ͨUKƆe n@ 2 2iiulG |`tLp>Gg}O4*gjBAXmf=]7[}hC8n}lp<ҩˡk)|kO U׶ȜmVWGRxpe{h Ox J`K!2ۃ[_C6Q@rbѸr0t`?NH)f$ pɄ۴ԙr ۓv46-7!d3N.r Q# xȍҮUܼNBo4i'3<Τn8O9o]B%?ˮ?]i2Nedv:ή:GQ\wj `#Anۛ"u5 )ޤ3P(Pr# T"X`{ZUJM>Gf ]V!}kN Z2t]e˔Z3XPq;,~_o6F TݾE Dms*4LqO 8U[ϧ #er4[RmmnJ9({[Z@tZ{s{$3Nc}|l15{Y<:2&+)L@#x! j ku,~ ]ÌiőlCS9+]̲a)wŗbV3Yrg3Dєe0\_eUbcʴ|V~\,e$$^_H?+YMmyR@v|QqN=30y,+b2$d<lV:sC8.&e>;O0X'k8G VTs(b^8"{#4׬>pPB2*Gx&R>U.S(U~QRW4]/F3\EK̗eAqb"$h1ԒyPR9aj]LyΗm Z|\E3 @o:;ESbBkx\LIb*sl5RS# to:3Gb0<:zzID II3G?I".*G9(U"O 12)Dpzȝ܉UU^v23_ZO.?&?O(a:A"[EV<{ȀBj/@ 0%_c^PǜdW Ͽò]~8̌H00ADO}j$!Q@W0ӋcGC*蚑CW*j%=%z)#d,g%e$GZ&! M^"]es  hmI&In@^EwwD 3aǣ牟ld=@"pDxIn ,+>1wD#w&qXXC߿9bZ#IKI݀D\x U%͛OsI#\PN$)Hy]Jt uyb&u2?T;,sd*/+ kn~BQ[#y 2x1!ȣg}=!~<%2CT1G~Nأy.Ǖ :U7dX>}>kDendstream endobj 675 0 obj 2218 endobj 676 0 obj <> endobj 678 0 obj <> stream x}UnH樯qNW}La@mJS@"f}셲,:իWEJ/ק김ٖS\}YXbS((J)QTQV171MZ~um"&FwdL&jfvE^&%8MEF߇ݗMI" ~|HU \(veiwu۾ BRU&Ϫ,f+%Le4QSvѓf>J,}K:L3ZK>f&(ɵ{k/48JDw޵3Ex]NGfTm8Tc{+.8hFMa&׊  ^xAgXF?2DrRRfֈSZ<챉lq!c[=1r!$T]:+hWOܦݪ\^(F, DA> endobj 682 0 obj <> stream xVnGG M!`K6sr9pw2#ΣIJ @hgz(ac:ߪ}}zq6|Ul)њq70񱲂H9գ=2($ ƆWIbaAE*#6^qnJ{7,VLj%Ή6Ʀ"lD1,NU园!58(+C݄`:#ku(2~3,)!e )Í8(#*/8N Yj&,pQN{3b Hsi1 zI$q|̴HA(ߧQ3󩝔|U.vkPxst)HOtmB3j n#2,Y Dbm vsߕU-,6k\y)O>$wn `!Eٗ2VOh<{oeZWnSZn>jUSӇi$ckm` |$g%PĢ+f%sS8B5'KD_J_ I""%]ʡR•Ò%T.v8R*0F+`uek$Y<jB,ݭ&A 5.i@h,0Pzad=9~Y\;roB0GSخ.jZ;ت}lC,cM ${Se;D ",7\Vo(XHq"53o{(3ɋӶwͪяl(I@nrQ[o>zn ,P Q1oneD5дii; [Xp8h09ݶOsdIYAeUÜl )JVC3wm5i+5lVmwBp`FY88Kw[ (Uos88ƾ6 5 @ڎ6q0D XdJiܱi`s<0Xxeo>L&r}G۶ZNtl&9 D nN&)dBW}+cghg C>M_b^40#ؒeQS u{T섀;|Yv'nHy6dTMܽ9q(=}J,PK}h[38WMޥw+6{(6?#IIiH5|m6ݏE^endstream endobj 683 0 obj 1353 endobj 684 0 obj <> endobj 686 0 obj <> stream xe @E)pܙ}I\0 !-#BnA).{H$'1ha'8^@`jHOJH$v>O%%=*~\)^z鑟Dcªcwj1^^Df:oP 3j6z-"& ޚn;endstream endobj 687 0 obj 175 endobj 688 0 obj <> endobj 690 0 obj <> stream xXM8r0bo!lc䢶mؖ#ɝEXܞA4@Q%ޫW\3?9y\6Wj53F*aa^Lϻ4Ç_W1}-aWqʛ* 0q称[&,LI8U|]1ǥO&,'p8%~SD>v?RE!Dץp2rV|]:`%M 1fx'v,d 2.&dL@:B p<lrO\ 61SIJR!B~5 dJ l[V'@e%}mKXusܢk~S JW\ů-^kV RajSx-IGVù};N]ms_T*O~)j܌;;^]i.{UW0 %|z7LL.wf j;tt)qdZGh~jQ-Kk"u%!t7-ۈPTC mx-+LymrO=Q aH6 f6!(V7+H~ɲx&7kHDXBhq労.KRI>lA})v`RQ,(|Y.A^>j$d|=؛@Jo6Khvmt@= C_M4J>=$]&MpҀb)a%-`샻D3͐S>_迩,\gKSa,]ʆǒahV̈́RcSbC"o5#, 5ed~2ZN@p=)|6e{h#4Ra:S_X2+;4N:w4Z,l,z),SmYν1Q3%} ~ zc"1wpW9, Œc׷[RʋB2°UmnO(YWQ+=7|Q>b0_sa MU,Ϙgܛj8=sx4ўB &KKCu.3-Ux2-"l|Oޯ.-`Tw +LQП00i p0YѢs}Q<g{E *_KC:11({A8l/ӶWqC/*3p Vi`]5HftORSyRq\l7S~0m48ޛ~LUTz_/~ڞOL _5kԎwf;;ḽ~R_ F3zF[S/f4Z__a2;;fEԎh`,YwP};nf,7P1ݐD0h4UW?ZrNendstream endobj 691 0 obj 2157 endobj 692 0 obj <> endobj 694 0 obj <> stream xZMoF7 !/v޼'Q/ %љ!'$NJ뷚UHWェf og~gf˳Թl y~y}Yg9/Lr O?w4K1!_7?_Jo_na0GLgVsoLX+f)^G[ZXqLKCeŷ^ݯ^?՛| .Fe~L 8)˸q#P_߻?pi-qzp ihh\FRȔG:m/UKp>l 'Ӗ1fw`o88ɟǦѥq…޿`||+ǝ<"5Ta)i_Ǟ!/Ɲx\a֯p+UCd Ӹ*f"apdVp uUe&`u寿BxlEp{Bx`aY3|TֻjW}{a \*>`rOF,8]ٽ @(JoC@D붣Wvf-DC̤vc^p ons? GP)-ރ5gpbzUQ>`iL;Pk;=490"+4ϡ۲B ˆYȔ" \etG[6l)WˈUPW0BB6 kf bT*ʨp8/Dƀ^0࿖Yu!E6p 0qB/pPڐۖD9$z+;4_ՎчN# ]E'@y^/sY!O)}@-<'zSz&CTDBy.Bׂ)rMʄgMpO<$ ٴC8 FQʾo75lh(Lf~+=f$Fr5C@Nh,ꏥYBG UC*jQ3 $(A(+ R*R2T$2jZP|ݵ^90e*gZ M2CFX.5'Qt? z #gRFG/ÁCPⵓAʂ`,V lC]4>%`L,b @ V*"0=pWTXį =?!&NR\<3ŭsQ*EH A\mI?8 L”@u*3OuΖV Wq3AI<Œ@,5RP5U72¤Q~ &x Y .SL"NS!h:h( P.>׿!ȍ8n?؛6pN|iwU̍F H9vdX ȋTK~R0Zi鬷Xዘe( u#vU$?bb33iw;??ԠSpR ̅x7@|?ʀ6"⦑, X(v:kVbS5x)90gpJk^JDh$ZiS҈Q۶X # :Wa0lB:=+uޒ q&Z=>:P8ռXGG'NhB5ն>_as(@/¬\NGu$ 4[B"-mM'pEZ׾PB$dALLs0 \e-H';qI>3x;\3}JP;ZU:DrYl 8k/=K:86yl{Cl!8ڤ)^7q[Q!&>}v}Yϝ>yJ7H`E)|# B-v\v(IճW2,*s!hϸI~Ѕ]\H@V.쮻HnexcrEWՊf̌ݔM8FXz͚\5*๎5$~bXަm.@ x)4Xaqp仭`#`hjVFmd0(%! P*՛!dhaIvBKw ܵr%1mvdsθVn><_ }e+uZ$V݄êhPv%JK!\;pz!Cl~&rwzєTZ0Fb_`$7;rklmqOw*z0;Qa6J=ERE!~k.8c3NZplq$(,t~u#̍N{>2xFu]mgfĢ73MaZUԿ=rtN#/V0H/ ^{`|+METt&z~C9E-~w+ӂS_Niw3j IE2a"pH=*s]nF3E~r&c_@*xiޑ7#%ǥ7(V& Q@;nյm}I0R]f!O(.SC'qtKsFjL'Rړc?^AU}Z%FzF>^H_T8e~К/ec咾Y[E 0liҜړS렱 Bw$eMEtqd"uC;7\&1k OgTtثᚚa3v!h XxB2f"$B q!endstream endobj 695 0 obj 3371 endobj 696 0 obj <> endobj 698 0 obj <> stream xZ[o81"Sh4_fg(%_,%iƘS˔fP//ݾDF 8쫦_mQ?BfVj=.rE)ΉzcSa/mayC^ݫBxnY$8KtqIrN!ްo#9 o8_\<DꣳdL`BV1/ekay -x^_Aت ^ՂcV˔Ɣ(q.M*$yU7n<\ m aaW§&uK-w/ @>ˈ,7p߫eS"똧tFDTp}~?: iv, j'},am.(4${Zաmn|͗P#$iR7{o~]|X-Dy$'a.љj+׫|xohX2[Wj3g {n"E &0&DN@B^hVY// Er-=,x,.b&Ѽ8Adfvú W+lvQk~fT5۶ylMg03fw1"'ȋ+Q+kѹ + $Uw$& jQ~û#{|Aߪeȹ]}\I k{ o%h E`("ۅv_9&9g&^.&+~:Lkccb;azֳbyLJ\<׎܈M29!P^'AS-jfQQ/}$; @@#.w~"’euπ 7WXe> L|5brTZa3~LILPtvIQ=Fj$eHdtup7b_-Đ|A2^+j>AK[5 pŴD \*䈓z*B ƥ1uㄱɽOͦ L(]C. O?ud,r֣%@BTvEu CС"6 ;o-PTo"jyUa_ B> ܉>NK&8fOj Լͥk,jҩh} ^ZvA0y!A|xAEQFv@MIXnN{cLw˶x˷)/Cٰƃ R_Ϋipx:~@y&G^1]!(+CXW{ Өeʟjgqj.ˏ``1 e&ZES_p"Um1WQC j)Uv 9q5jMƓb"?o3 ˷2źY  ӣ`t 쭦]1#tvV3ά '*eFo;rc2t- ADPAؓzڵ͐G01E~aG׈ر(˘{aLdM4MT~{W y.W9 [vwuC^k$| ҟnԈ߳zQ gD_Ivuޛlj s6˼zW$߫ۿw_'8|w}OwH %p|v}߱ v2}w_N7@k&匢M7-E/|5~"?\TA(^eTqW{(Loټa3"ևCH8 .Ť &+DZ*9Bd(0ٻ/7.AO]r)^eG!PQ>] g jB[ׅBG!c+'DI[iDRUT*Ax`}hH{TAJZ^)d/ObD>VtiԬ׍ z JHZ82FMwԹQf{D(&b&ql+PLka*R }zLv⽜>-yϤmIF1H(Bv~0P"؈AG jB WεBD*K.r$YƋ_ɠR4vaq6c7}3'b}@ $S^l P֌yA(EUnqR(2TJO5V`?.*ySAS"4غ,| öab3.Us(KPD@G 1" A2wfs|7cG{^J]v5T$RY4fiT #:$1D&b\#fAEEf!! V˜nURHg^Zendstream endobj 699 0 obj 3743 endobj 700 0 obj <> endobj 702 0 obj <> stream xeN1 "q깡qH9U2Eendstream endobj 703 0 obj 201 endobj 704 0 obj <> endobj 706 0 obj <> stream xYے6}[;';֬wcU‘8#%R!G{ \C>}L,Ojwo _ŏXHάvqs_e^.L!Y776~7p3kxf}FqO6N-Lw1I/U7ʉ_%Ozv^L§}2.Zwz5/%(X,gE ^UM_Ř]j+ǘMu X-}էwסq ޗ?qpW0_/XĪf\׊2+a36-RIDKދ$31I) Qw,|᷏]I17n߆ s@rLs{U!d SaY19>\vUp4. N{he a,T&K(቟ [JƇ5 $2¨vmQB!rU]u ddPdTR#R̞!4 9Rh*HP>|zPU2::7yN̂BC<;|ZYwYذ}tD>(4=-MRz$ O>B >ڂX4vA/K Jch@y^We5E59C9uXmFc" `V{kiT1M5PtrGU!hCamڇFbq7mD :X0av5g@s$\ȇ>s(%oiN¤utyMtӱ 8k;3KؔvZ# F.Ǻܾū BPaGW:IH_C[D;(J]1+$kABP steA#Yr th%lwΕOJ2WCB!tjr)CJD}4`RgXԞfL3^ljc\2>Ig6_M4ԅ]uf%ۘœR3j,69mAx=]A {O@K`>ht97aTfV2^aW_{Wy4*NƜs3 $'@QW pPj4i^g"ϝ>T}1wTutL3èf; b%ř^_rVNvDK۵>LνKa10oEW7_.~Yendstream endobj 707 0 obj 2344 endobj 708 0 obj <> endobj 710 0 obj <> stream xZnFv_$l2ز# EA6_Jff8!9﷚]Uݜ6 :U"'WDWon=)2W9'2Y^Ev_Ҫo hu!*u۟ίo/neo2KeS^|S*5m7Yz6RkRzOG1@<W x =;4e]s7gƆ $|06u?>ޣְn8 *HI\Ӎۮ}uСL6xzǺCt=?4=ؼ7Z"=^Y)C)H:XLlnN@ͶyұX2k#>RJ1l5 j`kw{oQS#3)j5>2m4 `aMH)jkX4Qp镅 Kgn6)uԞ/Fjg=$AEVjg*H6RA1ʒcahS(~G2Ω/zSfBq.x1r([2fixB$Ϣ]AH[Ro({Qc8}ʫ_{l1a0tUuO֔jD>[S~oX=442?ZiJ:eThHx(6ojQLInsO@ @ lh@)p?Q%;9ɌHDZj,<6 aP* |GDĮiB\bL H苈R3ҵX$>Y&[-c(%n V͢`d O 5M1_ =L8\aEB4}ߴ#b`218`Ϳ* l;b匢v܏߄SG7MV@>_nj٣ dB_9nxl@`)ZZKr`6dxPDE֐)+fX@"h Tԥ u_. MB{u7T(/\fhWOd2.sQ=:$d˒wef4B'[iDy59BJߨ0]%V8w*>Q/l&ۻgFIX߮kP@?V=,imዀa˷S4ܞ=Euo#46d= VsL9YD/O~xǫ#q5@ QZ3)>PAg6@F~dMBo6*^`K{J%m .Ew::`ՀUKv[5Lr7G؅r ~j)+7FW)5[42fn41RK1kFHL&a>w=E"VÜ6NȰNaMއ,0(I}$Ip hgsBd`6re66) fv0@=,[~;=E#(vcp?;F:REEOXpJXZy9m[&0i[{ae&uH V3V~9y{ƐM;CL6 xw{qoiί!AH~aXAw:S'!-xՇSd$kQz% W(,/ߑ{ tT,._=OosNV/gt[2'F`=k*V8 \Cݮp#G.ۛjL4ͳ`ݛ+߿qA@q8@4/zaI֗o98V+"]0SflWz/S3NخκAT4PTX@lBa~l15cLo B$C4+z&cI't Mʒx&?33AA@ZV :C) Ub㽾YiIW#lF| nIGӅB8{4ĸ>z%b*9Tabx*#r1擌)g'b%b{quWpyapg  "ɍp#^‟q  ;󹙏}C9zp`e3u)o`,=֠e74(1PSc NKJFU$؏(IK֛FzE2෱K+UUA=d=mB**cУJ}zGC. [۶# eM`SU3d^? RsPϒ;+jQPš~Nzmjs?`&'~GRFbA>ǹ¯9+ F'L{UmvC(`_?yP7~WA0ΤqFn_84nwZ'lw* J^5f0OGN,NN0ȼN:=]] _[bwFQ*^T%m~;w<=1yQwj.Y>:KN[hDsEAcDgUa@Sq Y-[*2C3y(n5${*JȚp?њ%͢<$z_p.҂M]|Iҹ?cހ˴?yU֟tܾķ RlOk wҜ/*{Z˘m#4k|{@? i9]z'GA)hlA8RVCŞ_' gָS9(| OMyä?NPg/be[xvx(5,T,aFqV~<^oŮ Y`c~M i>RAVXjY ?IoK+9eb0pF}QQTrp>?G!3;844Y#zNNj21H/nO~}o\endstream endobj 711 0 obj 3980 endobj 712 0 obj <> endobj 714 0 obj <> stream xZKo8_ `k7s` agחre[nRߢHVQNAd]}UdY]7_wl|۟vL\4rwx>`;)TwS\ n mww*sZQ]Cf gM;T?">] +2>)*Y|vC{!:oWapVLbX_>+->{nb"O-wU{ҙg]wU=uJow?(1>>.^l#i=5))Mrη/KߎVYV\ ; WRoD`ߜFʲЊM `:_㲬`tO4A*د`K}w7Et?)P9p'.$F:vӸ8ɋ/<>en0[1_Z}pwNk4~,rgӧAܑ0XױnpXcQw4˸~~{w̦ z}u%]$)A,/MR1oqSdY*+[Xeޯve0VD ;M׎B3CNI x4Ƹ:/DmWXuz}Z^@cЌ!ڐFAzW<ۤȓ-TFY"alSwh{OHh@!L*&P1\n%2…SB 9P -K5<_R B0W ζJLR`;%dEiD/PU_"dcmt4 -wm41='WP4Dp mCa|3L _dp}">_W>hT'c ~ÙGg^CSH ǭXFOy)Ÿ"CꡋtMܦq fO5L$3]Jԕ[ [cŏKZTCV bFBhF@`v`޵fL_nq4#VF C59k,x5cnǘϠb/)=kr5ʀ+3 nEbWL ϸmnfɛ }{ͼso ,Ǫ'\ѓ~v"4 $f٤-ȡpdqOS5Y!-rsԺТc Zq.0&a&v-h43pGp+}Vc*Ήu -vJYl 9 N @'YT>f.@"LXd aĆHTY: 16< G㶆*U8Pؒ}w}_l{iS,D8AIiT%C}{e$qj AP^n k iEL d'ES W89p⺾zMl)̴ xNfHPz1HIp_kjǴWqSא=|˜s$Ae7Y jzRXzYv!w!U$=c *|I{0J؉='%S`"I7|kȕlŖ fɒ"8zҎݹPHc(FnL))fc܎qC*} &I&_J ZCWH1nNPY"VSl: '^Nck?JG'B^|g^F=^,I1I ܹвSƲ+Z&(fE*ٓVX{KP76#㆟I@4E*B׶ZS2Ӊ;;&ckWK9G$ [;4Ty8[1q Mr{VUvDPb|$x?i_H,[~.֑xw-/d(HA84 1ʸ2?!*cj˫L_Co?L[yo'qGLirLhqA8j,F#4̻۸t*& @4صB*Myf+g0OIJpɌƉsVB:tu[tfI1f'rVt7<5,N&pPrO?7.OժS:L e$6Vɹs2)"_aD8ӔM4ƟaE-%seLpzv\NFqL K'Up\K]: iQ)h_ʏ?XEW",NgE +K:m>e*tI[-Ut{+NtTD>kAh'fgvoH`YD`0O]C,,u֌_AɎVPZEȼl5QrIc2fL>NmOp0/N/lv) xm>#f{tS} gM4tNQw Zhҫ cg׾nˠ]+ ;mK -W1N(y]~ : ]d#<1Se,-6Yzi!'nު0g^#e轺ߖ*$AvSq>,\G0Rz0{8L!ϙ&l.YOcjL1x}JlNtpTqNI~owXQ@8aMn(5ٸdĽ?wyLendstream endobj 715 0 obj 3355 endobj 716 0 obj <> endobj 718 0 obj <> stream x[MoFrmwwOdv3@LBKD"Q~ꪦH˚l!-^{U# y-׫_,o?H{3wW Z:Qڕn{拻f/o<\Y?7/J [tI_J|}_/VV_B[=>w?Ň"?}s 9<|ݏo#)wN5];lZߩtpDصxHldP5*~wعsta,JG4.]? J/ tZ ^ǭ*׃ErL'$ZCWdDag0d)>;kTϒ_tpZ ',< U|T`gN.}o{᫸u+H{m#LʄnsP898zt܄Fօ,Mĺ>ŘcBrmn *wGg9Kb:x7#.('6d. ^ˏ_1:/%Uq,סl~xjz }+嘮UukƧ^}Y/pLw_ak@϶)QRV"p Tw4-'k'LQ1c(8FgBF-5ܧ/$X 1$jfpSMt IuMtiǂB^f)2fBaE(R ர[}2gc>ϋ1Υ rL9:sf^i:}US^ҙ.ɴӅKBn?RY#hl\_+y|'aRe;'=Lsh)R,`3~lrCIxƭ/f궻k5P$4<cF&*STq *)#ew]F0PUOmSַ[FXRY: 'Q>cZU 49bx 8!NԬ08j `5]]hG0?LXl=ыqVzT#3۠ud[I㭞 yp\< s Asܢ6`pՁ4\'5 `)ܯsKCyHqoz,VtԆ凇:7o/{4IzF҅~Sb>rĪG#zU(=,}6crd\#QH= ҈ eN#˦' s ;11!,m3m9E F\ GB'tO#WDÏOF3'Wg: 1%WxgHrg­CM)NQ'z;zE67nG@3]!ኘ^"\wceAOftZpYЌTg&z| U:i0>)r9Rt:;,Л~Vg꼬沬8JE |幅q(@ -qx 5ʅQSSaX&^\ad۵1˂I,} η-kjNθUhcO±*vxh2/G¤'DRR,+r;Y/D * aU$uƨWӧ"(/ "f?Q$g;FB\=[(W sR+p([<;j]Տ[u Ǭ,tflZp @ ~x:lVQ~BП,89k_4۰` g@gK`p6S3@cx/{^hgg707~AjՑu.Cn>[U'"CƊȍC,C҄ܟ(iRr|PԔݖ}}^q֓2^ԓH (ˑ?,?yAH:dO27 *y6[uj>|ĭVP&"F U\ן !m qJ;K~ovN%Yƃ3 yMTIudMnDP6R ." a8G+W1j( tSDXA|(cHb6ynАx*=N*_N,yњ\1(2.3nk|t "4jsb=6Ncwc65I'#Ezl,e+4S͂Ih`KGhh 9\j'*-?chN1 J4bv;")!>yС/N![vL6KJFxv00NCP$*GrVLK5]kCOt,2b> RE6v p\K?[tHKf8ϝ!Y-qdr 0i\|,E>Es݊YBO<כ U*4#yZ1}lR9K6v]QW_M_KW\&W9B~0m*Ϩ?tG\VɃ CZ+AwN> endobj 722 0 obj <> stream xZKoFW`-/BKD5"V"MkmU_}Uu߳}XosݏW2ƙ'{apq‡Uq %S8]d=0+8ğ:)ơc75VSUI.ej]qX2َ?"oh.}Wo6i\Hʊ4kc8Ki}%AZKq3A*.q-zga q_O4k)FJ$]* g?;{{}cR u_ 3h1d=԰K-]|9atd```ɘ|h2J)(x%mq`kxwN2mi47Zd$H W >U8pX2[Fkh)ܷ͹GmͰzhL`J&h#ЄJ&lIƯ78GKˌ9℟9) h>C R} 34+H3uƀd6o{1J'c5b^9WO'ӂ*gw hnɰ_q^]fNaQt[j-sB216tm1R6!k7t0Y-~#$".R g6| 0:'B_#bm7u$kPS՘!{dܘd,%`eI13O lNUݹ}i m\t|O*I zBAY߇S ~E]kŮb7bұRaHW1(B#"&iemnCw+ H^ʴFƬv}7 NJVY7gfK|IE8?mRnATr;o1 e>m*/.UtT<cQC~( OH%R咮N7.M2REՙV瀨D8~l_f'4YA k^!$K8l?tXrH{|>>ihyqgJ! O_|A MEW (ÜN[ݷ*E\~}l4}p|)aGqkPv"qTyf*4c!-tF ^wMWDzE_*%tm:γ.ZRZ0h0*F{-S!#DB0C6ohQjڅf12Nlڣ:t~p.=A 64QO6wQs1"(s僘\HuŘ5^-X![',5 .YR8 /aAto~x{l'CA@iׂiԨf㦕8]],]tpuT*M{zuZcE((F6 9 ]. s:NZhاNMzRs~hmy`rw,zّ κ"hsPO3w"0IPx@Ijlg{6F,BcЀdYZdg-S`Yfs=5IN sJE7ǁp& 0#X1 hI`u)-Gu n c8Egd ūSwN[ VSښs5S@ +Kһ y&{B|ZkvߦF@cvWT#vܜW]8bH,1t6}e+lWM[ԌZtˡ/^ɡ z 퓽x} &M)_SrF,V^tN'd.n`Oϯp~л[sVH CڧkwH/xg:vWǛdy}2N8Nfl|x)ZmYۥ.0J.3]*HJ\S?@~y"(g"⍕uc(hL{f1?jãy4Xن$+%?)m`X*t}w #e.E6-1^N%8ҩ6O!ަ\]PoB3E_6N'+驞u{l 5Z_])'fWt`&\]xcV׻_ endstream endobj 723 0 obj 3794 endobj 724 0 obj <> endobj 726 0 obj <> stream xZMoH_a $ =2mkK$'`/,ڱ%$'~Uդ0EvwUz<GywHxH#y+>ܽ#aGGwk?x@ɽI[dҫSդ' wOna1Ke/I[$\*K2grxlp.J}WU?\Ww r0.Ijc==,fm]}>/fӇ`6vl׋p`tb3kkvJiY<6k|X~ǟޯ6s\M)^mz^|{E٬0,2B3l]QG!h0Y!;lb)kO5X֧;I[-~ԋ@,\syeF; )&U󌰻X B*1 ی`Ɵ%MLJEx%AL >:]Z -a۾Lhr3¾JN#ct xnmS 盇 ūGo?i54P9ePy:-s@Llri6MЦt>e ]<#ıvVd~AP\@?uKGم%4ۤ)H_- Q JTTK`M=<sڲ|<O\Fp{5L>n[/xsZ [Eoi%1X=@;ӯ1E9P2q{arMU³A+ߨMNq>R yER*w:jGO%^]J JYHf19@;Qӝ]tEcXvg,q(l3WKV:BR,^0Z%ͻ@4]4r2]4oC/6? (3쏞h<߉"T^- EsUL*v]ƈ놖1GG-%w:пQ 0̑C8C 5gYv>N\q992k6j3mUv(RyN1|^ZZtbɪXeZlLDDG'4¥lTQ>HݾtPutU>lIyQ(gΏLLT&DQ#КukՅv5(h:]r|C,*mY6lr|$4-y u>p"nNjq ͺ,M~ ok9;XoE{7-$Pl4 'w>- ! \E_ɇ\{Qo0mr2VqQؓ b<.=t-:ȫb AjpNzAA՘r*5K3ʒdfU0zB ߰@ӫĩw|QbAE\1T: 'iX2_E-|BTey~[4n 3~N(QmHdhHKMQHB&=r2Zr'ڱ&*NW{5 ! ~'jpBo]7eE#@HF92@Q ?c= -FpL*%$`w5gVՠq}HЪ1ގ#(-8YIMbKc Hϛ bG~C+#xw|SLΠ^EOba&pD/ԋȋ;Zꢊ N\]zwZM@L.[\Q(#5S%(oEʤ__ĬÊzt55cŎC )C @dT3\LZq+~56/5jѦ8;!ĥ2F3јB.{~xhLQaUfQ}Q8%Qm4 39:s>q] 0eF,Sy;<DCL bq_AT}[TvI J_?I2 1I"HSTz<'EE UHHaٓg{1n!KTmT`T A9]DWKȆl6 瓽}iNb8XT62iEv Fkh*y CclXڟq-SyD iBӄ [,)uUunk JS"CK]Jf־ിj68G `Zb(4 ݡ܋dROGnn]ޥAG]Y6; 7E߿՗Ûg"J:64sUe-M%&75KV.Acz:.N:rmg0[NC>}ԭ}w7endstream endobj 727 0 obj 3969 endobj 728 0 obj <> endobj 730 0 obj <> stream x[n82OaMgD#R(nmd&ؙE^b+f"{(x2E.0y~^lN~?}B5kxGDF2)Od4K#N曓 ?i:,J8/O}$8O(^ s4;WFqƩYTdfm~o,b)g(1~4gwR1;IDxlo=IOHRi w4J_;Irf)^Q%^$"B:vps*"B翞_'HIK-RGgo/N{;MDthdD${c4brȁ E1D?,_^LgFM,-o $b$LQӔ~34e<=4,xf6|syuK$%GNAQ,QfI|>Ϣ J[`ל_ q~["LL6O'o 6EO-my,6A>Ū ~h` G@e\ "L8 nQM,ۮ) hcͺO X՗ L*PjYXD")zere*P剀`$+ WM+أ1!x}#d|| zQL۪2qrQFY#v`WdKd]|A7dmh|ψg q>69<) tvyj]0’@ @]N\3GA Ήk#YRXGm5bѕgy S{_a2ąP rxoq&8 |zזr*"i6h`i _BHb膨*ptG M߭z,%iqpwKXP.ZXJRn `yMe}g̊p]VW /¶.N# S 4SjѾAPPD P0H5h@ zEB8%5r< ~$}z2pnKߟL4Q-x^~)K-Ѱ Šޫք,ͬ|`u)Q )˫x,]^Gv1O+mz67.뢍~KBxEjCY?i_6?(FX3!]wݪge3PF&,,-zWqBSHh^lzĤHtd p;ujS/ǽY1)c:; -!i?\PTE}8|Iyسӧ0XXA|h+;N:0<(W̷LDѩJP-f|gdƌMQ=bN{XayX]Ⱦ :M% 69icPGuδ4SwW6>&h x#ԫN}΀~(ձM`nz='0Z0>VTA3+7uikdO&ɲ 1ۮ}<{{TN]{ f;ṫ9t"$6w˷WSRT<:Y08*/û8n G-񝛺uYty6fBʸBiwӑX,H {?1y"~k]T }$ OOcB.$ީOM>?TN}|ѩ\ @—:_3198:IS7PƺHb uIwYMcF#3k ٬52OYnzK~a*c%h֤ocI/qI/JPiwB7A&P trC򁘾Z+&ͷ&[aOO,1 "6 a8I sX%|,Pn)sөP)Ԝ'2Aok{:eIlۚ &?l\3f=a.M$fS5̕gM 6 ޑ՚IFYi-GjboM?°EIW7T~M&tZx*O}P%@=( VW>eiQo [ZQ왾\ϯ>8w}VG` a_~70"y(jAnEG#aT"oLX0,Z =5闥)kP:p"`R8{ƣ`jƤ3cF1jt6AQ,>洘 4Sώ~S?[/>Q h<nc>B;4̷MkQ AZp>K1a̎ (r{r`Uc(G&rGĨZ!~U Pm޶E"ܷ/C"PQ"_|-,b*̻աz"A7?\ MumSϞ=b]>4r?(&H{ל5M6=NbTv4Mh"Y+@Fճ,\BrV#%jA=nJTzŞ݂Wj/0b Wy#F:Q) b{s5,[=M)weK?8R0G^Ꭲe]ėR̂VԣgWNRR֟m"xfxX ޹K䗓_N 4Vendstream endobj 731 0 obj 3959 endobj 732 0 obj <> endobj 734 0 obj <> stream xe 0<ō:x&5С￘h pw'@){"[4C~ U_D:d!bCm+ Z IR֡:.!3ƌѳr]C齡3Ȥva1CU~ucs2g]xnAmendstream endobj 735 0 obj 189 endobj 736 0 obj <> endobj 738 0 obj <> stream xVnF -Їլ8ykAt<֖Ylrvc(ᐇf2{)O).O Z),ϳpIC )ofVvDpq>wOqLN%>.(Bxs}}sg 3QJR:JDӕOj)$7v.b. 2<_uЯb(-hJ.Ѵ1Ayo~E$KaA(x*h|TOwqwA-RV/J9l=1%gb U_"PM0Ԙ8a;JZ TCzq64Z2A~Y!*B?0F(ڧMSSfT8 sE)d1^7H6i:@*DHzUÈVe.xjP4eiX0^iY^*eck[lHM&6P}#i);%=RwdA86X]^34N춶[rrhS}ƒ(swD~O/wd*N(4up%=½p!OXmy CupY}MИpaםT1@Ͷe<3*k0'f?o-/]Ϣab_._E+J硷kKfνٰE4p %C\~g]ϋo҅nlendstream endobj 739 0 obj 1114 endobj 740 0 obj <> endobj 742 0 obj <> stream xu[O@}W&vKb`K")b1]Dȷs̜- ,~Ld1E8͵$S aD[ LNΑ\(k `MVyy4`VLG̀3pZ( 'G0Th(#̀fY:_)ZKYaiEEʷ=o`bHI?6,>f'脦1a3!Z`{OVi_6 G7mt1Ɂ~yd@0|tUUySw]WC԰/oÉ 26~b@e-Nuo)O)垦9Y' endstream endobj 743 0 obj 362 endobj 744 0 obj <> endobj 746 0 obj <> stream xXnFͳ ~yݸ1N"/ Z\I,D%iR}, pvs朙YaD ~s,.cGA T", $ q^]8HpqU-^lg)lđҊiɍy;GUDŏ? CgWD bLhZ1M4 pos8;+B!>8WƐ&,}A8CQ'%~0RȸCol|>mD5QD&Řz3hHǛ*Nœhw6¡8OUaė]Lm=z\24N׶lJ/\ N*.2%4UP ˼]Y JKӇb)l.8B B9,an0q9x$ijuFnٙNn5 rY+Y0}MmMlv=]W%svs<ӅFt|"̌`p{[6Jɶcx)2XpnmnT?'ѰwKɶ}\HRY(47ۨ6E7]KHHa GۃSk{ j/j 0 PM"PG4; ?L2 I1}=3qL$8r Hr{c55DԹF2=HXJD"y7F/'sH(һ{D/A,?H/vpQAHl"P=:) ))SWTX%ԀZOqAo#4bgP^=_*P- P`$Lg%h6`֡0[,YpRU쩆6ʗ<ձ:Rxqt$fNTlevc,;`5lxL8I耱k⇣CQZ9ׂn eH:K]$p]t"}؈d GtfPgPAӂyd\SNe`=lu8ԕM> endobj 750 0 obj <> stream xXnF-cTٗfDE[ @Kc E$'{9%Ke$ vϽCbDF gqcl1:AFRG#H9,IOn-9 1Pl}ɫJ0{2ꆈBFQ/.^{yGD8^u7fšG۳nR CDktÕ!Ҹ(HJ>G@ :B#fv`!&^!$Ҍ82HjLZ-g1bgen *4ִYkl86kQحۄp$)6K;s[cDEEմ7p :-r8##V3.i̘vnj!zϐ&){`)})xcK[iXd|z=1ou] LIUyvTQx`2~]zH Eļ;*! b'Eu5=_ҵUoK T!a h\YWeAwOpV ͪU9}` KDݪjRc. gYZ[{:ƕC\P*'#e{g*`)}IY7_C[iCbw6r|-PaSyn6^# L?EY]eM'bϩS ,N  p8sI28Fi*ls[Um-RUb])LY͛{,Ϭv;5op9f^'A$eq:7=#a!5"{z_M<)jq o6?v*liz^N_eV!T%JВSsBޑ 'i dmY\a*X!>(y'3}̠qI_#L?k<,7/M^X'!TI}w:"6 2 >кJ/&"ԣ +vNC+=1y ܽC^mķ 6HT4E]q~xo˼!d_].2%3%PpԠ~_+m*cil|Fr:W԰M^iū?bendstream endobj 751 0 obj 1711 endobj 752 0 obj <> endobj 754 0 obj <> stream xYmܶ.o+c dSڠn$خ( 0Zݭ]i\.áv}wJp^gb:\}Z:y}忄Yy歴zu}s_+ +[X&p/+VJtz{˷“JB_Xϯd:GH*ϊă.[2}2>2$ZpeP>>jChB"!ܤӆn}祤*x˛*Ƥӊ\XX6F%Ûvvl1py\, rmɮ1rƚdS#=?~^cM@mÏ ]ilѨxk DNT5\ݸtv:'AiE;6~^[CIE>;;݃&8EҒY] =4e7S0iɝƺe1 sw<-G -(YxØwVMolb8(ti YCIbp "ʖ7Op[Uk'i2B c)792T3Bp[VS>)rP=n ʏאvh’q hȩζ<-ƪ|tsaEPUm"^m>NqCHV3S2 ,KD;q%e_$>co)5[`)F,R@~ϗ5.  !sPF> %QBLppʄEضbPGɍwnU売$!A{Z_S"vw=xi8UU= 7i ғtBt J-1%drlۗ=nv*{>s&<w3!Jp5-r?hE1Shd}[oo%> ry-iiGd mמ6J@~ybvU9s@-a4, b0Q0l׫+yp5G}.ۃEF2$pB 8]\l9E7jI'-vj Du|h),{7)55 <2G>$ߚk(2/pT7AR )Y]u d6i xGu Hz-9^\P Ӏ.g9j:ܷ R ItI⫠EHYOeq *xj )(hr/i)N 2!{ƌ0zBJ߱btK~bJee빧ܺ;ߖЩӅya CZ"YEI RDk}unۺRK#U =J6qrvJmӢdž򤻿hLaȃHP@ \@r\pb?;v)6_ \/MIXH! xp.n,븣LIb˛Q3I_0<{|sh1W֏|wt$i,TFs0S pQ (Ssf^ج@65b @3A@U+U[8.DTl0_8̵ieD%L6*Iy@xTb$,Ȏ<ς4c%#~*cM 5果O[+xkhZQ̩|-Q"oUآq7XX9}u_簣z%?II*ݖ0clyaDz SwM݃v*?iP(ͺO&= rl a=1 GE}_ЩoA5OpՅM~SCiTg@/;ˤ&RNrӈS?9 Nv& Y0~evM#I$v䖇'>,vP\K M"aho&h҇E 1@ ^S+B4}JQg|0*|Op0'C_"~O?C!h($0~A?PXSBUuC3P2==_|䀤048>3#@s&cak3wC?ѝRS4mND50'Es(9:vNrK ;W׫wWu endstream endobj 755 0 obj 2851 endobj 756 0 obj <> endobj 758 0 obj <> stream xXnFB mGq.@0 m1I;mHr$yp0̙3g:ܿwQ|;6ޖ,o_/XbSb2= 脪(3QF&U lXaw|vvv Mճ%&3QMf&O>")\/iΙ ɸ4X4}x5sVHT:rB\JSRh/!g@2H6QW/-n$4]̻&"J06msUUw> E°ͦi;u4_.GYejS,|7PM d銢^.mtYRR.z2"x>E )gb3XɔpcYϷoOJ 7*}0EZtT)+?Qb(bQf!˒kb"PUO|xU顡`6*n˛uL'NiMW<2KźEN, >L9`fB|P z4uHsXth9<^Aat^6T^/c>Cմ@A3`*iT޽3i+9s|SAXXhϺƄdXd=¡vRȫͺ-gtreB6P~;EƟ‚ƾX*O؞'fЃ[bbSDFj-T)38[Sτ6e@?A&,Y5O!WG X%',Ǣ-|{W(&-iK㲩H<XRc0>iȭq5t4E>+ҵ$y( Jn hM<4¹(kicکxYӭ qϮ^è OJp|,vUQkDh|Mç(aHcثݭbǡ2j vvmzgnT+҃cSVinݖN&EӸw\<,HnpIdx(x\NULsO5)'SГi(0rˡEѹdz, i$7{2Y1eiP0er-_4sUOTwl>%{f{ghYsXcwb/Xn>ĴW1gFhĉ=LDfwWuV"XA̲޹$_`#JS? Ezc{ OG=qgzK5&3e *o"2+5Pl# ^x(#mOA?fcRcD-FLgK MXJ݇ŰuMYfD" T̈́L}/ۦv<+l688endstream endobj 759 0 obj 1801 endobj 760 0 obj <> endobj 5 0 obj <> /Contents 6 0 R >> endobj 16 0 obj <> /Contents 17 0 R >> endobj 22 0 obj <> /Contents 23 0 R >> endobj 28 0 obj <> /Contents 29 0 R >> endobj 34 0 obj <> /Contents 35 0 R >> endobj 38 0 obj <> /Contents 39 0 R >> endobj 42 0 obj <> /Contents 43 0 R >> endobj 46 0 obj <> /Contents 47 0 R >> endobj 52 0 obj <> /Contents 53 0 R >> endobj 58 0 obj <> /Contents 59 0 R >> endobj 64 0 obj <> /Contents 65 0 R >> endobj 71 0 obj <> /Contents 72 0 R >> endobj 83 0 obj <> /Contents 84 0 R >> endobj 87 0 obj <> /Contents 88 0 R >> endobj 91 0 obj <> /Contents 92 0 R >> endobj 97 0 obj <> /Contents 98 0 R >> endobj 101 0 obj <> /Contents 102 0 R >> endobj 105 0 obj <> /Contents 106 0 R >> endobj 109 0 obj <> /Contents 110 0 R >> endobj 113 0 obj <> /Contents 114 0 R >> endobj 119 0 obj <> /Contents 120 0 R >> endobj 123 0 obj <> /Contents 124 0 R >> endobj 127 0 obj <> /Contents 128 0 R >> endobj 133 0 obj <> /Contents 134 0 R >> endobj 137 0 obj <> /Contents 138 0 R >> endobj 141 0 obj <> /Contents 142 0 R >> endobj 145 0 obj <> /Contents 146 0 R >> endobj 149 0 obj <> /Contents 150 0 R >> endobj 153 0 obj <> /Contents 154 0 R >> endobj 157 0 obj <> /Contents 158 0 R >> endobj 161 0 obj <> /Contents 162 0 R >> endobj 165 0 obj <> /Contents 166 0 R >> endobj 169 0 obj <> /Contents 170 0 R >> endobj 173 0 obj <> /Contents 174 0 R >> endobj 177 0 obj <> /Contents 178 0 R >> endobj 181 0 obj <> /Contents 182 0 R >> endobj 185 0 obj <> /Contents 186 0 R >> endobj 189 0 obj <> /Contents 190 0 R >> endobj 195 0 obj <> /Contents 196 0 R >> endobj 199 0 obj <> /Contents 200 0 R >> endobj 203 0 obj <> /Contents 204 0 R >> endobj 207 0 obj <> /Contents 208 0 R >> endobj 211 0 obj <> /Contents 212 0 R >> endobj 215 0 obj <> /Contents 216 0 R >> endobj 219 0 obj <> /Contents 220 0 R >> endobj 223 0 obj <> /Contents 224 0 R >> endobj 227 0 obj <> /Contents 228 0 R >> endobj 231 0 obj <> /Contents 232 0 R >> endobj 235 0 obj <> /Contents 236 0 R >> endobj 239 0 obj <> /Contents 240 0 R >> endobj 245 0 obj <> /Contents 246 0 R >> endobj 249 0 obj <> /Contents 250 0 R >> endobj 253 0 obj <> /Contents 254 0 R >> endobj 259 0 obj <> /Contents 260 0 R >> endobj 263 0 obj <> /Contents 264 0 R >> endobj 267 0 obj <> /Contents 268 0 R >> endobj 271 0 obj <> /Contents 272 0 R >> endobj 275 0 obj <> /Contents 276 0 R >> endobj 279 0 obj <> /Contents 280 0 R >> endobj 283 0 obj <> /Contents 284 0 R >> endobj 289 0 obj <> /Contents 290 0 R >> endobj 293 0 obj <> /Contents 294 0 R >> endobj 299 0 obj <> /Contents 300 0 R >> endobj 303 0 obj <> /Contents 304 0 R >> endobj 307 0 obj <> /Contents 308 0 R >> endobj 311 0 obj <> /Contents 312 0 R >> endobj 315 0 obj <> /Contents 316 0 R >> endobj 319 0 obj <> /Contents 320 0 R >> endobj 323 0 obj <> /Contents 324 0 R >> endobj 327 0 obj <> /Contents 328 0 R >> endobj 331 0 obj <> /Contents 332 0 R >> endobj 335 0 obj <> /Contents 336 0 R >> endobj 339 0 obj <> /Contents 340 0 R >> endobj 343 0 obj <> /Contents 344 0 R >> endobj 347 0 obj <> /Contents 348 0 R >> endobj 351 0 obj <> /Contents 352 0 R >> endobj 355 0 obj <> /Contents 356 0 R >> endobj 359 0 obj <> /Contents 360 0 R >> endobj 363 0 obj <> /Contents 364 0 R >> endobj 367 0 obj <> /Contents 368 0 R >> endobj 371 0 obj <> /Contents 372 0 R >> endobj 375 0 obj <> /Contents 376 0 R >> endobj 379 0 obj <> /Contents 380 0 R >> endobj 383 0 obj <> /Contents 384 0 R >> endobj 387 0 obj <> /Contents 388 0 R >> endobj 391 0 obj <> /Contents 392 0 R >> endobj 395 0 obj <> /Contents 396 0 R >> endobj 399 0 obj <> /Contents 400 0 R >> endobj 403 0 obj <> /Contents 404 0 R >> endobj 407 0 obj <> /Contents 408 0 R >> endobj 411 0 obj <> /Contents 412 0 R >> endobj 415 0 obj <> /Contents 416 0 R >> endobj 419 0 obj <> /Contents 420 0 R >> endobj 423 0 obj <> /Contents 424 0 R >> endobj 427 0 obj <> /Contents 428 0 R >> endobj 431 0 obj <> /Contents 432 0 R >> endobj 435 0 obj <> /Contents 436 0 R >> endobj 439 0 obj <> /Contents 440 0 R >> endobj 443 0 obj <> /Contents 444 0 R >> endobj 447 0 obj <> /Contents 448 0 R >> endobj 451 0 obj <> /Contents 452 0 R >> endobj 455 0 obj <> /Contents 456 0 R >> endobj 459 0 obj <> /Contents 460 0 R >> endobj 463 0 obj <> /Contents 464 0 R >> endobj 467 0 obj <> /Contents 468 0 R >> endobj 471 0 obj <> /Contents 472 0 R >> endobj 475 0 obj <> /Contents 476 0 R >> endobj 479 0 obj <> /Contents 480 0 R >> endobj 483 0 obj <> /Contents 484 0 R >> endobj 487 0 obj <> /Contents 488 0 R >> endobj 491 0 obj <> /Contents 492 0 R >> endobj 495 0 obj <> /Contents 496 0 R >> endobj 499 0 obj <> /Contents 500 0 R >> endobj 503 0 obj <> /Contents 504 0 R >> endobj 507 0 obj <> /Contents 508 0 R >> endobj 511 0 obj <> /Contents 512 0 R >> endobj 515 0 obj <> /Contents 516 0 R >> endobj 519 0 obj <> /Contents 520 0 R >> endobj 523 0 obj <> /Contents 524 0 R >> endobj 529 0 obj <> /Contents 530 0 R >> endobj 549 0 obj <> /Contents 550 0 R >> endobj 553 0 obj <> /Contents 554 0 R >> endobj 557 0 obj <> /Contents 558 0 R >> endobj 561 0 obj <> /Contents 562 0 R >> endobj 565 0 obj <> /Contents 566 0 R >> endobj 569 0 obj <> /Contents 570 0 R >> endobj 573 0 obj <> /Contents 574 0 R >> endobj 577 0 obj <> /Contents 578 0 R >> endobj 581 0 obj <> /Contents 582 0 R >> endobj 585 0 obj <> /Contents 586 0 R >> endobj 589 0 obj <> /Contents 590 0 R >> endobj 593 0 obj <> /Contents 594 0 R >> endobj 597 0 obj <> /Contents 598 0 R >> endobj 601 0 obj <> /Contents 602 0 R >> endobj 641 0 obj <> /Contents 642 0 R >> endobj 645 0 obj <> /Contents 646 0 R >> endobj 649 0 obj <> /Contents 650 0 R >> endobj 653 0 obj <> /Contents 654 0 R >> endobj 657 0 obj <> /Contents 658 0 R >> endobj 661 0 obj <> /Contents 662 0 R >> endobj 665 0 obj <> /Contents 666 0 R >> endobj 669 0 obj <> /Contents 670 0 R >> endobj 673 0 obj <> /Contents 674 0 R >> endobj 677 0 obj <> /Contents 678 0 R >> endobj 681 0 obj <> /Contents 682 0 R >> endobj 685 0 obj <> /Contents 686 0 R >> endobj 689 0 obj <> /Contents 690 0 R >> endobj 693 0 obj <> /Contents 694 0 R >> endobj 697 0 obj <> /Contents 698 0 R >> endobj 701 0 obj <> /Contents 702 0 R >> endobj 705 0 obj <> /Contents 706 0 R >> endobj 709 0 obj <> /Contents 710 0 R >> endobj 713 0 obj <> /Contents 714 0 R >> endobj 717 0 obj <> /Contents 718 0 R >> endobj 721 0 obj <> /Contents 722 0 R >> endobj 725 0 obj <> /Contents 726 0 R >> endobj 729 0 obj <> /Contents 730 0 R >> endobj 733 0 obj <> /Contents 734 0 R >> endobj 737 0 obj <> /Contents 738 0 R >> endobj 741 0 obj <> /Contents 742 0 R >> endobj 745 0 obj <> /Contents 746 0 R >> endobj 749 0 obj <> /Contents 750 0 R >> endobj 753 0 obj <> /Contents 754 0 R >> endobj 757 0 obj <> /Contents 758 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R 16 0 R 22 0 R 28 0 R 34 0 R 38 0 R 42 0 R 46 0 R 52 0 R 58 0 R 64 0 R 71 0 R 83 0 R 87 0 R 91 0 R 97 0 R 101 0 R 105 0 R 109 0 R 113 0 R 119 0 R 123 0 R 127 0 R 133 0 R 137 0 R 141 0 R 145 0 R 149 0 R 153 0 R 157 0 R 161 0 R 165 0 R 169 0 R 173 0 R 177 0 R 181 0 R 185 0 R 189 0 R 195 0 R 199 0 R 203 0 R 207 0 R 211 0 R 215 0 R 219 0 R 223 0 R 227 0 R 231 0 R 235 0 R 239 0 R 245 0 R 249 0 R 253 0 R 259 0 R 263 0 R 267 0 R 271 0 R 275 0 R 279 0 R 283 0 R 289 0 R 293 0 R 299 0 R 303 0 R 307 0 R 311 0 R 315 0 R 319 0 R 323 0 R 327 0 R 331 0 R 335 0 R 339 0 R 343 0 R 347 0 R 351 0 R 355 0 R 359 0 R 363 0 R 367 0 R 371 0 R 375 0 R 379 0 R 383 0 R 387 0 R 391 0 R 395 0 R 399 0 R 403 0 R 407 0 R 411 0 R 415 0 R 419 0 R 423 0 R 427 0 R 431 0 R 435 0 R 439 0 R 443 0 R 447 0 R 451 0 R 455 0 R 459 0 R 463 0 R 467 0 R 471 0 R 475 0 R 479 0 R 483 0 R 487 0 R 491 0 R 495 0 R 499 0 R 503 0 R 507 0 R 511 0 R 515 0 R 519 0 R 523 0 R 529 0 R 549 0 R 553 0 R 557 0 R 561 0 R 565 0 R 569 0 R 573 0 R 577 0 R 581 0 R 585 0 R 589 0 R 593 0 R 597 0 R 601 0 R 641 0 R 645 0 R 649 0 R 653 0 R 657 0 R 661 0 R 665 0 R 669 0 R 673 0 R 677 0 R 681 0 R 685 0 R 689 0 R 693 0 R 697 0 R 701 0 R 705 0 R 709 0 R 713 0 R 717 0 R 721 0 R 725 0 R 729 0 R 733 0 R 737 0 R 741 0 R 745 0 R 749 0 R 753 0 R 757 0 R ] /Count 164 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 67 0 obj <> endobj 69 0 obj <> stream 0 0 0 0 39 38 d1 39 0 0 38 0 0 cm BI /IM true /W 39 /H 38 /BPC 1 /F /CCF /DP <> ID &f?z k- EI endstream endobj 533 0 obj <> stream 0 0 0 0 81 101 d1 81 0 0 101 0 0 cm BI /IM true /W 81 /H 101 /BPC 1 /F /CCF /DP <> ID &p74zAo_?7A'}>M}oaxwP|5={~a{€ EI endstream endobj 534 0 obj <> stream 0 0 0 32 50 79 d1 50 0 0 47 0 32 cm BI /IM true /W 50 /H 47 /BPC 1 /F /CCF /DP <> ID &|/ 6kqmacoh<7y5^w kwșOh>M5 '|1 ,A@ EI endstream endobj 535 0 obj <> stream 0 0 0 -45 39 2 d1 39 0 0 47 0 -45 cm BI /IM true /W 39 /H 47 /BPC 1 /F /CCF /DP <> ID &™ 0}~`\ ~R܆)op}￷]Xzn EI endstream endobj 536 0 obj <> stream 0 0 0 -70 22 0 d1 22 0 0 70 0 -70 cm BI /IM true /W 22 /H 70 /BPC 1 /F /CCF /DP <> ID jDkɨ EI endstream endobj 537 0 obj <> stream 0 0 0 -45 50 0 d1 50 0 0 45 0 -45 cm BI /IM true /W 50 /H 45 /BPC 1 /F /CCF /DP <> ID &Nis4-[ BQ@ EI endstream endobj 538 0 obj <> stream 28 0 0 0 0 0 d1 endstream endobj 539 0 obj <> stream 0 0 0 -46 45 2 d1 45 0 0 48 0 -46 cm BI /IM true /W 45 /H 48 /BPC 1 /F /CCF /DP <> ID &@13PzMAXz Ow&_K_ m.ް !~( EI endstream endobj 540 0 obj <> stream 0 0 0 -46 46 22 d1 46 0 0 68 0 -46 cm BI /IM true /W 46 /H 68 /BPC 1 /F /CCF /DP <> ID &0@0|'M5L/2+Z 0z3_䏶?&  v׆a! EI endstream endobj 541 0 obj <> stream 50 0 0 0 0 0 d1 endstream endobj 542 0 obj <> stream 0 0 0 -32 27 14 d1 27 0 0 46 0 -32 cm BI /IM true /W 27 /H 46 /BPC 1 /F /CCF /DP <> ID &Mʿ|< EI endstream endobj 543 0 obj <> stream 55 0 0 0 0 0 d1 endstream endobj 544 0 obj <> stream 0 0 0 -32 33 16 d1 33 0 0 48 0 -32 cm BI /IM true /W 33 /H 48 /BPC 1 /F /CCF /DP <> ID &XGzL?-U=vAo[ 3@ EI endstream endobj 545 0 obj <> stream 37 0 0 0 0 0 d1 endstream endobj 546 0 obj <> stream 27 0 0 0 0 0 d1 endstream endobj 547 0 obj <> stream 51 0 0 0 0 0 d1 endstream endobj 605 0 obj <> stream 0 0 0 0 68 72 d1 68 0 0 72 0 0 cm BI /IM true /W 68 /H 72 /BPC 1 /F /CCF /DP <> ID %?R(@p ޸~. o׿o_  EI endstream endobj 606 0 obj <> stream 0 0 0 2 37 74 d1 37 0 0 72 0 2 cm BI /IM true /W 37 /H 72 /BPC 1 /F /CCF /DP <> ID &=&a}7o;^]!x0]_ EI endstream endobj 607 0 obj <> stream 75 0 0 0 0 0 d1 endstream endobj 608 0 obj <> stream 0 0 0 27 44 74 d1 44 0 0 47 0 27 cm BI /IM true /W 44 /H 47 /BPC 1 /F /CCF /DP <> ID &G<zM~Vn?~|í^`d4U4 EI endstream endobj 609 0 obj <> stream 42 0 0 0 0 0 d1 endstream endobj 610 0 obj <> stream 0 0 0 27 40 74 d1 40 0 0 47 0 27 cm BI /IM true /W 40 /H 47 /BPC 1 /F /CCF /DP <> ID &l>}rjB=s4t oNbb0 EI endstream endobj 611 0 obj <> stream 47 0 0 0 0 0 d1 endstream endobj 612 0 obj <> stream 0 0 0 9 31 74 d1 31 0 0 65 0 9 cm BI /IM true /W 31 /H 65 /BPC 1 /F /CCF /DP <> ID &>0C}߿;"y5_!{ﰾ  EI endstream endobj 613 0 obj <> stream 0 0 0 1 60 75 d1 60 0 0 74 0 1 cm BI /IM true /W 60 /H 74 /BPC 1 /F /CCF /DP <> ID &`6B F` 6 o  u ` XAh-tT| 9@i!k߰av{3A1?i EI endstream endobj 614 0 obj <> stream 65 0 0 0 0 0 d1 endstream endobj 615 0 obj <> stream 0 0 0 27 47 74 d1 47 0 0 47 0 27 cm BI /IM true /W 47 /H 47 /BPC 1 /F /CCF /DP <> ID & `0h a ;A?ɯ>pOo.Cd  EI endstream endobj 616 0 obj <> stream 52 0 0 0 0 0 d1 endstream endobj 617 0 obj <> stream 0 0 0 -39 66 -12 d1 66 0 0 27 0 -39 cm BI /IM true /W 66 /H 27 /BPC 1 /F /CCF /DP <> ID &?4@ EI endstream endobj 618 0 obj <> stream 76 0 0 0 0 0 d1 endstream endobj 619 0 obj <> stream 0 0 0 -69 72 0 d1 72 0 0 69 0 -69 cm BI /IM true /W 72 /H 69 /BPC 1 /F /CCF /DP <> ID T@prj67?|6?nw^pK\4 d~~w>^%]S `  EI endstream endobj 620 0 obj <> stream 104 0 0 0 0 0 d1 endstream endobj 621 0 obj <> stream 0 0 0 -45 46 21 d1 46 0 0 66 0 -45 cm BI /IM true /W 46 /H 66 /BPC 1 /F /CCF /DP <> ID &!T?<vvjj w<$ޯww ߶߆Xyưb EI endstream endobj 622 0 obj <> stream 45 0 0 0 0 0 d1 endstream endobj 623 0 obj <> stream 0 0 0 -67 26 2 d1 26 0 0 69 0 -67 cm BI /IM true /W 26 /H 69 /BPC 1 /F /CCF /DP <> ID & z<޷?|b`^? ( EI endstream endobj 624 0 obj <> stream 53 0 0 0 0 0 d1 endstream endobj 625 0 obj <> stream 0 0 0 -45 54 2 d1 54 0 0 47 0 -45 cm BI /IM true /W 54 /H 47 /BPC 1 /F /CCF /DP <> ID &l2τa8{ppp߿ }&> stream 34 0 0 0 0 0 d1 endstream endobj 627 0 obj <> stream 0 0 0 -69 98 3 d1 98 0 0 72 0 -69 cm BI /IM true /W 98 /H 72 /BPC 1 /F /CCF /DP <> ID &H*A4_h{~߸_zx>߿xa? {>~ݿ݇`$! B EI endstream endobj 628 0 obj <> stream 79 0 0 0 0 0 d1 endstream endobj 629 0 obj <> stream 0 0 0 2 47 74 d1 47 0 0 72 0 2 cm BI /IM true /W 47 /H 72 /BPC 1 /F /CCF /DP <> ID &n|/A{ ;ׯ\.H i~ݲ i n~߰8 B"Ubp EI endstream endobj 630 0 obj <> stream 49 0 0 0 0 0 d1 endstream endobj 631 0 obj <> stream 0 0 0 14 66 80 d1 66 0 0 66 0 14 cm BI /IM true /W 66 /H 66 /BPC 1 /F /CCF /DP <> ID &`~4?dsj  EI endstream endobj 632 0 obj <> stream 78 0 0 0 0 0 d1 endstream endobj 633 0 obj <> stream 98 0 0 0 0 0 d1 endstream endobj 634 0 obj <> stream 0 0 0 1 68 92 d1 68 0 0 91 0 1 cm BI /IM true /W 68 /H 91 /BPC 1 /F /CCF /DP <> ID &| }3}!o " a4|.o'޷jޭ~1O0A߷??~}uwoᴶ[i`a \y d@@ EI endstream endobj 635 0 obj <> stream 68 0 0 0 0 0 d1 endstream endobj 636 0 obj <> stream 0 0 0 3 61 72 d1 61 0 0 69 0 3 cm BI /IM true /W 61 /H 69 /BPC 1 /F /CCF /DP <> ID $P@;;w~.7 EI endstream endobj 637 0 obj <> stream 0 0 0 3 73 72 d1 73 0 0 69 0 3 cm BI /IM true /W 73 /H 69 /BPC 1 /F /CCF /DP <> ID )@!8e=4}CD?f u@r ~  EI endstream endobj 638 0 obj <> stream 85 0 0 0 0 0 d1 endstream endobj 639 0 obj <> stream 48 0 0 0 0 0 d1 endstream endobj 21 0 obj <> endobj 131 0 obj <> endobj 761 0 obj <> endobj 604 0 obj <>/FontBBox[0 -27 98 141]/FontMatrix[1 0 0 1 0 0]/FirstChar 0/LastChar 36/Widths[ 0 0 75 0 42 0 47 0 0 55 65 0 37 52 0 76 0 104 0 45 0 53 0 34 0 79 0 49 0 78 98 0 68 0 0 85 48] >> endobj 532 0 obj <>/FontBBox[0 -32 81 140]/FontMatrix[1 0 0 1 0 0]/FirstChar 0/LastChar 14/Widths[ 0 0 0 0 0 28 0 0 50 0 55 0 37 27 51] >> endobj 68 0 obj <>/FontBBox[0 0 39 38]/FontMatrix[1 0 0 1 0 0]/FirstChar 0/LastChar 0/Widths[ 0] >> endobj 526 0 obj <> endobj 15 0 obj <> endobj 762 0 obj <> endobj 117 0 obj <> endobj 763 0 obj <> endobj 527 0 obj <> endobj 11 0 obj <> endobj 95 0 obj <> endobj 764 0 obj <> endobj 81 0 obj <> endobj 765 0 obj <> endobj 9 0 obj <> endobj 296 0 obj <> endobj 80 0 obj <> endobj 78 0 obj <> endobj 74 0 obj <> endobj 31 0 obj <> endobj 14 0 obj <> endobj 10 0 obj <> endobj 8 0 obj <> endobj 79 0 obj <> endobj 297 0 obj <> endobj 77 0 obj <> endobj 766 0 obj <> endobj 75 0 obj <> endobj 286 0 obj <> endobj 192 0 obj <> endobj 287 0 obj <> endobj 256 0 obj <> endobj 130 0 obj <> endobj 116 0 obj <> endobj 76 0 obj <> endobj 61 0 obj <> endobj 55 0 obj <> endobj 50 0 obj <> endobj 25 0 obj <> endobj 20 0 obj <> endobj 62 0 obj <> endobj 767 0 obj <> endobj 257 0 obj <> endobj 56 0 obj <> endobj 768 0 obj <> endobj 51 0 obj <> endobj 242 0 obj <> endobj 94 0 obj <> endobj 32 0 obj <> endobj 243 0 obj <> endobj 26 0 obj <> endobj 769 0 obj <> endobj 193 0 obj <> endobj 2 0 obj <>endobj xref 0 770 0000000000 65535 f 0000488474 00000 n 0000526821 00000 n 0000487124 00000 n 0000488522 00000 n 0000462165 00000 n 0000000015 00000 n 0000000409 00000 n 0000510885 00000 n 0000509319 00000 n 0000510823 00000 n 0000505717 00000 n 0000000428 00000 n 0000000458 00000 n 0000510761 00000 n 0000502105 00000 n 0000462325 00000 n 0000000499 00000 n 0000000654 00000 n 0000000673 00000 n 0000517311 00000 n 0000498442 00000 n 0000462469 00000 n 0000000705 00000 n 0000002302 00000 n 0000517250 00000 n 0000524480 00000 n 0000002323 00000 n 0000462613 00000 n 0000002377 00000 n 0000004514 00000 n 0000510699 00000 n 0000522213 00000 n 0000004535 00000 n 0000462757 00000 n 0000004589 00000 n 0000006749 00000 n 0000006770 00000 n 0000462901 00000 n 0000006824 00000 n 0000009013 00000 n 0000009034 00000 n 0000463045 00000 n 0000009088 00000 n 0000010995 00000 n 0000011016 00000 n 0000463189 00000 n 0000011070 00000 n 0000011254 00000 n 0000011274 00000 n 0000517189 00000 n 0000520949 00000 n 0000463324 00000 n 0000011317 00000 n 0000013697 00000 n 0000517128 00000 n 0000519709 00000 n 0000013718 00000 n 0000463476 00000 n 0000013794 00000 n 0000018121 00000 n 0000517067 00000 n 0000517372 00000 n 0000018142 00000 n 0000463620 00000 n 0000018207 00000 n 0000021603 00000 n 0000488577 00000 n 0000501867 00000 n 0000489815 00000 n 0000021624 00000 n 0000463772 00000 n 0000021687 00000 n 0000025444 00000 n 0000510637 00000 n 0000514438 00000 n 0000517009 00000 n 0000513214 00000 n 0000510575 00000 n 0000510946 00000 n 0000510513 00000 n 0000508080 00000 n 0000025465 00000 n 0000463924 00000 n 0000025574 00000 n 0000028781 00000 n 0000028802 00000 n 0000464076 00000 n 0000028889 00000 n 0000033066 00000 n 0000033087 00000 n 0000464228 00000 n 0000033185 00000 n 0000036842 00000 n 0000522150 00000 n 0000506850 00000 n 0000036863 00000 n 0000464380 00000 n 0000036939 00000 n 0000040778 00000 n 0000040799 00000 n 0000464533 00000 n 0000040854 00000 n 0000042751 00000 n 0000042773 00000 n 0000464688 00000 n 0000042872 00000 n 0000043620 00000 n 0000043641 00000 n 0000464843 00000 n 0000043718 00000 n 0000047285 00000 n 0000047307 00000 n 0000464998 00000 n 0000047406 00000 n 0000049699 00000 n 0000516950 00000 n 0000503355 00000 n 0000049721 00000 n 0000465153 00000 n 0000049789 00000 n 0000052484 00000 n 0000052506 00000 n 0000465308 00000 n 0000052585 00000 n 0000056426 00000 n 0000056448 00000 n 0000465463 00000 n 0000056560 00000 n 0000060285 00000 n 0000516891 00000 n 0000499579 00000 n 0000060307 00000 n 0000465618 00000 n 0000060432 00000 n 0000063588 00000 n 0000063610 00000 n 0000465773 00000 n 0000063711 00000 n 0000066797 00000 n 0000066819 00000 n 0000465928 00000 n 0000066898 00000 n 0000069432 00000 n 0000069454 00000 n 0000466083 00000 n 0000069522 00000 n 0000072727 00000 n 0000072749 00000 n 0000466238 00000 n 0000072861 00000 n 0000075618 00000 n 0000075640 00000 n 0000466393 00000 n 0000075765 00000 n 0000078482 00000 n 0000078504 00000 n 0000466548 00000 n 0000078616 00000 n 0000081342 00000 n 0000081364 00000 n 0000466703 00000 n 0000081476 00000 n 0000084332 00000 n 0000084354 00000 n 0000466858 00000 n 0000084475 00000 n 0000088156 00000 n 0000088178 00000 n 0000467013 00000 n 0000088299 00000 n 0000091203 00000 n 0000091225 00000 n 0000467168 00000 n 0000091326 00000 n 0000094334 00000 n 0000094356 00000 n 0000467323 00000 n 0000094457 00000 n 0000097960 00000 n 0000097982 00000 n 0000467478 00000 n 0000098105 00000 n 0000100609 00000 n 0000100631 00000 n 0000467633 00000 n 0000100741 00000 n 0000103396 00000 n 0000103418 00000 n 0000467780 00000 n 0000103521 00000 n 0000106755 00000 n 0000515635 00000 n 0000525688 00000 n 0000106777 00000 n 0000467935 00000 n 0000106880 00000 n 0000107778 00000 n 0000107799 00000 n 0000468082 00000 n 0000107843 00000 n 0000108118 00000 n 0000108139 00000 n 0000468220 00000 n 0000108183 00000 n 0000109867 00000 n 0000109889 00000 n 0000468367 00000 n 0000109944 00000 n 0000113035 00000 n 0000113057 00000 n 0000468522 00000 n 0000113169 00000 n 0000116998 00000 n 0000117020 00000 n 0000468677 00000 n 0000117132 00000 n 0000120296 00000 n 0000120318 00000 n 0000468832 00000 n 0000120430 00000 n 0000123530 00000 n 0000123552 00000 n 0000468987 00000 n 0000123631 00000 n 0000126571 00000 n 0000126593 00000 n 0000469142 00000 n 0000126672 00000 n 0000130285 00000 n 0000130307 00000 n 0000469297 00000 n 0000130419 00000 n 0000133566 00000 n 0000133588 00000 n 0000469452 00000 n 0000133667 00000 n 0000136234 00000 n 0000136256 00000 n 0000469607 00000 n 0000136335 00000 n 0000138791 00000 n 0000522086 00000 n 0000523346 00000 n 0000138813 00000 n 0000469762 00000 n 0000138938 00000 n 0000142138 00000 n 0000142160 00000 n 0000469917 00000 n 0000142252 00000 n 0000145352 00000 n 0000145374 00000 n 0000470072 00000 n 0000145466 00000 n 0000148781 00000 n 0000516832 00000 n 0000518581 00000 n 0000148803 00000 n 0000470227 00000 n 0000148908 00000 n 0000152333 00000 n 0000152355 00000 n 0000470382 00000 n 0000152436 00000 n 0000155423 00000 n 0000155445 00000 n 0000470537 00000 n 0000155548 00000 n 0000158451 00000 n 0000158473 00000 n 0000470692 00000 n 0000158554 00000 n 0000161236 00000 n 0000161258 00000 n 0000470847 00000 n 0000161350 00000 n 0000164891 00000 n 0000164913 00000 n 0000471002 00000 n 0000165025 00000 n 0000168060 00000 n 0000168082 00000 n 0000471157 00000 n 0000168170 00000 n 0000171102 00000 n 0000515571 00000 n 0000515699 00000 n 0000171124 00000 n 0000471312 00000 n 0000171227 00000 n 0000174667 00000 n 0000174689 00000 n 0000471467 00000 n 0000174764 00000 n 0000177948 00000 n 0000510450 00000 n 0000512079 00000 n 0000177970 00000 n 0000471622 00000 n 0000178027 00000 n 0000181426 00000 n 0000181448 00000 n 0000471777 00000 n 0000181505 00000 n 0000184973 00000 n 0000184995 00000 n 0000471932 00000 n 0000185063 00000 n 0000188515 00000 n 0000188537 00000 n 0000472087 00000 n 0000188627 00000 n 0000192246 00000 n 0000192268 00000 n 0000472242 00000 n 0000192347 00000 n 0000195272 00000 n 0000195294 00000 n 0000472397 00000 n 0000195373 00000 n 0000199494 00000 n 0000199516 00000 n 0000472552 00000 n 0000199602 00000 n 0000202583 00000 n 0000202605 00000 n 0000472707 00000 n 0000202737 00000 n 0000206589 00000 n 0000206611 00000 n 0000472862 00000 n 0000206701 00000 n 0000210093 00000 n 0000210115 00000 n 0000473017 00000 n 0000210205 00000 n 0000213282 00000 n 0000213304 00000 n 0000473172 00000 n 0000213429 00000 n 0000216989 00000 n 0000217011 00000 n 0000473327 00000 n 0000217088 00000 n 0000219107 00000 n 0000219129 00000 n 0000473482 00000 n 0000219197 00000 n 0000222141 00000 n 0000222163 00000 n 0000473637 00000 n 0000222266 00000 n 0000224817 00000 n 0000224839 00000 n 0000473792 00000 n 0000224918 00000 n 0000227149 00000 n 0000227171 00000 n 0000473947 00000 n 0000227250 00000 n 0000230318 00000 n 0000230340 00000 n 0000474102 00000 n 0000230430 00000 n 0000233438 00000 n 0000233460 00000 n 0000474257 00000 n 0000233539 00000 n 0000235375 00000 n 0000235397 00000 n 0000474412 00000 n 0000235465 00000 n 0000238789 00000 n 0000238811 00000 n 0000474567 00000 n 0000238945 00000 n 0000241902 00000 n 0000241924 00000 n 0000474722 00000 n 0000242047 00000 n 0000244766 00000 n 0000244788 00000 n 0000474877 00000 n 0000244845 00000 n 0000247411 00000 n 0000247433 00000 n 0000475032 00000 n 0000247512 00000 n 0000250496 00000 n 0000250518 00000 n 0000475187 00000 n 0000250628 00000 n 0000253872 00000 n 0000253894 00000 n 0000475342 00000 n 0000254017 00000 n 0000257060 00000 n 0000257082 00000 n 0000475497 00000 n 0000257172 00000 n 0000259635 00000 n 0000259657 00000 n 0000475652 00000 n 0000259725 00000 n 0000262307 00000 n 0000262329 00000 n 0000475807 00000 n 0000262410 00000 n 0000265109 00000 n 0000265131 00000 n 0000475962 00000 n 0000265210 00000 n 0000268687 00000 n 0000268709 00000 n 0000476117 00000 n 0000268777 00000 n 0000271592 00000 n 0000271614 00000 n 0000476272 00000 n 0000271682 00000 n 0000274281 00000 n 0000274303 00000 n 0000476427 00000 n 0000274426 00000 n 0000274998 00000 n 0000275019 00000 n 0000476574 00000 n 0000275076 00000 n 0000277719 00000 n 0000277741 00000 n 0000476729 00000 n 0000277860 00000 n 0000280765 00000 n 0000280787 00000 n 0000476884 00000 n 0000280908 00000 n 0000283962 00000 n 0000283984 00000 n 0000477039 00000 n 0000284116 00000 n 0000287338 00000 n 0000287360 00000 n 0000477194 00000 n 0000287492 00000 n 0000290566 00000 n 0000290588 00000 n 0000477349 00000 n 0000290676 00000 n 0000293845 00000 n 0000293867 00000 n 0000477504 00000 n 0000294003 00000 n 0000297064 00000 n 0000297086 00000 n 0000477659 00000 n 0000297176 00000 n 0000299546 00000 n 0000299568 00000 n 0000477814 00000 n 0000299658 00000 n 0000301744 00000 n 0000301766 00000 n 0000477969 00000 n 0000301856 00000 n 0000304785 00000 n 0000304807 00000 n 0000478124 00000 n 0000304910 00000 n 0000307386 00000 n 0000307408 00000 n 0000478279 00000 n 0000307500 00000 n 0000310190 00000 n 0000310212 00000 n 0000478434 00000 n 0000310302 00000 n 0000313188 00000 n 0000313210 00000 n 0000478589 00000 n 0000313302 00000 n 0000315573 00000 n 0000315595 00000 n 0000478744 00000 n 0000315663 00000 n 0000317476 00000 n 0000317498 00000 n 0000478899 00000 n 0000317577 00000 n 0000320764 00000 n 0000320786 00000 n 0000479054 00000 n 0000320865 00000 n 0000323974 00000 n 0000323996 00000 n 0000479209 00000 n 0000324075 00000 n 0000326869 00000 n 0000326891 00000 n 0000479364 00000 n 0000326959 00000 n 0000329511 00000 n 0000329533 00000 n 0000479519 00000 n 0000329645 00000 n 0000330011 00000 n 0000330032 00000 n 0000479666 00000 n 0000330089 00000 n 0000333169 00000 n 0000333191 00000 n 0000479821 00000 n 0000333312 00000 n 0000336183 00000 n 0000336205 00000 n 0000479976 00000 n 0000336308 00000 n 0000339315 00000 n 0000339337 00000 n 0000480131 00000 n 0000339449 00000 n 0000342378 00000 n 0000342400 00000 n 0000480286 00000 n 0000342479 00000 n 0000345139 00000 n 0000502038 00000 n 0000504581 00000 n 0000345161 00000 n 0000480441 00000 n 0000345277 00000 n 0000347483 00000 n 0000501497 00000 n 0000490026 00000 n 0000490313 00000 n 0000490579 00000 n 0000490831 00000 n 0000491049 00000 n 0000491281 00000 n 0000491346 00000 n 0000491592 00000 n 0000491881 00000 n 0000491946 00000 n 0000492158 00000 n 0000492223 00000 n 0000492459 00000 n 0000492524 00000 n 0000492589 00000 n 0000347505 00000 n 0000480596 00000 n 0000347618 00000 n 0000349973 00000 n 0000349995 00000 n 0000480751 00000 n 0000350085 00000 n 0000353264 00000 n 0000353286 00000 n 0000480906 00000 n 0000353376 00000 n 0000354262 00000 n 0000354283 00000 n 0000481053 00000 n 0000354340 00000 n 0000354571 00000 n 0000354592 00000 n 0000481191 00000 n 0000354636 00000 n 0000357037 00000 n 0000357059 00000 n 0000481338 00000 n 0000357138 00000 n 0000361145 00000 n 0000361167 00000 n 0000481493 00000 n 0000361277 00000 n 0000364522 00000 n 0000364544 00000 n 0000481640 00000 n 0000364636 00000 n 0000366918 00000 n 0000366940 00000 n 0000481787 00000 n 0000366997 00000 n 0000370238 00000 n 0000370260 00000 n 0000481942 00000 n 0000370363 00000 n 0000372506 00000 n 0000372528 00000 n 0000482097 00000 n 0000372651 00000 n 0000376801 00000 n 0000376823 00000 n 0000482252 00000 n 0000376946 00000 n 0000379351 00000 n 0000379373 00000 n 0000482407 00000 n 0000379474 00000 n 0000381580 00000 n 0000381602 00000 n 0000482554 00000 n 0000381688 00000 n 0000386249 00000 n 0000500805 00000 n 0000492654 00000 n 0000492912 00000 n 0000493168 00000 n 0000493233 00000 n 0000493480 00000 n 0000493545 00000 n 0000493782 00000 n 0000493847 00000 n 0000494084 00000 n 0000494380 00000 n 0000494445 00000 n 0000494701 00000 n 0000494766 00000 n 0000494962 00000 n 0000495027 00000 n 0000495306 00000 n 0000495372 00000 n 0000495645 00000 n 0000495710 00000 n 0000495956 00000 n 0000496021 00000 n 0000496283 00000 n 0000496348 00000 n 0000496657 00000 n 0000496722 00000 n 0000497002 00000 n 0000497067 00000 n 0000497288 00000 n 0000497353 00000 n 0000497418 00000 n 0000497739 00000 n 0000497804 00000 n 0000498046 00000 n 0000498312 00000 n 0000498377 00000 n 0000386271 00000 n 0000482709 00000 n 0000386379 00000 n 0000388657 00000 n 0000388679 00000 n 0000482856 00000 n 0000388778 00000 n 0000391564 00000 n 0000391586 00000 n 0000483003 00000 n 0000391663 00000 n 0000394849 00000 n 0000394871 00000 n 0000483150 00000 n 0000394970 00000 n 0000398944 00000 n 0000398966 00000 n 0000483305 00000 n 0000399076 00000 n 0000402126 00000 n 0000402148 00000 n 0000483460 00000 n 0000402269 00000 n 0000405309 00000 n 0000405331 00000 n 0000483607 00000 n 0000405399 00000 n 0000408625 00000 n 0000408647 00000 n 0000483762 00000 n 0000408790 00000 n 0000409679 00000 n 0000409700 00000 n 0000483909 00000 n 0000409755 00000 n 0000412047 00000 n 0000412069 00000 n 0000484056 00000 n 0000412144 00000 n 0000413129 00000 n 0000413150 00000 n 0000484203 00000 n 0000413205 00000 n 0000414632 00000 n 0000414654 00000 n 0000484350 00000 n 0000414731 00000 n 0000414980 00000 n 0000415001 00000 n 0000484488 00000 n 0000415045 00000 n 0000417276 00000 n 0000417298 00000 n 0000484635 00000 n 0000417386 00000 n 0000420831 00000 n 0000420853 00000 n 0000484782 00000 n 0000420919 00000 n 0000424736 00000 n 0000424758 00000 n 0000484929 00000 n 0000424813 00000 n 0000425088 00000 n 0000425109 00000 n 0000485067 00000 n 0000425153 00000 n 0000427571 00000 n 0000427593 00000 n 0000485214 00000 n 0000427670 00000 n 0000431724 00000 n 0000431746 00000 n 0000485361 00000 n 0000431812 00000 n 0000435241 00000 n 0000435263 00000 n 0000485508 00000 n 0000435307 00000 n 0000439118 00000 n 0000439140 00000 n 0000485655 00000 n 0000439195 00000 n 0000443063 00000 n 0000443085 00000 n 0000485802 00000 n 0000443129 00000 n 0000447172 00000 n 0000447194 00000 n 0000485949 00000 n 0000447260 00000 n 0000451293 00000 n 0000451315 00000 n 0000486096 00000 n 0000451383 00000 n 0000451646 00000 n 0000451667 00000 n 0000486234 00000 n 0000451711 00000 n 0000452899 00000 n 0000452921 00000 n 0000486381 00000 n 0000453018 00000 n 0000453454 00000 n 0000453475 00000 n 0000486528 00000 n 0000453539 00000 n 0000455203 00000 n 0000455225 00000 n 0000486683 00000 n 0000455333 00000 n 0000457118 00000 n 0000457140 00000 n 0000486830 00000 n 0000457204 00000 n 0000460129 00000 n 0000460151 00000 n 0000486977 00000 n 0000460204 00000 n 0000462079 00000 n 0000462101 00000 n 0000500724 00000 n 0000503255 00000 n 0000504500 00000 n 0000507999 00000 n 0000509230 00000 n 0000514357 00000 n 0000518526 00000 n 0000520863 00000 n 0000525633 00000 n trailer << /Size 770 /Root 1 0 R /Info 2 0 R >> startxref 526873 %%EOF apq-3.2.0/legacy/build_files000066400000000000000000000051251171626402600157550ustar00rootroot00000000000000# $Id: build_files,v 1.19 2004/10/07 03:34:59 wwg Exp $ # Warren W. Gay VE3WWG # # Build File for distribution : APQ-2.1 d - 700 /release i apq-manual.pdf 400 / i APQ_VERSION 400 / i READ.ME 400 / i INSTALL 400 / i HISTORY 400 / i COPYING 400 / i PG_COPYRIGHT 400 / i ACL.txt 400 / i GPL.txt 400 / i Makefile 400 / i decimal.h 400 / i numeric.c 400 / i numeric.h 400 / i pgtypes.h 400 / i notices.c 400 / i apq.ads 400 / i apq.adb 400 / i apq-postgresql.ads 400 / i apq-postgresql-client.adb 400 / i apq-postgresql-client.ads 400 / i apq-postgresql-decimal.adb 400 / i apq-postgresql-decimal.ads 400 / i comp_pg.adb 400 / i c_mysql.c 400 / i mysql_gentyp.c 400 / i mysql_generr.c 400 / i mysqlopts.c 400 / i comp_mysql.adb 400 / i apq-mysql.ads-in 400 / i apq-mysql-client.ads 400 / i apq-mysql-client.adb 400 / i prep_sybase 500 / i sybase_gentyp.c 400 / i sybaseopts.c 400 / i c_sybase.c 400 / i apq-sybase.ads-in 400 / i apq-sybase.adb 400 / i apq-sybase-client.ads 400 / i apq-sybase-client.adb 400 / i comp_sybase.adb 400 / i prep_sybase 500 / i configure 500 / i mysql_incl 500 / i mysql_xty 500 / i mysql_xcr 500 / i mysql_xcr2 500 / i mysql_xcr3 500 / i install_lib 500 / i eg/Makefile 400 /eg i eg/getpwent.c 400 /eg i eg/getgrent.c 400 /eg i eg/create_pwdb_main.adb 400 /eg i eg/load_tables.adb 400 /eg i eg/load_tables.ads 400 /eg i eg/check_pwdb.adb 400 /eg i eg/check_tables.adb 400 /eg i eg/check_tables.ads 400 /eg i eg2/Makefile 400 /eg2 i eg2/getgrent.c 400 /eg2 i eg2/getpwent.c 400 /eg2 i eg2/create_pwdb_main.adb 400 /eg2 i eg2/load_tables.adb 400 /eg2 i eg2/load_tables.ads 400 /eg2 i eg2/check_pwdb.adb 400 /eg2 i eg2/check_tables.adb 400 /eg2 i eg2/check_tables.ads 400 /eg2 i eg2/check_mysql.adb 400 /eg2 i eg2/create_mysql.adb 400 /eg2 i win32_config 500 / i Makefile.win32 400 / i mysql_linker_options 500 / i gnat_info.adb 400 / i win32_registry.ads 400 / i win32_registry.adb 400 / i win32_gnat_info.ads 400 / i win32_gnat_info.adb 400 / i installer.nsi 400 / i win32_test.adb 400 / i win32.pdf 400 / i win32_copying.rtf 400 / i binaries/apq_myadapter.dll 400 /binaries i Makefile 600 /sybase i README 400 /sybase i params.ads 600 /sybase i checks.adb 400 /sybase i checks.ads 400 /sybase i copies.adb 400 /sybase i copies.ads 400 /sybase i load_db.adb 400 /sybase i my_pubs2.sql 400 /sybase i pg_pubs2.sql 400 /sybase i pubs2.adb 400 /sybase i pubs2_examples.adb 400 /sybase i pubs2_examples.ads 400 /sybase # End $Source: /cvsroot/apq/apq/build_files,v $ apq-3.2.0/legacy/build_release000077500000000000000000000022521171626402600162740ustar00rootroot00000000000000#!/bin/sh # $Id: build_release,v 1.4 2003/09/28 20:47:39 wwg Exp $ # Warren W. Gay VE3WWG # # Build a software release for distribution # # Driven by the build_files file. if [ "${1:-NOFORCE}" = FORCE ] ; then FORCE=1 shift else FORCE=0 fi set -eu BUILD_FILES="${1:-build_files}" directory() { DESTDIR="${PWD}$1" # Destination directory to build mode="$2" # Mode of the destination directory rm -fr "$DESTDIR" mkdir -p $DESTDIR chmod "$mode" "$DESTDIR" } install() { src="$1" # Source file name mode="$2" # Mode for destination file dst="$3" # Destination directory name bname=$(basename "$src") dstfile="${DESTDIR}${dst}/$bname" mkdir -p $(dirname $dstfile) if [ ! -r "$src" ] ; then echo "FILE '$src' is missing!" if [ $FORCE -eq 0 ] ; then exit 13 else return 0; # Ignore the error for test distributions fi fi cp "$src" "$dstfile" chmod "$mode" "$dstfile" ls -l "$dstfile" } sed '/^#/d;s|#.$||;/^ *$/d' <$BUILD_FILES | while read flg file mode dest rest ; do case $flg in d ) directory "$dest" "$mode";; i ) install "$file" "$mode" "$dest";; * ) echo "What is '$flg'?!?!?"; exit 13;; esac done # End $Source: /cvsroot/apq/apq/build_release,v $ apq-3.2.0/legacy/decimal.h000066400000000000000000000073401171626402600153210ustar00rootroot00000000000000/* $Id: decimal.h,v 1.4 2002/08/04 23:34:08 wwg Exp $ * Copyright (C) 2002, Warren W. Gay VE3WWG * * Licensed under the ACL (Ada Community License) * or * GNU Public License 2 (GPL2) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _DECIMAL_H_ #define _DECIMAL_H_ 1 #include "pgtypes.h" #include "numeric.h" enum Num_Exception { No_Error = 0, Numeric_Format, Numeric_Overflow, Undefined_Result, Divide_By_Zero }; typedef enum Num_Exception Decimal_Exception; extern int numeric_global_rscale(void); /* Initial value for global_rscale */ extern void numeric_free(Numeric num); /* Free storage used by Numeric */ extern int numeric_isnan(Numeric num); /* Test for NaN */ extern Numeric numeric_nan(void); /* Create a NaN */ extern Numeric numeric_in(const char *str,int precision,int scale,Decimal_Exception *ex); extern char * numeric_out(Numeric num); /* Numeric to String */ extern Numeric numeric(Numeric num, int precision, int scale, Decimal_Exception *ex); extern Numeric numeric_abs(Numeric num); /* Absolute value */ extern Numeric numeric_uminus(Numeric num); /* Unary minus */ extern Numeric numeric_uplus(Numeric num); /* Copy value */ extern Numeric numeric_sign(Numeric num); /* Determine sign */ extern Numeric numeric_round(Numeric num,int scale); /* Round */ extern Numeric numeric_trunc(Numeric num,int scale); /* Truncate */ extern Numeric numeric_ceil(Numeric num); /* Ceiling */ extern Numeric numeric_floor(Numeric num); /* Floor */ extern int numeric_cmp(Numeric num1, Numeric num2); /* Compare */ extern int numeric_eq(Numeric num1, Numeric num2); /* = */ extern int numeric_ne(Numeric num1, Numeric num2); /* != */ extern int numeric_gt(Numeric num1, Numeric num2); /* > */ extern int numeric_ge(Numeric num1, Numeric num2); /* >= */ extern int numeric_lt(Numeric num1, Numeric num2); /* < */ extern int numeric_le(Numeric num1, Numeric num2); /* <= */ extern Numeric numeric_add(Numeric num1, Numeric num2); /* + */ extern Numeric numeric_sub(Numeric num1, Numeric num2); /* - */ extern Numeric numeric_mul(Numeric num1, Numeric num2, int *global_rscale); /* * */ extern Numeric numeric_div(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex); /* / */ extern Numeric numeric_mod(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex); /* % */ extern Numeric numeric_smaller(Numeric num1, Numeric num2); /* min(a,b) */ extern Numeric numeric_larger(Numeric num1, Numeric num2); /* max(a,b) */ extern Numeric numeric_sqrt(Numeric num, int *global_rscale,Decimal_Exception *ex); /* Square root */ extern Numeric numeric_exp(Numeric num, int *global_rscale, Decimal_Exception *ex); /* Exponent */ extern Numeric numeric_ln(Numeric num, int *global_rscale, Decimal_Exception *ex); /* Ln */ extern Numeric numeric_log(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex); /* Log */ extern Numeric numeric_power(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex); /* Power */ #endif /* _DECIMAL_H_ */ /* End $Source: /cvsroot/apq/apq/decimal.h,v $ */ apq-3.2.0/legacy/gnat_info.adb000066400000000000000000000065111171626402600161650ustar00rootroot00000000000000-- $Id: gnat_info.adb,v 1.2 2003/09/24 15:45:37 wwg Exp $ -- Copyright (c) 2002, Warren W. Gay VE3WWG -- -- Licensed under the ACL (Ada Community License) -- or -- GNU Public License 2 (GPL2) -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -- Usage: gnat_info [-S|-A] [-M] [options] -- -S Output in shell assignment mode -- -A Output all values as shell assignments -- -M Output variables in Makefile format (no quotes) -- -- -r Get GNAT root directory -- -v Get GNAT version -- -b Get GNAT bin directory -- -B Get GNAT Bindings directory -- -w Get GNAT Windows binding directory -- -i Get GNAT adainclude directory -- -l Get GNAT adalib directory -- -- -a Get APQ version, if installed with Ada.Text_IO; with Ada.Characters.Latin_1; with GNAT.Command_Line; with Win32_GNAT_Info; use Ada.Text_IO; use Ada.Characters.Latin_1; use GNAT.Command_Line; use Win32_GNAT_Info; procedure GNAT_Info is S : Boolean := False; M : Boolean := False; procedure Emit(Varname, Val : String) is begin if S then Put(Varname & "="); if not M then Put(""""); end if; end if; Put(Val); if S then if not M then Put_Line(""""); end if; else New_Line; end if; end Emit; begin loop case GetOpt("S A M r v b B w i l a") is when NUL => exit; when 'S' => S := True; When 'M' => M := True; when 'r' => Emit("GNAT_ROOT",Root); when 'v' => Emit("GNAT_VERSION",Version); when 'b' => Emit("GNAT_BIN",Bin); when 'B' => Emit("GNAT_BINDINGS",Bindings_Directory); when 'w' => Emit("GNAT_WIN32_BINDINGS",Win32Ada_Bindings_Directory); when 'i' => Emit("GNAT_ADAINCLUDE",ADAINCLUDE); when 'l' => Emit("GNAT_ADALIB",ADALIB); when 'A' => S := True; Emit("GNAT_VERSION",Version); Emit("GNAT_ROOT",Root); Emit("GNAT_BIN",Bin); Emit("GNAT_BINDINGS",Bindings_Directory); Emit("GNAT_WIN32_BINDINGS",Win32Ada_Bindings_Directory); Emit("GNAT_ADAINCLUDE",ADAINCLUDE); Emit("GNAT_ADALIB",ADALIB); when 'a' => begin Emit("APQ_VERSION",APQ_Version); exception when others => Emit("APQ_VERSION","NOT INSTALLED"); end; when others => raise Program_Error; end case; end loop; end GNAT_Info; apq-3.2.0/legacy/install_lib000077500000000000000000000144161171626402600157760ustar00rootroot00000000000000#!/bin/sh # # $Id: install_lib,v 1.12 2003/09/27 21:07:57 wwg Exp $ # Warren W. Gay VE3WWG # # Licensed under the ACL (Ada Community License) TMPDIR="${TMPDIR:-/tmp}" # Temp file directory TMP="$TMPDIR/$$-1.tmp" # Temp file 1 trap "rm -f $TMP" 0 # Clean up temp file(s) on exit UNINSTALL=0 if [ "$1" = uninstall ] ; then UNINSTALL=1 # Uninstall orignal APQ stuff fi is_unix() { if [ "${WINDIR:-UNIX}" = UNIX ] ; then return 0; fi return 1; } # # Checks for ADA_INCLUDE_PATH or ADA_OBJECTS_PATH # check_variable() { AVAR="$1" AWHAT="$2" eval "APATH=\"\$$AVAR\"" if [ -z "$APATH" ] ; then cat <$TMP if [ $? -ne 0 ] ; then cat </dev/tty ---------------------------------------------------------------------- None of the directories in $AVAR are writable by $LOGNAME. You will need to either gain access to one directory referenced by $AVAR, or you will need to create a local directory and append that to the list int $AVAR. Try make install again, after you take care of this issue. ---------------------------------------------------------------------- EOF exit 1 fi count=$(wc -l <$TMP) if [ $count -gt 1 ] ; then loop=true while $loop ; do cat </dev/tty ---------------------------------------------------------------------- There is more than one writable directory in $AVAR that I could use. Please enter the line number you want to choose below: EOF cat -n $TMP >/dev/tty echo >/dev/tty echo "Enter your choice below (q to quit)?" >/dev/tty read selection /dev/tty echo "Choose a number between 1 and $count please." >/dev/tty echo >/dev/tty done dir=$(sed -n ${selection}p <$TMP) else dir=$(cat $TMP) fi echo "$dir" } check_instfile() { INSTVAR="$1" eval INSTLST="\$$INSTVAR" for file in $INSTLST ; do if [ ! -r $file ] ; then echo "Hey! File $file is not available to install." echo "Are you done make?" exit 1 fi done } install_files() { INSTVAR="$1" eval INSTLST="\$$INSTVAR" INSTDIR="$2" INSTMODE="$3" for file in $INSTLST ; do if [ ! -r $file ] ; then echo "Hey! File $file is not available to install!!!" echo "Are files being deleted as we install?!?!?!?!?" exit 13 fi rm -f "$INSTDIR/$file" cp -p "$file" "$INSTDIR/$file" chmod $INSTMODE "$INSTDIR/$file" ls -l "$INSTDIR/$file" done } uninstall_files() { INSTVAR="$1" eval INSTLST="\$$INSTVAR" INSTDIR="$2" INSTMODE="$3" for file in $INSTLST ; do if [ -f "$INSTDIR/$file" ] ; then echo "removing $INSTDIR/$file" rm -f "$INSTDIR/$file" fi done } HAVE_PG="${HAVE_PG:-0}" HAVE_MY="${HAVE_MY:-0}" HAVE_SY="${HAVE_SY:-0}" if [ $(expr $HAVE_PG + $HAVE_MY + $HAVE_SY) -eq 0 ] ; then cat <&2 You must run this script from a 'make install', or you must specify environment variables HAVE_PG and HAVE_MY (one of them must be true). EOF exit 13 fi check_variable ADA_INCLUDE_PATH "Ada95 specifications files" check_variable ADA_OBJECTS_PATH "Ada95 object files" INSTSPEC="apq.ads apq.adb" INSTALIS="apq.ali" INSTOBJS="libapq.a" if [ $HAVE_PG -gt 0 ] ; then INSTSPEC="$INSTSPEC apq-postgresql.ads apq-postgresql-client.ads apq-postgresql-client.adb" INSTSPEC="$INSTSPEC apq-postgresql-decimal.ads apq-postgresql-decimal.adb" INSTALIS="$INSTALIS apq-postgresql.ali apq-postgresql-client.ali apq-postgresql-decimal.ali" fi if [ $HAVE_MY -gt 0 ] ; then INSTSPEC="$INSTSPEC apq-mysql.ads apq-mysql-client.ads apq-mysql-client.adb" INSTALIS="$INSTALIS apq-mysql.ali apq-mysql-client.ali" fi if [ $HAVE_SY -gt 0 ] ; then INSTSPEC="$INSTSPEC apq-sybase.ads apq-sybase-client.ads apq-sybase-client.adb" INSTALIS="$INSTALIS apq-sybase.ali apq-sybase-client.ali" fi if [ $UNINSTALL -eq 0 ] ; then check_instfile INSTSPEC check_instfile INSTALIS check_instfile INSTOBJS fi INCLDIR=$(check_include ADA_INCLUDE_PATH) if [ $? -ne 0 ] ; then exit 1 fi OBJSDIR=$(check_include ADA_OBJECTS_PATH) if [ $? -ne 0 ] ; then exit 1 fi echo "Using ADA_INCLUDE_PATH=$INCLDIR" echo "Using ADA_OBJECTS_PATH=$OBJSDIR" if [ $UNINSTALL -ne 0 ] ; then uninstall_files INSTSPEC $INCLDIR 444 uninstall_files INSTALIS $OBJSDIR 444 uninstall_files INSTOBJS $OBJSDIR 444 echo "Uninstall complete." exit 0 fi echo echo "Ready to continue install? Press RETURN (Q or ^C to quit)" >/dev/tty read reply #include #include "decimal.h" int main(int argc,char **argv) { int rscale = numeric_global_rscale(); puts("nmain started.. division"); { Numeric a, b, r; Decimal_Exception ex; a = numeric_in("16.0",0,0,&ex); printf("a ex = %d\n",ex); b = numeric_in("0.6",0,0,&ex); printf("b ex = %d\n",ex); r = numeric_div(a,b,&rscale,&ex); printf("r ex = %d\n",ex); printf("'%s' / '%s' => '%s' (%s)\n", numeric_out(a), numeric_out(b), numeric_out(r), numeric_isnan(r) ? "NaN" : "OK"); free(a); free(b); free(r); } puts("sqrt.."); { Numeric a, r; Decimal_Exception ex; a = numeric_in("16.374239828239472974978290E09",0,0,&ex); printf("a ex = %d\n",ex); r = numeric_sqrt(a,&rscale,&ex); printf("r ex = %d\n",ex); printf("'%s' sqrt => '%s' (%s)\n", numeric_out(a), numeric_out(r), numeric_isnan(r) ? "NaN" : "OK"); free(a); free(r); } puts("nmain ended."); return 0; } /* End $Source: /cvsroot/apq/apq/nmain.c,v $ */ apq-3.2.0/legacy/notices.c000066400000000000000000000030401171626402600153530ustar00rootroot00000000000000/* $Id: notices.c,v 1.4 2002/08/04 23:34:07 wwg Exp $ * Copyright (C) 2002, Warren W. Gay VE3WWG * * Licensed under the ACL (Ada Community License) * or * GNU Public License 2 (GPL2) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include /* * Connection_Notify is an Ada procedure using C calling convention : */ extern void Connection_Notify(void *arg,const char *message); /* * A do-nothing notices callback : */ static void notices_dud(void *arg,const char *message) { return; } /* * Install a new notices callback : */ void notice_install(PGconn *conn,void *ada_obj_ptr) { PQsetNoticeProcessor(conn,Connection_Notify,ada_obj_ptr); } /* * Disable callbacks to the Connection_Notify Ada procedure : */ void notice_uninstall(PGconn *conn) { PQsetNoticeProcessor(conn,notices_dud,NULL); } /* End $Source: /cvsroot/apq/apq/notices.c,v $ */ apq-3.2.0/legacy/numeric.c000066400000000000000000001765171171626402600153750ustar00rootroot00000000000000/* Borrowed from postgresql-7.2.1 sources : * $Id: numeric.c,v 1.5 2002/08/03 03:27:33 wwg Exp $ * * See PG_COPYRIGHT file. * ---------- * numeric.c * * An exact numeric data type for the Postgres database system * * 1998 Jan Wieck * * $Header: /cvsroot/apq/apq/numeric.c,v 1.5 2002/08/03 03:27:33 wwg Exp $ * * ---------- */ #include #include #include #include #include #include #include #include #include #include #include "decimal.h" /* ---------- * Uncomment the following to enable compilation of dump_numeric() * and dump_var() and to get a dump of any result produced by make_result(). * ---------- #define NUMERIC_DEBUG */ /* ---------- * Local definitions * ---------- */ #ifndef MIN #define MIN(a,b) (((a)<(b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b)) ? (a) : (b)) #endif #ifndef NAN #define NAN (0.0/0.0) #endif #define nan_var(v) free_var(v) /* ---------- * Local data types * * Note: the first digit of a NumericVar's value is assumed to be multiplied * by 10 ** weight. Another way to say it is that there are weight+1 digits * before the decimal point. It is possible to have weight < 0. * * The value represented by a NumericVar is determined by the sign, weight, * ndigits, and digits[] array. The rscale and dscale are carried along, * but they are just auxiliary information until rounding is done before * final storage or display. (Scales are the number of digits wanted * *after* the decimal point. Scales are always >= 0.) * * buf points at the physical start of the palloc'd digit buffer for the * NumericVar. digits points at the first digit in actual use (the one * with the specified weight). We normally leave an unused byte or two * (preset to zeroes) between buf and digits, so that there is room to store * a carry out of the top digit without special pushups. We just need to * decrement digits (and increment weight) to make room for the carry digit. * * If buf is NULL then the digit buffer isn't actually palloc'd and should * not be freed --- see the constants below for an example. * * NB: All the variable-level functions are written in a style that makes it * possible to give one and the same variable as argument and destination. * This is feasible because the digit buffer is separate from the variable. * ---------- */ typedef unsigned char NumericDigit; typedef struct NumericVar { int ndigits; /* number of digits in digits[] - can be * 0! */ int weight; /* weight of first digit */ int rscale; /* result scale */ int dscale; /* display scale */ int sign; /* NUMERIC_POS, NUMERIC_NEG, or * NUMERIC_NAN */ NumericDigit *buf; /* start of palloc'd space for digits[] */ NumericDigit *digits; /* decimal digits */ } NumericVar; /* ---------- * Some preinitialized variables we need often * ---------- */ static NumericDigit const_zero_data[1] = {0}; static NumericVar const_zero = {0, 0, 0, 0, NUMERIC_POS, NULL, const_zero_data}; static NumericDigit const_one_data[1] = {1}; static NumericVar const_one = {1, 0, 0, 0, NUMERIC_POS, NULL, const_one_data}; static NumericDigit const_two_data[1] = {2}; static NumericVar const_two = {1, 0, 0, 0, NUMERIC_POS, NULL, const_two_data}; static NumericVar const_nan = {0, 0, 0, 0, NUMERIC_NAN, NULL, NULL}; /* ---------- * Local functions * ---------- */ #ifdef NUMERIC_DEBUG static void dump_numeric(char *str, Numeric num); static void dump_var(char *str, NumericVar *var); #else #define dump_numeric(s,n) #define dump_var(s,v) #endif #define digitbuf_alloc(size) ((NumericDigit *) palloc(size)) #define digitbuf_free(buf) \ do { \ if ((buf) != NULL) \ pfree(buf); \ } while (0) #define init_var(v) memset(v,0,sizeof(NumericVar)) static void alloc_var(NumericVar *var, int ndigits); static void free_var(NumericVar *var); static void zero_var(NumericVar *var); static void set_var_from_str(const char *str, NumericVar *dest, Decimal_Exception *ex); static void set_var_from_num(Numeric value, NumericVar *dest); static void set_var_from_var(NumericVar *value, NumericVar *dest); static char *get_str_from_var(NumericVar *var, int dscale); static Numeric make_result(NumericVar *var); static void apply_typmod(NumericVar *var, int precision, int scale, Decimal_Exception *ex); static int cmp_numerics(Numeric num1, Numeric num2); static int cmp_var(NumericVar *var1, NumericVar *var2); static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result); static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result); static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale); static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static int select_div_scale(NumericVar *var1, NumericVar *var2, int *global_rscale); static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static void ceil_var(NumericVar *var, NumericVar *result); static void floor_var(NumericVar *var, NumericVar *result); static void sqrt_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static void exp_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static void ln_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static void log_var(NumericVar *base, NumericVar *num, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result, int *global_rscale, Decimal_Exception *ex); static int cmp_abs(NumericVar *var1, NumericVar *var2); static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result); static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result); /* * Provide an initialization value for global_rscale : */ int numeric_global_rscale(void) { return NUMERIC_MIN_RESULT_SCALE; } /* ---------------------------------------------------------------------- * * Input-, output- and rounding-functions * * ---------------------------------------------------------------------- * numeric_in() - * * Input function for numeric data type : * NOTES: * When precision is zero, the precision and scale arguments are * ignored. Otherwise the converted value is made to fit the * parameters supplied, else Numeric_Overflow exception. * ---------- */ Numeric numeric_in(const char *str, int precision, int scale, Decimal_Exception *ex) { NumericVar value; Numeric res; *ex = No_Error; /* * Check for NaN */ if (strcmp(str, "NaN") == 0) return make_result(&const_nan); /* * Use set_var_from_str() to parse the input string and return it in * the packed DB storage format */ init_var(&value); set_var_from_str(str, &value, ex); if ( *ex != No_Error ) { res = make_result(&const_nan); } else { if ( precision != 0 ) apply_typmod(&value, precision, scale, ex); res = make_result(&value); } free_var(&value); return res; } /* ---------- * numeric_out() - * * Output function for numeric data type * ---------- */ char * numeric_out(Numeric num) { NumericVar x; char *str; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return pstrdup("NaN"); /* * Get the number in the variable format. * * Even if we didn't need to change format, we'd still need to copy the * value to have a modifiable copy for rounding. set_var_from_num() * also guarantees there is extra digit space in case we produce a * carry out from rounding. */ init_var(&x); set_var_from_num(num, &x); str = get_str_from_var(&x, x.dscale); free_var(&x); return str; } /* * Return TRUE if the value is NaN : */ int numeric_isnan(Numeric num) { return NUMERIC_IS_NAN(num); } /* ---------- * numeric() - * * This is a special function called by the Postgres database system * before a value is stored in a tuples attribute. The precision and * scale of the attribute have to be applied on the value. * ---------- */ Numeric numeric(Numeric num, int precision, int scale, Decimal_Exception *ex) { Numeric new; int maxweight; NumericVar var; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); maxweight = precision - scale; /* * If the number is in bounds and due to the present result scale no * rounding could be necessary, just make a copy of the input and * modify its scale fields. */ if (num->n_weight < maxweight && scale >= num->n_rscale) { new = (Numeric) palloc(num->varlen); memcpy(new, num, num->varlen); new->n_rscale = scale; new->n_sign_dscale = NUMERIC_SIGN(new) | ((uint16) scale & NUMERIC_DSCALE_MASK); return new; } /* * We really need to fiddle with things - unpack the number into a * variable and let apply_typmod() do it. */ init_var(&var); set_var_from_num(num, &var); apply_typmod(&var, precision, scale, ex); new = make_result(&var); free_var(&var); return new; } /* * Release the storage occupied by this Numeric : * (designed to be called by Ada95) */ void numeric_free(Numeric num) { free(num); } /* ---------------------------------------------------------------------- * * Sign manipulation, rounding and the like * * ---------------------------------------------------------------------- */ Numeric numeric_abs(Numeric num) { Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Do it the easy way directly on the packed format */ res = (Numeric) palloc(num->varlen); memcpy(res, num, num->varlen); res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num); return res; } Numeric numeric_uminus(Numeric num) { Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Do it the easy way directly on the packed format */ res = (Numeric) palloc(num->varlen); memcpy(res, num, num->varlen); /* * The packed format is known to be totally zero digit trimmed always. * So we can identify a ZERO by the fact that there are no digits at * all. Do nothing to a zero. */ if (num->varlen != NUMERIC_HDRSZ) { /* Else, flip the sign */ if (NUMERIC_SIGN(num) == NUMERIC_POS) res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num); else res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num); } return res; } /* * This effectively just copies the value : */ Numeric numeric_uplus(Numeric num) { Numeric res; res = (Numeric) palloc(num->varlen); memcpy(res, num, num->varlen); return res; } /* * Return the sign of the value : */ Numeric numeric_sign(Numeric num) { Numeric res; NumericVar result; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); init_var(&result); /* * The packed format is known to be totally zero digit trimmed always. * So we can identify a ZERO by the fact that there are no digits at * all. */ if (num->varlen == NUMERIC_HDRSZ) set_var_from_var(&const_zero, &result); else { /* * And if there are some, we return a copy of ONE with the sign of * our argument */ set_var_from_var(&const_one, &result); result.sign = NUMERIC_SIGN(num); } res = make_result(&result); free_var(&result); return res; } /* ---------- * numeric_round() - * * Round a value to have 'scale' digits after the decimal point. * We allow negative 'scale', implying rounding before the decimal * point --- Oracle interprets rounding that way. * ---------- */ Numeric numeric_round(Numeric num,int scale) { Numeric res; NumericVar arg; int i; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Limit the scale value to avoid possible overflow in calculations * below. */ scale = MIN(NUMERIC_MAX_RESULT_SCALE, MAX(-NUMERIC_MAX_RESULT_SCALE, scale)); /* * Unpack the argument and round it at the proper digit position */ init_var(&arg); set_var_from_num(num, &arg); i = arg.weight + scale + 1; if (i < arg.ndigits) { /* * If i = 0, the value loses all digits, but could round up if its * first digit is more than 4. If i < 0 the result must be 0. */ if (i < 0) arg.ndigits = 0; else { int carry = (arg.digits[i] > 4) ? 1 : 0; arg.ndigits = i; while (carry) { carry += arg.digits[--i]; arg.digits[i] = carry % 10; carry /= 10; } if (i < 0) { Assert(i == -1); /* better not have added more than 1 digit */ Assert(arg.digits > arg.buf); arg.digits--; arg.ndigits++; arg.weight++; } } } /* * Set result's scale to something reasonable. */ scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale)); arg.rscale = scale; arg.dscale = scale; /* * Return the rounded result */ res = make_result(&arg); free_var(&arg); return res; } /* ---------- * numeric_trunc() - * * Truncate a value to have 'scale' digits after the decimal point. * We allow negative 'scale', implying a truncation before the decimal * point --- Oracle interprets truncation that way. * ---------- */ Numeric numeric_trunc(Numeric num,int scale) { Numeric res; NumericVar arg; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Limit the scale value to avoid possible overflow in calculations * below. */ scale = MIN(NUMERIC_MAX_RESULT_SCALE, MAX(-NUMERIC_MAX_RESULT_SCALE, scale)); /* * Unpack the argument and truncate it at the proper digit position */ init_var(&arg); set_var_from_num(num, &arg); arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1)); /* * Set result's scale to something reasonable. */ scale = MIN(NUMERIC_MAX_DISPLAY_SCALE, MAX(0, scale)); arg.rscale = scale; arg.dscale = scale; /* * Return the truncated result */ res = make_result(&arg); free_var(&arg); return res; } /* ---------- * numeric_ceil() - * * Return the smallest integer greater than or equal to the argument * ---------- */ Numeric numeric_ceil(Numeric num) { Numeric res; NumericVar result; if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); init_var(&result); set_var_from_num(num, &result); ceil_var(&result, &result); result.dscale = 0; res = make_result(&result); free_var(&result); return res; } /* ---------- * numeric_floor() - * * Return the largest integer equal to or less than the argument * ---------- */ Numeric numeric_floor(Numeric num) { Numeric res; NumericVar result; if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); init_var(&result); set_var_from_num(num, &result); floor_var(&result, &result); result.dscale = 0; res = make_result(&result); free_var(&result); return res; } /* ---------------------------------------------------------------------- * * Comparison functions * * Note: btree indexes need these routines not to leak memory; therefore, * be careful to free working copies of toasted datums. Most places don't * need to be so careful. * ---------------------------------------------------------------------- */ int numeric_cmp(Numeric num1, Numeric num2) { Numeric orig1 = num1, orig2 = num2; int result; result = cmp_numerics(num1, num2); if ( num1 != orig1 ) free(num1); if ( num2 != orig2 ) free(num2); return result; } int numeric_eq(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) == 0; } int numeric_ne(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) != 0; } int numeric_gt(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) > 0; } int numeric_ge(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) >= 0; } int numeric_lt(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) < 0; } int numeric_le(Numeric num1, Numeric num2) { return numeric_cmp(num1,num2) <= 0; } static int cmp_numerics(Numeric num1, Numeric num2) { int result; /* * We consider all NANs to be equal and larger than any non-NAN. This * is somewhat arbitrary; the important thing is to have a consistent * sort order. */ if (NUMERIC_IS_NAN(num1)) { if (NUMERIC_IS_NAN(num2)) result = 0; /* NAN = NAN */ else result = 1; /* NAN > non-NAN */ } else if (NUMERIC_IS_NAN(num2)) { result = -1; /* non-NAN < NAN */ } else { NumericVar arg1; NumericVar arg2; init_var(&arg1); init_var(&arg2); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); result = cmp_var(&arg1, &arg2); free_var(&arg1); free_var(&arg2); } return result; } /* ---------------------------------------------------------------------- * * Arithmetic base functions * * ---------------------------------------------------------------------- * numeric_add() - * * Add two numerics * ---------- */ Numeric numeric_add(Numeric num1, Numeric num2) { NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the values, let add_var() compute the result and return it. * The internals of add_var() will automatically set the correct * result and display scales in the result. */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); add_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); return res; } /* ---------- * numeric_sub() - * * Subtract one numeric from another * ---------- */ Numeric numeric_sub(Numeric num1, Numeric num2) { NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the two arguments, let sub_var() compute the result and * return it. */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); sub_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); return res; } /* ---------- * numeric_mul() - * * Calculate the product of two numerics * ---------- */ Numeric numeric_mul(Numeric num1, Numeric num2, int *global_rscale) { NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the arguments, let mul_var() compute the result and return * it. Unlike add_var() and sub_var(), mul_var() will round the result * to the scale stored in global_rscale. In the case of numeric_mul(), * which is invoked for the * operator on numerics, we set it to the * exact representation for the product (rscale = sum(rscale of arg1, * rscale of arg2) and the same for the dscale). */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); *global_rscale = arg1.rscale + arg2.rscale; mul_var(&arg1, &arg2, &result, global_rscale); result.dscale = arg1.dscale + arg2.dscale; res = make_result(&result); free_var(&arg1); free_var(&arg2); free_var(&result); return res; } /* ---------- * numeric_div() - * * Divide one numeric into another * ---------- */ Numeric numeric_div(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) { NumericVar arg1; NumericVar arg2; NumericVar result; Numeric res; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the arguments */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); res_dscale = select_div_scale(&arg1, &arg2, global_rscale); /* * Do the divide, set the display scale and return the result */ div_var(&arg1, &arg2, &result, global_rscale, ex); if ( *ex != No_Error ) { res = make_result(&const_nan); } else { result.dscale = res_dscale; res = make_result(&result); } free_var(&arg1); free_var(&arg2); free_var(&result); return res; } /* ---------- * numeric_mod() - * * Calculate the modulo of two numerics * ---------- */ Numeric numeric_mod(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; *ex = No_Error; if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); mod_var(&arg1, &arg2, &result, global_rscale, ex); res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); return res; } /* ---------- * numeric_smaller() - * * Return the smaller of two numbers * ---------- */ Numeric numeric_smaller(Numeric num1, Numeric num2) { NumericVar arg1; NumericVar arg2; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the values, and decide which is the smaller one */ init_var(&arg1); init_var(&arg2); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); if (cmp_var(&arg1, &arg2) <= 0) res = make_result(&arg1); else res = make_result(&arg2); free_var(&arg1); free_var(&arg2); return res; } /* ---------- * numeric_larger() - * * Return the larger of two numbers * ---------- */ Numeric numeric_larger(Numeric num1, Numeric num2) { NumericVar arg1; NumericVar arg2; Numeric res; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Unpack the values, and decide which is the larger one */ init_var(&arg1); init_var(&arg2); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); if (cmp_var(&arg1, &arg2) >= 0) res = make_result(&arg1); else res = make_result(&arg2); free_var(&arg1); free_var(&arg2); return res; } /* ---------------------------------------------------------------------- * * Complex math functions * * ---------------------------------------------------------------------- * numeric_sqrt() - * * Compute the square root of a numeric. * ---------- */ Numeric numeric_sqrt(Numeric num, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg; NumericVar result; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Unpack the argument, determine the scales like for divide, let * sqrt_var() do the calculation and return the result. */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE); *global_rscale = MAX(*global_rscale, res_dscale + 4); *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE); sqrt_var(&arg, &result, global_rscale, ex); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg); return res; } /* ---------- * numeric_exp() - * * Raise e to the power of x * ---------- */ Numeric numeric_exp(Numeric num, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg; NumericVar result; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Same procedure like for sqrt(). */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE); *global_rscale = MAX(*global_rscale, res_dscale + 4); *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE); exp_var(&arg, &result, global_rscale, ex); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg); return res; } /* ---------- * numeric_ln() - * * Compute the natural logarithm of x * ---------- */ Numeric numeric_ln(Numeric num, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg; NumericVar result; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* * Same procedure like for sqrt() */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); *global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE); *global_rscale = MAX(*global_rscale, res_dscale + 4); *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE); ln_var(&arg, &result, global_rscale, ex); if ( *ex == No_Error ) result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg); return res; } /* ---------- * numeric_log() - * * Compute the logarithm of x in a given base * ---------- */ Numeric numeric_log(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Initialize things and calculate scales */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); *global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE); *global_rscale = MAX(*global_rscale, res_dscale + 4); *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE); /* * Call log_var() to compute and return the result */ log_var(&arg1, &arg2, &result, global_rscale, ex); if ( *ex == No_Error ) result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); return res; } /* ---------- * numeric_power() - * * Raise m to the power of x * ---------- */ Numeric numeric_power(Numeric num1, Numeric num2, int *global_rscale, Decimal_Exception *ex) { Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; int res_dscale; *ex = No_Error; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* * Initialize things and calculate scales */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); *global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE); *global_rscale = MAX(*global_rscale, res_dscale + 4); *global_rscale = MIN(*global_rscale, NUMERIC_MAX_RESULT_SCALE); /* * Call log_var() to compute and return the result */ power_var(&arg1, &arg2, &result, global_rscale, ex); if ( *ex == No_Error ) result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); return res; } /* ---------------------------------------------------------------------- * * Local functions follow * * ---------------------------------------------------------------------- */ #ifdef NUMERIC_DEBUG /* ---------- * dump_numeric() - Dump a value in the db storage format for debugging * ---------- */ static void dump_numeric(char *str, Numeric num) { int i; printf("%s: NUMERIC w=%d r=%d d=%d ", str, num->n_weight, num->n_rscale, NUMERIC_DSCALE(num)); switch (NUMERIC_SIGN(num)) { case NUMERIC_POS: printf("POS"); break; case NUMERIC_NEG: printf("NEG"); break; case NUMERIC_NAN: printf("NaN"); break; default: printf("SIGN=0x%x", NUMERIC_SIGN(num)); break; } for (i = 0; i < num->varlen - NUMERIC_HDRSZ; i++) printf(" %d %d", (num->n_data[i] >> 4) & 0x0f, num->n_data[i] & 0x0f); printf("\n"); } /* ---------- * dump_var() - Dump a value in the variable format for debugging * ---------- */ static void dump_var(char *str, NumericVar *var) { int i; printf("%s: VAR w=%d r=%d d=%d ", str, var->weight, var->rscale, var->dscale); switch (var->sign) { case NUMERIC_POS: printf("POS"); break; case NUMERIC_NEG: printf("NEG"); break; case NUMERIC_NAN: printf("NaN"); break; default: printf("SIGN=0x%x", var->sign); break; } for (i = 0; i < var->ndigits; i++) printf(" %d", var->digits[i]); printf("\n"); } #endif /* NUMERIC_DEBUG */ /* ---------- * alloc_var() - * * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding) * ---------- */ static void alloc_var(NumericVar *var, int ndigits) { digitbuf_free(var->buf); var->buf = digitbuf_alloc(ndigits + 1); var->buf[0] = 0; var->digits = var->buf + 1; var->ndigits = ndigits; } /* ---------- * free_var() - * * Return the digit buffer of a variable to the free pool * ---------- */ static void free_var(NumericVar *var) { digitbuf_free(var->buf); var->buf = NULL; var->digits = NULL; var->sign = NUMERIC_NAN; } /* ---------- * zero_var() - * * Set a variable to ZERO. * Note: rscale and dscale are not touched. * ---------- */ static void zero_var(NumericVar *var) { digitbuf_free(var->buf); var->buf = NULL; var->digits = NULL; var->ndigits = 0; var->weight = 0; /* by convention; doesn't really matter */ var->sign = NUMERIC_POS; /* anything but NAN... */ } /* ---------- * set_var_from_str() * * Parse a string and put the number into a variable * ---------- */ static void set_var_from_str(const char *str, NumericVar *dest, Decimal_Exception *ex) { char *cp = (char *) str; bool have_dp = FALSE; int i = 0; bool bad_format = FALSE; while (*cp) { if (!isspace((unsigned char) *cp)) break; cp++; } alloc_var(dest, strlen(cp)); dest->weight = -1; dest->dscale = 0; dest->sign = NUMERIC_POS; switch (*cp) { case '+': dest->sign = NUMERIC_POS; cp++; break; case '-': dest->sign = NUMERIC_NEG; cp++; break; } if (*cp == '.') { have_dp = TRUE; cp++; } if (!isdigit((unsigned char) *cp)) bad_format = TRUE; /* Bad format exception */ while (*cp) { if (isdigit((unsigned char) *cp)) { dest->digits[i++] = *cp++ - '0'; if (!have_dp) dest->weight++; else dest->dscale++; } else if (*cp == '.') { if (have_dp) bad_format = TRUE; have_dp = TRUE; cp++; } else break; } dest->ndigits = i; /* Handle exponent, if any */ if (*cp == 'e' || *cp == 'E') { long exponent; char *endptr; cp++; exponent = strtol(cp, &endptr, 10); if (endptr == cp) bad_format = TRUE; cp = endptr; if (exponent > NUMERIC_MAX_PRECISION || exponent < -NUMERIC_MAX_PRECISION) bad_format = TRUE; dest->weight += (int) exponent; dest->dscale -= (int) exponent; if (dest->dscale < 0) dest->dscale = 0; } /* Should be nothing left but spaces */ while (*cp) { if (!isspace((unsigned char) *cp)) bad_format = TRUE; cp++; } /* Strip any leading zeroes */ while (dest->ndigits > 0 && *(dest->digits) == 0) { (dest->digits)++; (dest->weight)--; (dest->ndigits)--; } if (dest->ndigits == 0) dest->weight = 0; dest->rscale = dest->dscale; if ( bad_format ) *ex = Numeric_Format; /* Bad format exception */ } /* * set_var_from_num() - * * Parse back the packed db format into a variable * */ static void set_var_from_num(Numeric num, NumericVar *dest) { NumericDigit *digit; int i; int n; n = num->varlen - NUMERIC_HDRSZ; /* number of digit-pairs in packed * fmt */ alloc_var(dest, n * 2); dest->weight = num->n_weight; dest->rscale = num->n_rscale; dest->dscale = NUMERIC_DSCALE(num); dest->sign = NUMERIC_SIGN(num); digit = dest->digits; for (i = 0; i < n; i++) { unsigned char digitpair = num->n_data[i]; *digit++ = (digitpair >> 4) & 0x0f; *digit++ = digitpair & 0x0f; } } /* ---------- * set_var_from_var() - * * Copy one variable into another * ---------- */ static void set_var_from_var(NumericVar *value, NumericVar *dest) { NumericDigit *newbuf; newbuf = digitbuf_alloc(value->ndigits + 1); newbuf[0] = 0; /* spare digit for rounding */ memcpy(newbuf + 1, value->digits, value->ndigits); digitbuf_free(dest->buf); memcpy(dest, value, sizeof(NumericVar)); dest->buf = newbuf; dest->digits = newbuf + 1; } /* ---------- * get_str_from_var() - * * Convert a var to text representation (guts of numeric_out). * CAUTION: var's contents may be modified by rounding! * Caller must have checked for NaN case. * Returns a palloc'd string. * ---------- */ static char * get_str_from_var(NumericVar *var, int dscale) { char *str; char *cp; int i; int d; /* * Check if we must round up before printing the value and do so. */ i = dscale + var->weight + 1; if (i >= 0 && var->ndigits > i) { int carry = (var->digits[i] > 4) ? 1 : 0; var->ndigits = i; while (carry) { carry += var->digits[--i]; var->digits[i] = carry % 10; carry /= 10; } if (i < 0) { Assert(i == -1); /* better not have added more than 1 digit */ Assert(var->digits > var->buf); var->digits--; var->ndigits++; var->weight++; } } else var->ndigits = MAX(0, MIN(i, var->ndigits)); /* * Allocate space for the result */ str = palloc(MAX(0, dscale) + MAX(0, var->weight) + 4); cp = str; /* * Output a dash for negative values */ if (var->sign == NUMERIC_NEG) *cp++ = '-'; /* * Output all digits before the decimal point */ i = MAX(var->weight, 0); d = 0; while (i >= 0) { if (i <= var->weight && d < var->ndigits) *cp++ = var->digits[d++] + '0'; else *cp++ = '0'; i--; } /* * If requested, output a decimal point and all the digits that follow * it. */ if (dscale > 0) { *cp++ = '.'; while (i >= -dscale) { if (i <= var->weight && d < var->ndigits) *cp++ = var->digits[d++] + '0'; else *cp++ = '0'; i--; } } /* * terminate the string and return it */ *cp = '\0'; return str; } Numeric numeric_nan(void) { Numeric num = (Numeric) palloc(NUMERIC_HDRSZ); num->varlen = NUMERIC_HDRSZ; num->n_weight = 0; num->n_rscale = 0; num->n_sign_dscale = NUMERIC_NAN; return num; } /* ---------- * make_result() - * * Create the packed db numeric format in palloc()'d memory from * a variable. The var's rscale determines the number of digits kept. * ---------- */ static Numeric make_result(NumericVar *var) { Numeric result; NumericDigit *digit = var->digits; int weight = var->weight; int sign = var->sign; int n; int i, j; if (sign == NUMERIC_NAN) { return numeric_nan(); return result; } n = MAX(0, MIN(var->ndigits, var->weight + var->rscale + 1)); /* truncate leading zeroes */ while (n > 0 && *digit == 0) { digit++; weight--; n--; } /* truncate trailing zeroes */ while (n > 0 && digit[n - 1] == 0) n--; /* If zero result, force to weight=0 and positive sign */ if (n == 0) { weight = 0; sign = NUMERIC_POS; } result = (Numeric) palloc(NUMERIC_HDRSZ + (n + 1) / 2); result->varlen = NUMERIC_HDRSZ + (n + 1) / 2; result->n_weight = weight; result->n_rscale = var->rscale; result->n_sign_dscale = sign | ((uint16) var->dscale & NUMERIC_DSCALE_MASK); i = 0; j = 0; while (j < n) { unsigned char digitpair = digit[j++] << 4; if (j < n) digitpair |= digit[j++]; result->n_data[i++] = digitpair; } dump_numeric("make_result()", result); return result; } /* ---------- * apply_typmod() - * * Do bounds checking and rounding according to the attributes * typmod field. * ---------- */ static void apply_typmod(NumericVar *var, int precision, int scale, Decimal_Exception *ex) { int maxweight; int i; maxweight = precision - scale; /* Round to target scale */ i = scale + var->weight + 1; if (i >= 0 && var->ndigits > i) { int carry = (var->digits[i] > 4) ? 1 : 0; var->ndigits = i; while (carry) { carry += var->digits[--i]; var->digits[i] = carry % 10; carry /= 10; } if (i < 0) { Assert(i == -1); /* better not have added more than 1 digit */ Assert(var->digits > var->buf); var->digits--; var->ndigits++; var->weight++; } } else var->ndigits = MAX(0, MIN(i, var->ndigits)); /* * Check for overflow - note we can't do this before rounding, because * rounding could raise the weight. Also note that the var's weight * could be inflated by leading zeroes, which will be stripped before * storage but perhaps might not have been yet. In any case, we must * recognize a true zero, whose weight doesn't mean anything. */ if (var->weight >= maxweight) { /* Determine true weight; and check for all-zero result */ int tweight = var->weight; for (i = 0; i < var->ndigits; i++) { if (var->digits[i]) break; tweight--; } if ( tweight >= maxweight && i < var->ndigits ) *ex = Numeric_Overflow; /* Overflow exception */ } if ( *ex == No_Error ) { var->rscale = scale; var->dscale = scale; } else nan_var(var); } /* ---------- * cmp_var() - * * Compare two values on variable level * ---------- */ static int cmp_var(NumericVar *var1, NumericVar *var2) { if (var1->ndigits == 0) { if (var2->ndigits == 0) return 0; if (var2->sign == NUMERIC_NEG) return 1; return -1; } if (var2->ndigits == 0) { if (var1->sign == NUMERIC_POS) return 1; return -1; } if (var1->sign == NUMERIC_POS) { if (var2->sign == NUMERIC_NEG) return 1; return cmp_abs(var1, var2); } if (var2->sign == NUMERIC_POS) return -1; return cmp_abs(var2, var1); } /* ---------- * add_var() - * * Full version of add functionality on variable level (handling signs). * result might point to one of the operands too without danger. * ---------- */ static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result) { /* * Decide on the signs of the two variables what to do */ if (var1->sign == NUMERIC_POS) { if (var2->sign == NUMERIC_POS) { /* * Both are positive result = +(ABS(var1) + ABS(var2)) */ add_abs(var1, var2, result); result->sign = NUMERIC_POS; } else { /* * var1 is positive, var2 is negative Must compare absolute * values */ switch (cmp_abs(var1, var2)) { case 0: /* ---------- * ABS(var1) == ABS(var2) * result = ZERO * ---------- */ zero_var(result); result->rscale = MAX(var1->rscale, var2->rscale); result->dscale = MAX(var1->dscale, var2->dscale); break; case 1: /* ---------- * ABS(var1) > ABS(var2) * result = +(ABS(var1) - ABS(var2)) * ---------- */ sub_abs(var1, var2, result); result->sign = NUMERIC_POS; break; case -1: /* ---------- * ABS(var1) < ABS(var2) * result = -(ABS(var2) - ABS(var1)) * ---------- */ sub_abs(var2, var1, result); result->sign = NUMERIC_NEG; break; } } } else { if (var2->sign == NUMERIC_POS) { /* ---------- * var1 is negative, var2 is positive * Must compare absolute values * ---------- */ switch (cmp_abs(var1, var2)) { case 0: /* ---------- * ABS(var1) == ABS(var2) * result = ZERO * ---------- */ zero_var(result); result->rscale = MAX(var1->rscale, var2->rscale); result->dscale = MAX(var1->dscale, var2->dscale); break; case 1: /* ---------- * ABS(var1) > ABS(var2) * result = -(ABS(var1) - ABS(var2)) * ---------- */ sub_abs(var1, var2, result); result->sign = NUMERIC_NEG; break; case -1: /* ---------- * ABS(var1) < ABS(var2) * result = +(ABS(var2) - ABS(var1)) * ---------- */ sub_abs(var2, var1, result); result->sign = NUMERIC_POS; break; } } else { /* ---------- * Both are negative * result = -(ABS(var1) + ABS(var2)) * ---------- */ add_abs(var1, var2, result); result->sign = NUMERIC_NEG; } } } /* ---------- * sub_var() - * * Full version of sub functionality on variable level (handling signs). * result might point to one of the operands too without danger. * ---------- */ static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result) { /* * Decide on the signs of the two variables what to do */ if (var1->sign == NUMERIC_POS) { if (var2->sign == NUMERIC_NEG) { /* ---------- * var1 is positive, var2 is negative * result = +(ABS(var1) + ABS(var2)) * ---------- */ add_abs(var1, var2, result); result->sign = NUMERIC_POS; } else { /* ---------- * Both are positive * Must compare absolute values * ---------- */ switch (cmp_abs(var1, var2)) { case 0: /* ---------- * ABS(var1) == ABS(var2) * result = ZERO * ---------- */ zero_var(result); result->rscale = MAX(var1->rscale, var2->rscale); result->dscale = MAX(var1->dscale, var2->dscale); break; case 1: /* ---------- * ABS(var1) > ABS(var2) * result = +(ABS(var1) - ABS(var2)) * ---------- */ sub_abs(var1, var2, result); result->sign = NUMERIC_POS; break; case -1: /* ---------- * ABS(var1) < ABS(var2) * result = -(ABS(var2) - ABS(var1)) * ---------- */ sub_abs(var2, var1, result); result->sign = NUMERIC_NEG; break; } } } else { if (var2->sign == NUMERIC_NEG) { /* ---------- * Both are negative * Must compare absolute values * ---------- */ switch (cmp_abs(var1, var2)) { case 0: /* ---------- * ABS(var1) == ABS(var2) * result = ZERO * ---------- */ zero_var(result); result->rscale = MAX(var1->rscale, var2->rscale); result->dscale = MAX(var1->dscale, var2->dscale); break; case 1: /* ---------- * ABS(var1) > ABS(var2) * result = -(ABS(var1) - ABS(var2)) * ---------- */ sub_abs(var1, var2, result); result->sign = NUMERIC_NEG; break; case -1: /* ---------- * ABS(var1) < ABS(var2) * result = +(ABS(var2) - ABS(var1)) * ---------- */ sub_abs(var2, var1, result); result->sign = NUMERIC_POS; break; } } else { /* ---------- * var1 is negative, var2 is positive * result = -(ABS(var1) + ABS(var2)) * ---------- */ add_abs(var1, var2, result); result->sign = NUMERIC_NEG; } } } /* ---------- * mul_var() - * * Multiplication on variable level. Product of var1 * var2 is stored * in result. * ---------- */ static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale) { NumericDigit *res_buf; NumericDigit *res_digits; int res_ndigits; int res_weight; int res_sign; int i, ri, i1, i2; long sum = 0; res_weight = var1->weight + var2->weight + 2; res_ndigits = var1->ndigits + var2->ndigits + 1; if (var1->sign == var2->sign) res_sign = NUMERIC_POS; else res_sign = NUMERIC_NEG; res_buf = digitbuf_alloc(res_ndigits); res_digits = res_buf; memset(res_digits, 0, res_ndigits); ri = res_ndigits; for (i1 = var1->ndigits - 1; i1 >= 0; i1--) { sum = 0; i = --ri; for (i2 = var2->ndigits - 1; i2 >= 0; i2--) { sum += res_digits[i] + var1->digits[i1] * var2->digits[i2]; res_digits[i--] = sum % 10; sum /= 10; } res_digits[i] = sum; } i = res_weight + *global_rscale + 2; if (i >= 0 && i < res_ndigits) { sum = (res_digits[i] > 4) ? 1 : 0; res_ndigits = i; i--; while (sum) { sum += res_digits[i]; res_digits[i--] = sum % 10; sum /= 10; } } while (res_ndigits > 0 && *res_digits == 0) { res_digits++; res_weight--; res_ndigits--; } while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0) res_ndigits--; if (res_ndigits == 0) { res_sign = NUMERIC_POS; res_weight = 0; } digitbuf_free(result->buf); result->buf = res_buf; result->digits = res_digits; result->ndigits = res_ndigits; result->weight = res_weight; result->rscale = *global_rscale; result->sign = res_sign; } /* ---------- * div_var() - * * Division on variable level. * ---------- */ static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericDigit *res_digits; int res_ndigits; int res_sign; int res_weight; NumericVar dividend; NumericVar divisor[10]; int ndigits_tmp; int weight_tmp; int rscale_tmp; int ri; int i; long guess; long first_have; long first_div; int first_nextdigit; int stat = 0; /* * First of all division by zero check */ ndigits_tmp = var2->ndigits + 1; if (ndigits_tmp == 1) { *ex = Divide_By_Zero; nan_var(result); return; } /* * Determine the result sign, weight and number of digits to calculate */ if (var1->sign == var2->sign) res_sign = NUMERIC_POS; else res_sign = NUMERIC_NEG; res_weight = var1->weight - var2->weight + 1; res_ndigits = *global_rscale + res_weight; if (res_ndigits <= 0) res_ndigits = 1; /* * Now result zero check */ if (var1->ndigits == 0) { zero_var(result); result->rscale = *global_rscale; return; } /* * Initialize local variables */ init_var(÷nd); for (i = 1; i < 10; i++) init_var(&divisor[i]); /* * Make a copy of the divisor which has one leading zero digit */ divisor[1].ndigits = ndigits_tmp; divisor[1].rscale = var2->ndigits; divisor[1].sign = NUMERIC_POS; divisor[1].buf = digitbuf_alloc(ndigits_tmp); divisor[1].digits = divisor[1].buf; divisor[1].digits[0] = 0; memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1); /* * Make a copy of the dividend */ dividend.ndigits = var1->ndigits; dividend.weight = 0; dividend.rscale = var1->ndigits; dividend.sign = NUMERIC_POS; dividend.buf = digitbuf_alloc(var1->ndigits); dividend.digits = dividend.buf; memcpy(dividend.digits, var1->digits, var1->ndigits); /* * Setup the result */ digitbuf_free(result->buf); result->buf = digitbuf_alloc(res_ndigits + 2); res_digits = result->buf; result->digits = res_digits; result->ndigits = res_ndigits; result->weight = res_weight; result->rscale = *global_rscale; result->sign = res_sign; res_digits[0] = 0; first_div = divisor[1].digits[1] * 10; if (ndigits_tmp > 2) first_div += divisor[1].digits[2]; first_have = 0; first_nextdigit = 0; weight_tmp = 1; rscale_tmp = divisor[1].rscale; for (ri = 0; ri <= res_ndigits; ri++) { first_have = first_have * 10; if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits) first_have += dividend.digits[first_nextdigit]; first_nextdigit++; guess = (first_have * 10) / first_div + 1; if (guess > 9) guess = 9; while (guess > 0) { if (divisor[guess].buf == NULL) { int i; long sum = 0; memcpy(&divisor[guess], &divisor[1], sizeof(NumericVar)); divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits); divisor[guess].digits = divisor[guess].buf; for (i = divisor[1].ndigits - 1; i >= 0; i--) { sum += divisor[1].digits[i] * guess; divisor[guess].digits[i] = sum % 10; sum /= 10; } } divisor[guess].weight = weight_tmp; divisor[guess].rscale = rscale_tmp; stat = cmp_abs(÷nd, &divisor[guess]); if (stat >= 0) break; guess--; } res_digits[ri + 1] = guess; if (stat == 0) { ri++; break; } weight_tmp--; rscale_tmp++; if (guess == 0) continue; sub_abs(÷nd, &divisor[guess], ÷nd); first_nextdigit = dividend.weight - weight_tmp; first_have = 0; if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits) first_have = dividend.digits[first_nextdigit]; first_nextdigit++; } result->ndigits = ri + 1; if (ri == res_ndigits + 1) { int carry = (res_digits[ri] > 4) ? 1 : 0; result->ndigits = ri; res_digits[ri] = 0; while (carry && ri > 0) { carry += res_digits[--ri]; res_digits[ri] = carry % 10; carry /= 10; } } while (result->ndigits > 0 && *(result->digits) == 0) { (result->digits)++; (result->weight)--; (result->ndigits)--; } while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0) (result->ndigits)--; if (result->ndigits == 0) result->sign = NUMERIC_POS; /* * Tidy up */ digitbuf_free(dividend.buf); for (i = 1; i < 10; i++) digitbuf_free(divisor[i].buf); } /* * Default scale selection for division * * Returns the appropriate display scale for the division result, * and sets global_rscale to the result scale to use during div_var. * * Note that this must be called before div_var. */ static int select_div_scale(NumericVar *var1, NumericVar *var2, int *global_rscale) { int res_dscale; int res_rscale; /* ---------- * The result scale of a division isn't specified in any * SQL standard. For Postgres it is the following (where * SR, DR are the result- and display-scales of the returned * value, S1, D1, S2 and D2 are the scales of the two arguments, * The minimum and maximum scales are compile time options from * numeric.h): * * DR = MIN(MAX(D1 + D2, MIN_DISPLAY_SCALE), MAX_DISPLAY_SCALE) * SR = MIN(MAX(MAX(S1 + S2, DR + 4), MIN_RESULT_SCALE), MAX_RESULT_SCALE) * * By default, any result is computed with a minimum of 34 digits * after the decimal point or at least with 4 digits more than * displayed. * ---------- */ res_dscale = var1->dscale + var2->dscale; res_dscale = MAX(res_dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); res_rscale = var1->rscale + var2->rscale; res_rscale = MAX(res_rscale, res_dscale + 4); res_rscale = MAX(res_rscale, NUMERIC_MIN_RESULT_SCALE); res_rscale = MIN(res_rscale, NUMERIC_MAX_RESULT_SCALE); *global_rscale = res_rscale; return res_dscale; } /* ---------- * mod_var() - * * Calculate the modulo of two numerics at variable level * ---------- */ static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericVar tmp; int save_global_rscale; int div_dscale; *ex = No_Error; init_var(&tmp); /* --------- * We do this using the equation * mod(x,y) = x - trunc(x/y)*y * We set global_rscale the same way numeric_div and numeric_mul do * to get the right answer from the equation. The final result, * however, need not be displayed to more precision than the inputs. * ---------- */ save_global_rscale = *global_rscale; div_dscale = select_div_scale(var1, var2, global_rscale); div_var(var1, var2, &tmp, global_rscale, ex); if ( *ex == No_Error ) { tmp.dscale = div_dscale; /* do trunc() by forgetting digits to the right of the decimal point */ tmp.ndigits = MAX(0, MIN(tmp.ndigits, tmp.weight + 1)); *global_rscale = var2->rscale + tmp.rscale; mul_var(var2, &tmp, &tmp, global_rscale); sub_var(var1, &tmp, result); result->dscale = MAX(var1->dscale, var2->dscale); *global_rscale = save_global_rscale; } free_var(&tmp); } /* ---------- * ceil_var() - * * Return the smallest integer greater than or equal to the argument * on variable level * ---------- */ static void ceil_var(NumericVar *var, NumericVar *result) { NumericVar tmp; init_var(&tmp); set_var_from_var(var, &tmp); tmp.rscale = 0; tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1)); if (tmp.sign == NUMERIC_POS && cmp_var(var, &tmp) != 0) add_var(&tmp, &const_one, &tmp); set_var_from_var(&tmp, result); free_var(&tmp); } /* ---------- * floor_var() - * * Return the largest integer equal to or less than the argument * on variable level * ---------- */ static void floor_var(NumericVar *var, NumericVar *result) { NumericVar tmp; init_var(&tmp); set_var_from_var(var, &tmp); tmp.rscale = 0; tmp.ndigits = MIN(tmp.ndigits, MAX(0, tmp.weight + 1)); if (tmp.sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0) sub_var(&tmp, &const_one, &tmp); set_var_from_var(&tmp, result); free_var(&tmp); } /* ---------- * sqrt_var() - * * Compute the square root of x using Newtons algorithm * ---------- */ static void sqrt_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericVar tmp_arg; NumericVar tmp_val; NumericVar last_val; int res_rscale; int save_global_rscale; int stat; save_global_rscale = *global_rscale; *global_rscale += 8; res_rscale = *global_rscale; stat = cmp_var(arg, &const_zero); if (stat == 0) { set_var_from_var(&const_zero, result); result->rscale = res_rscale; result->sign = NUMERIC_POS; return; } if (stat < 0) { *ex = Undefined_Result; nan_var(result); return; } init_var(&tmp_arg); init_var(&tmp_val); init_var(&last_val); set_var_from_var(arg, &tmp_arg); set_var_from_var(result, &last_val); /* * Initialize the result to the first guess */ digitbuf_free(result->buf); result->buf = digitbuf_alloc(1); result->digits = result->buf; result->digits[0] = tmp_arg.digits[0] / 2; if (result->digits[0] == 0) result->digits[0] = 1; result->ndigits = 1; result->weight = tmp_arg.weight / 2; result->rscale = res_rscale; result->sign = NUMERIC_POS; for (;;) { div_var(&tmp_arg, result, &tmp_val, global_rscale, ex); if ( *ex != No_Error ) break; add_var(result, &tmp_val, result); div_var(result, &const_two, result, global_rscale, ex); if ( *ex != No_Error ) break; if (cmp_var(&last_val, result) == 0) break; set_var_from_var(result, &last_val); } free_var(&last_val); free_var(&tmp_val); free_var(&tmp_arg); if ( *ex == No_Error ) { *global_rscale = save_global_rscale; div_var(result, &const_one, result, global_rscale, ex); } if ( *ex != No_Error ) nan_var(result); /* Set NAN if any exception occurred */ } /* ---------- * exp_var() - * * Raise e to the power of x * ---------- */ static void exp_var(NumericVar *arg, NumericVar *result,int *global_rscale, Decimal_Exception *ex) { NumericVar x; NumericVar xpow; NumericVar ifac; NumericVar elem; NumericVar ni; int d; int i; int ndiv2 = 0; bool xneg = FALSE; int save_global_rscale; init_var(&x); init_var(&xpow); init_var(&ifac); init_var(&elem); init_var(&ni); set_var_from_var(arg, &x); if (x.sign == NUMERIC_NEG) { xneg = TRUE; x.sign = NUMERIC_POS; } save_global_rscale = *global_rscale; *global_rscale = 0; for (i = x.weight, d = 0; i >= 0; i--, d++) { *global_rscale *= 10; if (d < x.ndigits) *global_rscale += x.digits[d]; if (*global_rscale >= 1000) { *ex = Numeric_Overflow; /* argument for EXP() too big */ nan_var(result); return; } } *global_rscale = *global_rscale / 2 + save_global_rscale + 8; while (cmp_var(&x, &const_one) > 0) { ndiv2++; (*global_rscale)++; div_var(&x, &const_two, &x, global_rscale, ex); if ( *ex != No_Error ) break; } if ( *ex == No_Error ) { add_var(&const_one, &x, result); set_var_from_var(&x, &xpow); set_var_from_var(&const_one, &ifac); set_var_from_var(&const_one, &ni); for (i = 2;; i++) { add_var(&ni, &const_one, &ni); mul_var(&xpow, &x, &xpow, global_rscale); mul_var(&ifac, &ni, &ifac, global_rscale); div_var(&xpow, &ifac, &elem, global_rscale, ex); if ( *ex != No_Error ) break; if (elem.ndigits == 0) break; add_var(result, &elem, result); } } if ( *ex == No_Error ) { while (ndiv2-- > 0) mul_var(result, result, result, global_rscale); *global_rscale = save_global_rscale; if (xneg) div_var(&const_one, result, result, global_rscale, ex); else div_var(result, &const_one, result, global_rscale, ex); if ( *ex == No_Error ) result->sign = NUMERIC_POS; } free_var(&x); free_var(&xpow); free_var(&ifac); free_var(&elem); free_var(&ni); if ( *ex != No_Error ) nan_var(result); } /* ---------- * ln_var() - * * Compute the natural log of x * ---------- */ static void ln_var(NumericVar *arg, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericVar x; NumericVar xx; NumericVar ni; NumericVar elem; NumericVar fact; int i; int save_global_rscale; if (cmp_var(arg, &const_zero) <= 0) { /* math error on numeric - cannot compute LN of value <= zero */ *ex = Numeric_Overflow; nan_var(result); return; } save_global_rscale = *global_rscale; *global_rscale += 8; init_var(&x); init_var(&xx); init_var(&ni); init_var(&elem); init_var(&fact); set_var_from_var(&const_two, &fact); set_var_from_var(arg, &x); while (cmp_var(&x, &const_two) >= 0) { sqrt_var(&x, &x, global_rscale, ex); if ( *ex != No_Error ) break; mul_var(&fact, &const_two, &fact, global_rscale); } if ( *ex == No_Error ) { set_var_from_str("0.5", &elem, ex); /* This won't raise exception */ while (cmp_var(&x, &elem) <= 0) { sqrt_var(&x, &x, global_rscale, ex); if ( *ex != No_Error ) break; mul_var(&fact, &const_two, &fact, global_rscale); } } if ( *ex == No_Error ) { sub_var(&x, &const_one, result); add_var(&x, &const_one, &elem); div_var(result, &elem, result, global_rscale, ex); } if ( *ex == No_Error ) { set_var_from_var(result, &xx); mul_var(result, result, &x, global_rscale); set_var_from_var(&const_one, &ni); for (i = 2;; i++) { add_var(&ni, &const_two, &ni); mul_var(&xx, &x, &xx, global_rscale); div_var(&xx, &ni, &elem, global_rscale, ex); if ( *ex != No_Error ) break; if (cmp_var(&elem, &const_zero) == 0) break; add_var(result, &elem, result); } } if ( *ex == No_Error ) { *global_rscale = save_global_rscale; mul_var(result, &fact, result, global_rscale); } free_var(&x); free_var(&xx); free_var(&ni); free_var(&elem); free_var(&fact); if ( *ex != No_Error ) nan_var(result); } /* ---------- * log_var() - * * Compute the logarithm of x in a given base * ---------- */ static void log_var(NumericVar *base, NumericVar *num, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericVar ln_base; NumericVar ln_num; *global_rscale += 8; init_var(&ln_base); init_var(&ln_num); ln_var(base, &ln_base, global_rscale, ex); if ( *ex == No_Error ) ln_var(num, &ln_num, global_rscale, ex); if ( *ex == No_Error ) { *global_rscale -= 8; div_var(&ln_num, &ln_base, result, global_rscale, ex); } free_var(&ln_num); free_var(&ln_base); if ( *ex != No_Error ) nan_var(result); } /* ---------- * power_var() - * * Raise base to the power of exp * ---------- */ static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result, int *global_rscale, Decimal_Exception *ex) { NumericVar ln_base; NumericVar ln_num; int save_global_rscale; save_global_rscale = *global_rscale; *global_rscale += *global_rscale / 3 + 8; init_var(&ln_base); init_var(&ln_num); ln_var(base, &ln_base, global_rscale, ex); if ( *ex == No_Error ) { mul_var(&ln_base, exp, &ln_num, global_rscale); *global_rscale = save_global_rscale; exp_var(&ln_num, result, global_rscale, ex); } free_var(&ln_num); free_var(&ln_base); if ( *ex != No_Error ) nan_var(result); } /* ---------------------------------------------------------------------- * * Following are the lowest level functions that operate unsigned * on the variable level * * ---------------------------------------------------------------------- */ /* ---------- * cmp_abs() - * * Compare the absolute values of var1 and var2 * Returns: -1 for ABS(var1) < ABS(var2) * 0 for ABS(var1) == ABS(var2) * 1 for ABS(var1) > ABS(var2) * ---------- */ static int cmp_abs(NumericVar *var1, NumericVar *var2) { int i1 = 0; int i2 = 0; int w1 = var1->weight; int w2 = var2->weight; int stat; while (w1 > w2 && i1 < var1->ndigits) { if (var1->digits[i1++] != 0) return 1; w1--; } while (w2 > w1 && i2 < var2->ndigits) { if (var2->digits[i2++] != 0) return -1; w2--; } if (w1 == w2) { while (i1 < var1->ndigits && i2 < var2->ndigits) { stat = var1->digits[i1++] - var2->digits[i2++]; if (stat) { if (stat > 0) return 1; return -1; } } } while (i1 < var1->ndigits) { if (var1->digits[i1++] != 0) return 1; } while (i2 < var2->ndigits) { if (var2->digits[i2++] != 0) return -1; } return 0; } /* ---------- * add_abs() - * * Add the absolute values of two variables into result. * result might point to one of the operands without danger. * ---------- */ static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result) { NumericDigit *res_buf; NumericDigit *res_digits; int res_ndigits; int res_weight; int res_rscale; int res_dscale; int i, i1, i2; int carry = 0; /* copy these values into local vars for speed in inner loop */ int var1ndigits = var1->ndigits; int var2ndigits = var2->ndigits; NumericDigit *var1digits = var1->digits; NumericDigit *var2digits = var2->digits; res_weight = MAX(var1->weight, var2->weight) + 1; res_rscale = MAX(var1->rscale, var2->rscale); res_dscale = MAX(var1->dscale, var2->dscale); res_ndigits = res_rscale + res_weight + 1; if (res_ndigits <= 0) res_ndigits = 1; res_buf = digitbuf_alloc(res_ndigits); res_digits = res_buf; i1 = res_rscale + var1->weight + 1; i2 = res_rscale + var2->weight + 1; for (i = res_ndigits - 1; i >= 0; i--) { i1--; i2--; if (i1 >= 0 && i1 < var1ndigits) carry += var1digits[i1]; if (i2 >= 0 && i2 < var2ndigits) carry += var2digits[i2]; if (carry >= 10) { res_digits[i] = carry - 10; carry = 1; } else { res_digits[i] = carry; carry = 0; } } Assert(carry == 0); /* else we failed to allow for carry out */ while (res_ndigits > 0 && *res_digits == 0) { res_digits++; res_weight--; res_ndigits--; } while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0) res_ndigits--; if (res_ndigits == 0) res_weight = 0; digitbuf_free(result->buf); result->ndigits = res_ndigits; result->buf = res_buf; result->digits = res_digits; result->weight = res_weight; result->rscale = res_rscale; result->dscale = res_dscale; } /* ---------- * sub_abs() - * * Subtract the absolute value of var2 from the absolute value of var1 * and store in result. result might point to one of the operands * without danger. * * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!! * ---------- */ static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result) { NumericDigit *res_buf; NumericDigit *res_digits; int res_ndigits; int res_weight; int res_rscale; int res_dscale; int i, i1, i2; int borrow = 0; /* copy these values into local vars for speed in inner loop */ int var1ndigits = var1->ndigits; int var2ndigits = var2->ndigits; NumericDigit *var1digits = var1->digits; NumericDigit *var2digits = var2->digits; res_weight = var1->weight; res_rscale = MAX(var1->rscale, var2->rscale); res_dscale = MAX(var1->dscale, var2->dscale); res_ndigits = res_rscale + res_weight + 1; if (res_ndigits <= 0) res_ndigits = 1; res_buf = digitbuf_alloc(res_ndigits); res_digits = res_buf; i1 = res_rscale + var1->weight + 1; i2 = res_rscale + var2->weight + 1; for (i = res_ndigits - 1; i >= 0; i--) { i1--; i2--; if (i1 >= 0 && i1 < var1ndigits) borrow += var1digits[i1]; if (i2 >= 0 && i2 < var2ndigits) borrow -= var2digits[i2]; if (borrow < 0) { res_digits[i] = borrow + 10; borrow = -1; } else { res_digits[i] = borrow; borrow = 0; } } Assert(borrow == 0); /* else caller gave us var1 < var2 */ while (res_ndigits > 0 && *res_digits == 0) { res_digits++; res_weight--; res_ndigits--; } while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0) res_ndigits--; if (res_ndigits == 0) res_weight = 0; digitbuf_free(result->buf); result->ndigits = res_ndigits; result->buf = res_buf; result->digits = res_digits; result->weight = res_weight; result->rscale = res_rscale; result->dscale = res_dscale; } /* End $Source: /cvsroot/apq/apq/numeric.c,v $ */ apq-3.2.0/legacy/numeric.h000066400000000000000000000043301171626402600153610ustar00rootroot00000000000000/* Borrowed from postgresql-7.2.1 sources : * $Id: numeric.h,v 1.4 2002/08/03 03:27:33 wwg Exp $ * * See PG_COPYRIGHT file. * ---------- * numeric.h * * Definitions for the exact numeric data type of Postgres * * 1998 Jan Wieck * * $Header: /cvsroot/apq/apq/numeric.h,v 1.4 2002/08/03 03:27:33 wwg Exp $ * * ---------- */ #ifndef _PG_NUMERIC_H_ #define _PG_NUMERIC_H_ /* ---------- * The hardcoded limits and defaults of the numeric data type * ---------- */ #define NUMERIC_MAX_PRECISION 1000 #define NUMERIC_DEFAULT_PRECISION 30 #define NUMERIC_DEFAULT_SCALE 6 /* ---------- * Internal limits on the scales chosen for calculation results * ---------- */ #define NUMERIC_MAX_DISPLAY_SCALE NUMERIC_MAX_PRECISION #define NUMERIC_MIN_DISPLAY_SCALE (NUMERIC_DEFAULT_SCALE + 4) #define NUMERIC_MAX_RESULT_SCALE (NUMERIC_MAX_PRECISION * 2) #define NUMERIC_MIN_RESULT_SCALE (NUMERIC_DEFAULT_PRECISION + 4) /* ---------- * Sign values and macros to deal with packing/unpacking n_sign_dscale * ---------- */ #define NUMERIC_SIGN_MASK 0xC000 #define NUMERIC_POS 0x0000 #define NUMERIC_NEG 0x4000 #define NUMERIC_NAN 0xC000 #define NUMERIC_DSCALE_MASK 0x3FFF #define NUMERIC_SIGN(n) ((n)->n_sign_dscale & NUMERIC_SIGN_MASK) #define NUMERIC_DSCALE(n) ((n)->n_sign_dscale & NUMERIC_DSCALE_MASK) #define NUMERIC_IS_NAN(n) (NUMERIC_SIGN(n) != NUMERIC_POS && \ NUMERIC_SIGN(n) != NUMERIC_NEG) /* ---------- * The Numeric data type stored in the database * * NOTE: by convention, values in the packed form have been stripped of * all leading and trailing zeroes (except there will be a trailing zero * in the last byte, if the number of digits is odd). In particular, * if the value is zero, there will be no digits at all! The weight is * arbitrary in that case, but we normally set it to zero. * ---------- */ typedef struct NumericData { int32 varlen; /* Variable size */ int16 n_weight; /* Weight of 1st digit */ uint16 n_rscale; /* Result scale */ uint16 n_sign_dscale; /* Sign + display scale */ unsigned char n_data[1]; /* Digit data (2 decimal digits/byte) */ } NumericData; typedef NumericData *Numeric; #define NUMERIC_HDRSZ (sizeof(int32) + sizeof(uint16) * 3) #endif /* _PG_NUMERIC_H_ */ apq-3.2.0/legacy/pgtypes.h000066400000000000000000000102001171626402600154030ustar00rootroot00000000000000/* Borrowed from postgresql-7.2.1 sources : * $Id: pgtypes.h,v 1.4 2002/08/03 03:27:34 wwg Exp $ * * See PG_COPYRIGHT file. * * The contents of this file is extracted from various portions * of other postgresql-7.2.1 works. */ #ifndef _PGTYPES_H_ #define _PGTYPES_H_ #include #define palloc malloc #define prealloc realloc #define pfree free #define pstrdup strdup #define Assert assert #define VARHDRSZ ((int32) sizeof(int32)) /* * NULL * Null pointer. */ #ifndef NULL #define NULL ((void *) 0) #endif typedef int bool; #define FALSE 0 #define TRUE 1 /* ---------------------------------------------------------------- * Section 3: standard system types * ---------------------------------------------------------------- */ /* * Pointer * Variable holding address of any memory resident object. * * XXX Pointer arithmetic is done with this, so it can't be void * * under "true" ANSI compilers. */ typedef char *Pointer; /* * intN * Signed integer, EXACTLY N BITS IN SIZE, * used for numerical computations and the * frontend/backend protocol. */ #ifndef HAVE_INT8 typedef signed char int8; /* == 8 bits */ typedef signed short int16; /* == 16 bits */ typedef signed int int32; /* == 32 bits */ #endif /* not HAVE_INT8 */ /* * uintN * Unsigned integer, EXACTLY N BITS IN SIZE, * used for numerical computations and the * frontend/backend protocol. */ /* Also defined in interfaces/odbc/md5.h */ #ifndef HAVE_UINT8 typedef unsigned char uint8; /* == 8 bits */ typedef unsigned short uint16; /* == 16 bits */ typedef unsigned int uint32; /* == 32 bits */ #endif /* not HAVE_UINT8 */ /* * boolN * Boolean value, AT LEAST N BITS IN SIZE. */ typedef uint8 bool8; /* >= 8 bits */ typedef uint16 bool16; /* >= 16 bits */ typedef uint32 bool32; /* >= 32 bits */ /* * bitsN * Unit of bitwise operation, AT LEAST N BITS IN SIZE. */ typedef uint8 bits8; /* >= 8 bits */ typedef uint16 bits16; /* >= 16 bits */ typedef uint32 bits32; /* >= 32 bits */ /* * wordN * Unit of storage, AT LEAST N BITS IN SIZE, * used to fetch/store data. */ typedef uint8 word8; /* >= 8 bits */ typedef uint16 word16; /* >= 16 bits */ typedef uint32 word32; /* >= 32 bits */ /* * floatN * Floating point number, AT LEAST N BITS IN SIZE, * used for numerical computations. * * Since sizeof(floatN) may be > sizeof(char *), always pass * floatN by reference. * * XXX: these typedefs are now deprecated in favor of float4 and float8. * They will eventually go away. */ typedef float float32data; typedef double float64data; typedef float *float32; typedef double *float64; /* * 64-bit integers */ #ifdef HAVE_LONG_INT_64 /* Plain "long int" fits, use it */ #ifndef HAVE_INT64 typedef long int int64; #endif #ifndef HAVE_UINT64 typedef unsigned long int uint64; #endif #elif defined(HAVE_LONG_LONG_INT_64) /* We have working support for "long long int", use that */ #ifndef HAVE_INT64 typedef long long int int64; #endif #ifndef HAVE_UINT64 typedef unsigned long long int uint64; #endif #else /* not HAVE_LONG_INT_64 and not HAVE_LONG_LONG_INT_64 */ /* Won't actually work, but fall back to long int so that code compiles */ #ifndef HAVE_INT64 typedef long int int64; #endif #ifndef HAVE_UINT64 typedef unsigned long int uint64; #endif #define INT64_IS_BUSTED #endif /* not HAVE_LONG_INT_64 and not HAVE_LONG_LONG_INT_64 */ /* sig_atomic_t is required by ANSI C, but may be missing on old platforms */ #ifndef HAVE_SIG_ATOMIC_T typedef int sig_atomic_t; #endif /* * Size * Size of any memory resident object, as returned by sizeof. */ typedef size_t Size; /* * Index * Index into any memory resident array. * * Note: * Indices are non negative. */ typedef unsigned int Index; /* * Offset * Offset into any memory resident array. * * Note: * This differs from an Index in that an Index is always * non negative, whereas Offset may be negative. */ typedef signed int Offset; /* * Common Postgres datatype names (as used in the catalogs) */ typedef int16 int2; typedef int32 int4; typedef float float4; typedef double float8; #endif /* End $Source: /cvsroot/apq/apq/pgtypes.h,v $ */ apq-3.2.0/legacy/win32.aux000066400000000000000000000027111171626402600152300ustar00rootroot00000000000000\relax \select@language{english} \@writefile{toc}{\select@language{english}} \@writefile{lof}{\select@language{english}} \@writefile{lot}{\select@language{english}} \@writefile{toc}{\contentsline {chapter}{\numberline {1}Getting Started}{1}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {1.1}Does APQ Need CYGWIN?}{1}} \@writefile{toc}{\contentsline {section}{\numberline {1.2}Tools Needed}{2}} \@writefile{toc}{\contentsline {section}{\numberline {1.3}CYGWIN Tools}{2}} \@writefile{toc}{\contentsline {chapter}{\numberline {2}PostgreSQL Preparation}{4}} \@writefile{lof}{\addvspace {10\p@ }} \@writefile{lot}{\addvspace {10\p@ }} \@writefile{toc}{\contentsline {section}{\numberline {2.1}Shell Sessions}{4}} \@writefile{toc}{\contentsline {section}{\numberline {2.2}Source Code}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.1}Download Sources}{4}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.2.2}Unpack Sources}{5}} \@writefile{toc}{\contentsline {section}{\numberline {2.3}Compile PostgreSQL Components}{5}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.3.1}Check for libpq.dll}{5}} \@writefile{toc}{\contentsline {section}{\numberline {2.4}Create Staging Area}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.4.1}Install the DLL File}{6}} \@writefile{toc}{\contentsline {subsection}{\numberline {2.4.2}Install C Header Files}{6}} apq-3.2.0/legacy/win32.dvi000066400000000000000000000276541171626402600152320ustar00rootroot00000000000000; TeX output 2008.02.20:1820y?֍nUsGGecrm1728APQ-2.1hWin32BuildInstructions+  ecrm1200WearrenlW.Gawy?SeptemwbSerl24,2003*y?/>?VEqqecbx2074ChapterV12> HHecbx2488GettingStarted4> 1 ecrm1000ThisdoGcumentprovidesaguidetothosepGeoplewhoprefertocompileproGducts >theyk$install,pfromthesourcecoGde.Thisguidespecicallyk%dealswithcompiling>andU installingAPQinawin32environment.MWhatU doyougetfromAPQinthewin32environment?MTheU followingaretheproGductsofthiscompileandinstallprocedure:M !", cmsy10WapGq_myadapter.dllU forMySQLsupportMWapGq-mysql.adsU generatedspecforMySQLsupportMWlibapGq.aU staticlibraryforAPQclientprogramsMWAPQU staticspGecandbodysourcesMWAPQ-2.1.EXEU Installerprogram>Y*oumayalsochoGosewhichdatabasesyouwishtosuppGort.F*orexample,you >maykonlywishtoincludeMySQLEsuppGortforthewin32environment.+aOrin->stead,wyou=maychoGose=tosupportall=products^T2ecrm07001|2,w sincePostgreSQLmay'resideonhostsotherthanthewin32environmentthatyouareusing.bTThe>choiceU isyours.!֍>!&Lt$ffffecbx14401.1bFDopesG\APQNeedCYGWIN?~>No.MWhen-dAPQ-,isbuilt-eandinstalledusingtheseinstructions,cuiscompletely>indepGendentҞofanyҟCYGWIN;toGolsandҞlibraries.Y*oumayҟrunyourAPQ>applicationAin@oroutofaCYGWINenvironment.ItAonlyrequiresthewin32>environment,U andthoselibrariesthatcomeinstalledwithGNA*T.>Xffv E !i-:7Lecrm06001K"ecrm0800AÒt(thepresenttime,thisisPostgreSQLandMySQL.(1y?MAPQQ^doGesQ_however,RrequiretheuseQ^ofCYGWINenvironmenttoGols,Rtoper- >formZtheYbuildproGcess.\-ThecompilerusedisonlyGNA*TFandGNAT'sZunder->lyingYgcc.^2 [However,theXwin32environmentXisnotrichinthewayXofscripted>buildU proGcesses,sotheCYGWINPOSIXlikeenvironmentisusedinstead.!֍>1.2bFT(opolsG\Needed~>InordertobuildtheAPQlibraryfromsources,]youwillneedanumbGeroftools>installed:MWCYGWINU (seebGelowforlist)MWMicrosoftU VisualStudio(V*ersion6.0)^3MWmakensisU (NullsoftScriptableInstallSystem)^4MWGNA*TU Compiler(3.14pwastested)>TheȉmakensisȈisactualsomewhatoptional.˺TheactualbuilddoGesnotrequire >thisvtoGol.րIfvyouarepreparedtomovevthevqariouscompGonentsintovthecorrect>places(orcustomloGcations),youdonotneedit.YHowever,thebuiltAPQ->2.1.EXEinstallprogramishighlyrecommended,bGecauseitprovidesthefollow->ingU bGenets:MWmakesU installationeasyandfoGolproofMWallowsU youtochoGosewhatcomponentstoinstallMWregistersU itsversionintheregistryMWisU GNA*TawareMWprovidesU anuninstallcapability^5!֍>1.3bFCYGWING\T(opols~>InqordertoprovideaPOSIX=likeenvironment,theCYGWIN=toGolsarenecessary >toTfacilitateUthecomplexproGcessofbuildingtheAPQ9libraryfromsources.If>binaryU versionsofthelibraryareavqailable,youmaywanttousetheminstead.MTheU followinglistaretheCYGWINtoGolsneeded:MWbashU (shell)MWsed>ffffv E !i-:2KMicrosoft's(toChapterV22>PFostgreSQLPreparation4>This?section>showsyouwhat>youneed>todotopreparethePostgreSQL$compGo- >nents(of)APQ.Ifyoudo)notplantoprovidewin32suppGortforPostgreSQL,then>youcanskiptothenextchapter.aPostgreSQLclientfacility*.ZInstallingandusingaPostgreSQLdatabaseunder>WindowsU iswellbGeyondthescopGeofthisdocument.!֍>2.1bFShellG\Sessions~>Thischapterwillassumethatyouareusingthecmd.exenativeshellsessions>(ie.qnotU CYGWIN).>2.2bFSourceG\Copde~>ThisdoGcumentwillassumethatyour3rdpartysourcecoGdewillbGedownloaded>andU unpackedinthedirectory:MWc:\work>IfU youdon'thavethisdirectory*,thencreateonenow.Y>"!N ecbx12002.2.1g=lDownloadSourcest>DownloadthePostgreSQLsourcesthatyouplantouse.Inthisexamplethe >downloadU le:W#qL ectt1000postgresql-base-snapshot.tar.gz>was^used.Y*oumay^wanttochoGose^astableproductionquality^releaseinstead.>OncePyouQhavedownloadedyourQsourcele,unpackQittoyourQworkdirectory*.>HereU wewillusetheleshownabGove.(4y?>2.2.2g=lUnpackSourcest>UnpackyourPostgreSQLsourcestotheworksubGdirectory*.7~Usingtheledown- >loadedU abGove,thesourcesunpackedintothedirectorynamed:MWc:\work\pGostgresql-snapshot>IfvyouvdownloadedaproGductionlevelvrelease,%thensnapshotKwasvlikelyreplaced>byJEaversionJFnumbGer.ChangetothesrcJFsubdirectory*,andthenlistJFthelesthere.>Y*ouU shouldndalenamedwin32.mak(usingcmd.exeshell):W$&ectt0800C:\work>?cdpostgresql-snapshot\src\interfaces\libpq WC:\work\postgresql-snapshot\src\interfaces\libpq>?dir/w!֍>2.3bFCompileG\PcostgreSQLCompponents~>In<&that<'directory*,A$youshouldseealenamedwin32.mak(thepromptherewill>bGeU abbreviated):WC:>?nmake/fwin32.mak>Note:eyou0shouldalways1checkwiththe1doGcumentationthatcomes1withyour>sourcecoGde.ÑThesedirectionsshouldworkonallrecentreleasesuptoand>including{7.4bGeta2.Buildandinstallinstructionsoften{change,ŭsocheckfor>them,U witheachnewrelease.Y>2.3.1g=lCheckforlibp_q.dllt>ThisshouldnowbuildthePostgreSQL=clientlibrarylibpGq.dll.Thisprocess>might+fail,atsomepGoint.^1aThiscanbGe,ignored,iftheimportant,part(libpq.dll)>wasU built.qChangetothedlldirectorytocheck:WC:>?cdinterfaces\libpq\Release WC:>?dirlibpq.dll\?Volume?indriveChasnolabel.\?Volume?SerialNumberis587F-CB45\?Directory?ofC:\work\postgresql-snapshot\src\interfaces\libpq\ReleaseW09/19/2003x10:42p;|H90,112?libpq.dll1?File(s)&=90,112bytes0?Dir(s)x32,435,912,704bytesfreeWC:>>The~example~sessionabGove,vshows~thatthelibpGq.dlllewassuccessfullycreated.>Xffv E !i-:1KRelease(7.4b2.4bFCreateG\StagingArea~>NowcreateadirectorytoplacetheimpGortantPostgreSQLƟlesinto.B Createthe >followingU directories:|>%]f ecbx1000c:\pQostgresql3topU levelstagingdirectoryp>c:\pQostgresql\includedirectoryU ofCheaderlesforcompiling>c:\pQostgresql\lib'optionalU directoryforDLL>These]directoriescreatea]placeforthePostgreSQL]DLLle]andtheC]header >les.^2湍>2.4.1g=lInstalltheDLLFilet>CopythePostgreSQLDLLleintothestagingarea.UnY*ouwanttocopythele:MWc:\work\pGostgresql-snapshot\src\interfaces\libpq\release\libpq.dll|>toU theloGcation:MWc:\pGostgresql\lib\libpq.dll>IfݤthisdirectoryisnotonyourwindowsP*ATH,ݤyouwillneedtoeitherputit>on:yourpath,@6orplaceitsomewhereelse:thatisonthepath.hOnesuggestionis>GNA*T'sU bindirectory.qOntheauthor'ssystem,thiswouldbGe:|MWc:\opt\gnat\bin\libpGq.dll湍>2.4.2g=lInstallCHeaderFilest>NowkitjisnecessarytocopyoverthejCheaderlesthatAPQwillneedto>examine.qCopyU allthelesfrom:MWc:\work\pGostgresql-snapshot\src\interfaces\libpq\*.h>toU thedirectory:|MWc:\work\pGostgresql\include>There;are;afewotherC;headerlesthatAPQ;willneed.iCopytheheaderles>from:>1։ffv E !i-:2KItispadditionallyU tothedirectory:MWc:\work\pGostgresql\include>NowU thePostgreSQLpreparationisreadyforAPQ.(7-;y%]f ecbx1000$&ectt0800#qL ectt1000"!N ecbx1200!&Lt$ffffecbx14407Lecrm0600"ecrm0800T2ecrm0700 HHecbx2488?VEqqecbx2074 ecrm1200UsGGecrm1728 1 ecrm1000 !", cmsy10.4apq-3.2.0/legacy/win32.log000066400000000000000000000132651171626402600152220ustar00rootroot00000000000000This is pdfeTeX, Version 3.141592-1.30.5-2.2 (Web2C 7.5.5) (format=latex 2007.9.4) 20 FEB 2008 18:20 entering extended mode **win32.tex (./win32.tex LaTeX2e <2003/12/01> Babel and hyphenation patterns for american, french, german, ngerman, b ahasa, basque, bulgarian, catalan, croatian, czech, danish, dutch, esperanto, e stonian, finnish, greek, icelandic, irish, italian, latin, magyar, norsk, polis h, portuges, romanian, russian, serbian, slovak, slovene, spanish, swedish, tur kish, ukrainian, nohyphenation, loaded. (/usr/share/texmf/tex/latex/base/report.cls Document Class: report 2004/02/16 v1.4f Standard LaTeX document class (/usr/share/texmf/tex/latex/base/size10.clo File: size10.clo 2004/02/16 v1.4f Standard LaTeX file (size option) ) \c@part=\count79 \c@chapter=\count80 \c@section=\count81 \c@subsection=\count82 \c@subsubsection=\count83 \c@paragraph=\count84 \c@subparagraph=\count85 \c@figure=\count86 \c@table=\count87 \abovecaptionskip=\skip41 \belowcaptionskip=\skip42 \bibindent=\dimen102 ) (/usr/share/texmf/tex/latex/base/fontenc.sty Package: fontenc 2004/02/22 v1.99f Standard LaTeX package (/usr/share/texmf/tex/latex/base/t1enc.def File: t1enc.def 2004/02/22 v1.99f Standard LaTeX file LaTeX Font Info: Redeclaring font encoding T1 on input line 43. )) (/usr/share/texmf/tex/latex/base/inputenc.sty Package: inputenc 2004/02/05 v1.0d Input encoding file (/usr/share/texmf/tex/latex/base/latin1.def File: latin1.def 2004/02/05 v1.0d Input encoding file )) (/usr/share/texmf/tex/latex/graphics/graphicx.sty Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) (/usr/share/texmf/tex/latex/graphics/keyval.sty Package: keyval 1999/03/16 v1.13 key=value parser (DPC) \KV@toks@=\toks14 ) (/usr/share/texmf/tex/latex/graphics/graphics.sty Package: graphics 2001/07/07 v1.0n Standard LaTeX Graphics (DPC,SPQR) (/usr/share/texmf/tex/latex/graphics/trig.sty Package: trig 1999/03/16 v1.09 sin cos tan (DPC) ) (/usr/share/texmf/tex/latex/graphics/graphics.cfg File: graphics.cfg 2005/02/03 v1.3 graphics configuration of teTeX/TeXLive ) Package graphics Info: Driver file: dvips.def on input line 80. (/usr/share/texmf/tex/latex/graphics/dvips.def File: dvips.def 1999/02/16 v3.0i Driver-dependant file (DPC,SPQR) )) \Gin@req@height=\dimen103 \Gin@req@width=\dimen104 ) (/usr/share/texmf/tex/generic/babel/babel.sty Package: babel 2004/11/20 v3.8d The Babel package (/usr/share/texmf/tex/generic/babel/english.ldf Language: english 2004/06/14 v3.3o English support from the babel system (/usr/share/texmf/tex/generic/babel/babel.def File: babel.def 2004/11/20 v3.8d Babel common definitions \babel@savecnt=\count88 \U@D=\dimen105 ) \l@british = a dialect from \language\l@english \l@UKenglish = a dialect from \language\l@english \l@canadian = a dialect from \language\l@american \l@australian = a dialect from \language\l@british \l@newzealand = a dialect from \language\l@british )) No file win32.aux. \openout1 = `win32.aux'. LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 30. LaTeX Font Info: ... okay on input line 30. LaTeX Font Info: External font `cmex10' loaded for size (Font) <12> on input line 40. LaTeX Font Info: External font `cmex10' loaded for size (Font) <8> on input line 40. LaTeX Font Info: External font `cmex10' loaded for size (Font) <6> on input line 40. [1 ] Chapter 1. LaTeX Font Info: Try loading font information for OMS+cmr on input line 53. (/usr/share/texmf/tex/latex/base/omscmr.fd File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions ) LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available (Font) Font shape `OMS/cmsy/m/n' tried instead on input line 53. LaTeX Font Info: External font `cmex10' loaded for size (Font) <7> on input line 62. LaTeX Font Info: External font `cmex10' loaded for size (Font) <5> on input line 62. [1 ] [2] [3] Chapter 2. LaTeX Font Info: Try loading font information for T1+cmtt on input line 170. (/usr/share/texmf/tex/latex/base/t1cmtt.fd File: t1cmtt.fd 1999/05/25 v2.5h Standard LaTeX font definitions ) [4 ] Overfull \hbox (3.42719pt too wide) in paragraph at lines 232--232 [] \T1/cmtt/m/n/8 Directory of C:\work\postgresql-snapshot\src\interfaces\libpq \Release [] [5] [6] [7] Chapter 3. LaTeX Warning: File `winzip.jpg' not found on input line 353. ! LaTeX Error: File `winzip.jpg' not found. See the LaTeX manual or LaTeX Companion for explanation. Type H for immediate help. ... l.353 \includegraphics[scale=0.5]{winzip.jpg} ? X Here is how much of TeX's memory you used: 1160 strings out of 94433 13136 string characters out of 1175590 65756 words of memory out of 1000000 4388 multiletter control sequences out of 10000+50000 17014 words of font info for 38 fonts, out of 500000 for 2000 580 hyphenation exceptions out of 1000 25i,8n,19p,225b,215s stack positions out of 1500i,500n,5000p,200000b,5000s Output written on win32.dvi (8 pages, 12204 bytes). apq-3.2.0/legacy/win32.pdf000066400000000000000000006753501171626402600152230ustar00rootroot00000000000000%PDF-1.2 %쏢 6 0 obj <> stream x=OO0 >q$1yt*فoO(+????O@Wj;Iݽ|,jʭ،_rdgdb-P1MjGasR~4%/)a17?:_ڵԍ aS^8! &.-.yDF2  {> stream xYKoGΙ<~?Ď+` '`LY𥙡~UE,XFY]]W_5*JXEOfw kbSϮ~fhu5 Al,'VWf??YE4͗o_ˊKbaLҁM;vHT2cLfLgd0w֊+^Ή%#˝_cGgæ݆8)EZ&)eҾknƓ$Θ%0=ְS&y9FqmV_R(dzOn;y*X)BM .xm],qFɓ AXcB-H&lU9ke lgf~N*}w_#|aBgsݡ_D)Q(t>*.$gL&JsL԰OVv}k JScf=`fln\#QkAgԌG0m,) }}:Hv۔f-nVcd^5o$~MWC8` 8ês s SL > ʳ6c+M)|rT (G=q.ąoj1x Ԏ*[٭1,I'~byl=&Es"w7)8X3h(|q @ r=ܢ]=~-BW5g}GUx?wG0` ,.re/ _'D` q0~<{Ilh9pIEwk,䦖4{n۾ImW*"{ q& ʺ=3eLߑ&E Bn3 X>-aźk2FBf8nf3< |.*z]/&QLr)rɱ?]\}*xQžȭ>58L^::C%r(*#J?2`*Ԕi~.rSh6MZ#n9ʑCm`і !rWgTlҋe1ϫcbN(yY6cbȡAg?w*u%&e /V9Ie)$W<\ e>4Tg5AKJI=x Ճymרg-c= )mCB"Дi109 Y"<#f/5T6Sv@ )0b"km/V gԗ PQ<~+)R _Tpk-';Qi FR[ }uH@y׋Is4]d0 @}r9b8,Vi]h1Q@ -uAl W@J=7uLdzᴃ7 oHn:r;!@SznB+K삟~.[c ' nld9,e"̖'xO"byoxPY 1`HUcz >>@e(Im v]!+- ŕ7N\},r]'QV^zuh|%-?Ś Ce88$$dmS('91~Ƃ3Peb甔*}{wH^Ṳ+!e#=ydǣMyՠ>{u.&} _6vY2G> bz$yd۲L!0+zWhUKb!bZP-6׳+vvb^{~?"?I}?$S@c:|A t1z"`3G,TఌƼC8P' s1|3o 0M:VN],vw =U, FQ(jÃ/dnendstream endobj 21 0 obj 2112 endobj 45 0 obj <> stream xZKΙ$Ty?rdރY޲`I.bPk`fzKiRUяKJؒ?vqqɆz|}E-DۥVpax]pE3.,.6?cGe<+ͭg:GSt'Bp$\[jKDa8dCcasڹx?zΟKS]00矪m/ K6$NMx${2Rɕ_GŨJrb|8k%'AQr{MLq&YoQp$ڡ]Ṝklc\:am9ZUȐ]yf߿{52bYuٱtU^ڙsQQqm0 ïjw~sA%$%M l)i9bInJW 7 T?j'k8`RH877q2d>l)q-}5OUXYw֡ŀmƒ, MD٭juV6.)\6e(r(S*U2Y8ṒH&V%]:,C(ߒgjr<4 ˛csyﺾ,6>44"$#@f"<"6LokB*tқO ]YnYu2=+ 7tnAµ&^j50cA 6M=`7۶hBD(C,ߵMu5v\*(GĤWu=Z" Kݕ"Cbr%ϕ7/\WjHpʿ֛utPj0/Uw( 3䥤\ܲf E7{je/ ׺-~2]W%ŻC]clc0.#(E q ZxӜҐ;94NH@ c|b\xzGxv37`uĮY.Zr ϳQź}mP;;5`͉YJ1d3Ydv:րd,<=7O$Ph]4 x2\pMm_Zd-&3N&mK M}:}{*PPdYBo FV͡V:ĿGbɃC ЁL~42PjL"7uӶ|*0X\X?{AkuԠ,<0#,錃xV,NC*TTz=4yO5OP.y++I  VB&:(ICdPVev@)xľ$ryP?IĶpy} tM,rNI-"7U} -1\(ڔQu,MueBʏi_dui΅]Ug+RAF{)r0 ʥ>Iq[``BqP!4u7e%4rݼ$ <@<-R>%K)}0k}ԏl8"|gZY%( 5ZpV7Q/nX9*:h[F>S=hmЯUj X#cQl/Fc~! ~3zotj%jP+% D vÏR33Z5XC9;ih "i^6$(8gb_Vu KQ)|ҡ̬ѸSi6(teZ]ءG(3.^_-.~\\\d^]}Uxc ڦ3t,}W%*8~Y19zsqE>IƏ)mSJH9euB;/ J!q&2 c}[͠pCwOq $}FG 7$O}>L" .MĹȆ^_-&&sdDuU|ri5iw%d&@yj 5u叟6%YVђH`xnCɋ?$SWZ#oa*CD>U4&Q LhϗC548jwϣ$aKᇵ<^,3^]͢nifmI⬍Bz<'_>9p״%ٕeWe۔~~h_}6D:r 績 Tl澄r-y1]Y% 8ҥ2,KA;(L P|vS<JiGx endstream endobj 46 0 obj 2838 endobj 49 0 obj <> stream xP1 .ِ'] RE$C\gF@"L5&Nt@{&_+e4xh,j*.NfjJcEozISTC E՚KA>L(1څs4N`֓3}[d-yo EIv#Nu Ik6~%ÏH endstream endobj 50 0 obj 225 endobj 53 0 obj <> stream xXnF%?bvo$NjÀ. aXAd3}Vv-Wp~ >Mq8$,~y ¤3ziNB?j2M!q41+|ԜiaGH{0Ci 1^W8Ngw<dDN6!YifǓ҃B!ST I]1(UG`.PɚaJ' WQD+oĨ#taN>AHd5W"}e0jLh f< "A>w\!MG!ͱ2lZ_Cf(Ԏ*Br{<3%b:({T>RHb]dPsiۀ8Yw}œHR\ԛs))ME)!!#Be&t% RHbK,,.FNX ~a)̌r< I-4)a%2ES v2 F/c1rJbNH>咹IΰˀwgU YB7Xx3Tv4n= v}C=\N.*f 0Tt8Lj2 ,~儞3cHWNO #sͨRބ2k0JS\FB]n:lq*ILγh7I4͗?>}wbCp'ӂТ9k9X;NyM$vj &VYxy(n+2wy*b?UM3FTE7!tF`UgrB zDŽ9?蜌ёB`[FF5&]' H\+tX56E/ Ӫ§n. M{:j-x^A_4Gxc`[JK xI̭w?(p[L}iQ:(/,nc%qxZe,4u ]ϱ'J !t;pV'u m oM; #ͷ"Fzbz4?%E^:1xk'qm6){p{ 4ٹITu%5ޡp&FM?R7V"/'`fg2ֱ>Kh:>jp+uC"Ɲ%Ǻ:tӱm.mtRO't|wj+ڞ,#ε9t%| )q}'v` ꙉ& f]Z|An3#"p$[Nn$1?qu,XߏF[x&H*EHXJ1CN\)[5~Dk[4t(Ma-tU2uDnsܪ`メ^e=5<8o{[^Lrl̟e#$ qsGv}eb䝘gTԠwLr|ic1D4 aN?endstream endobj 54 0 obj 1850 endobj 63 0 obj <> stream xYKoy.I{ h~?|]@Jsf8cCC."%o@e5U_}Ò|%kf|wk-Ez/[m +Q//vn~8,aw%kUx9o6<(¡+pv⮐ha Ah[XǥoaIZL]pXTLh’)UYc}>W~k+s` DrIxLy-Y^:>kMa{Rf\m9MYtQ$NM%{jCSiRMwb,xXŕpͱVۨ@J;2X+祯SgUWt|-uD6օ BQQq. fs^ 'tIھIxlw!DaXD8_y}f֊S oϔ#lͪ=Ew_lrM()yQpZU=8^6]}^4Wrv统*ۄ+ 7N')H3a\Hݚ B+oHox=g NMIYIKSt% hdǹ:hH2sareA5`UGSSn 윥, K2y&Ҍ¦ī,=%My;uvn;е@o\yG>=POu񋑎 'XHM@HSe除iD7?Rڂ#˻s.j $렢0 NzkVX)F\{R,X@Am˱r=8x^E>J}ikNjA\U)R\AްR$>6}Jq3s^;Բl"`(@9zۦ0MRv>2Q1ꭠ3N 3 S ks"k*4^.yYϰMG&˸PIG __aC["A)Y5N;"+Ec-U.u,sO`c4}vh*3TK IJ\P^a:MtfHfu%>z7hV;"lkE&_eS83 ކ¡JnH* !G4tڎaQ$O~V>@|6Jȑ<#|ƠU Xt/"b< DEx3Ϧ<` t}|9χ^!:;.G.z?KJ()E͸Ts MW_Qt=5:a}~KO!`[0,3(RӉ@H s d>[ls[*n9ׯևжA[2h돑uc>p4R|-s%B 0 I?/x9}{Z87{ĸ?NE6]8jřcESufe'wԎy4 ?.}5%Я KXS)MI xR'\!ejew6  4sT\`)|rԼZ{@Teޖ8 3ACV>)mdFD;dC@-P%iI< )*m 4@<&hg@endstream endobj 64 0 obj 2658 endobj 70 0 obj <> stream xYKoF޳.r-ŨGn3Nv@6It%b"2IկHɎ'jCA +K߫aPVbvDH͋,> &VpY,v8Z:X8Yg_]UW~]1"iM_/\K9pm9gʰdp.Dz/9b,- k 1s]ժo'dİlbD3ĵö\E8k&,2MzwH/ Lp|_R懸$+M߷O GDP|۪ /sDr ›,:^Rk(+l#DT`2oPmAZ7 !+#Q8Ū3 =n-DQSL5SOHIGY'L)g7iYiLpT"j͆3c0+1nsJe < SR̥!b:-0D"C{{LŒM[71DVB~wm~r#G藒XwebM&hhdrV(aSd95NB7g%FeU r8;b3+Y ڸӄh¸g2x'OCqo,E"(o$8ai b(`MqݱM2k$(˱ d !=7BJa Xо։ٌT͉`Tt{8AٺM(rm(dyM( U 7oR(E&rV?H]uͮzdDx^mqTeS%oZCE Jr,EXv㡓VWlU4(j!ڌ~6زl}exiSdPo$w*}+/;~cix1#O]_Ba5vaښ6BF03PMgN:?Au} ˁל`8s8G?Ce]g ޣ&G4^guĩzv03bTa_Xٕ' S#<)=BNsnrC۩g'.Ljp>w>yN0^޷>EEeĉع9cfpN\őW]Hql%@L:)gҶ].'ЗOSl,t8,C}& Bdd/QȍVj2ùUa"<+tmTy1v.F2-F`3I$Cx@,m?〙80ϻKE_F!)`{>wnfW7+Xͮ~.xn)1&ں| Z@3 DZz٠6Ft M1qWuazԞT4ОORFI'&`ChЯΛ}MwEϹ CaD sqlˬEpov-2صWM n$#LcIr0h})IR\;$j}l3Ħ$UOγu.ߜpa*1ې,LAut@A|bzwVRI/AXGNendstream endobj 71 0 obj 2187 endobj 77 0 obj <> stream xR=O0ܳ<< $6Z%JRH B{l7.TbElݻw0ZꐍوHV}>3 I%G.;5D /uT V@#R ݻC̥I4f|:ôgk'WYG` Ʌn 5Ak>`9%ԋj~Ru;캯^ }]X}A>ujeb4 VQXYYdM{m,E9g`hd>%[$?n$+/d_1v Ƀkҕ!ߘ-ap*Ӣf3Px׻b6[}93 Py(6 endstream endobj 78 0 obj 359 endobj 81 0 obj <> stream xWKsF 7D}?rl+MO;0I:ί/iI2:h\b>sĜ__gs1oy7rsə/of1J1?7^2wgŮ+μaVh .Wg*^z.5sމfg:xNjwo`6hnSWّ =8 #+o6ЌKkrͦn=c{EeA^RǦAV`bË@&2tۦVSy d{z]p.SlF.&l{&øMu2cVuYEgm(R솷JOHj!0ějW@)5 Il7pԭ R1nuF!w{6^(1jnЃZ=%f`ۣ6Sr͹C~ڷɃ9^!U̙ Ɏc_]8gX[Ti ΂a^ћz $& Nn"gU4!XH๮@PU KZ5eIa@ J[9(TP sA /v;=s` eBGAx7_Huj0 k7 ıhOb Ǜ4jh jRTUR@Zž:&vh+ڶT/0)t{+S䎈IXDD/uJ _x˻+?zy dˬ'mJF Kcqh&svb́O(&))nVz p8"0c^IǣdP(6!R~|TcGͿV95Jl]a)=YxtbD,A<e\P WSDbݩ& 83`uI@|بZRRTaCSC'"]j ^%< bW6u?Ss&Dxw鑊Mq08@aw;5ök{XOV=i²\$p~i)N+rԃی@0C4LNq I3ARXVĠ9:J )#܉MbuS+nZ9w0cG,TTX!/=5@-CY&D_]$ƸQpۮܵB xZ74u1[i0RXZMUF 5{?E.qB 8*زn8 )u8ZvnsXG&Z֍go-G 5,t (h M\dϛsܓ5{|tLyW4/?>~k7[d4$y@}@};XD骳GSDIBB?dGZ@ W_&sߖLe,5զ'b>О iǣL[tt$*'G+C}9z `.O~ endstream endobj 82 0 obj 1521 endobj 85 0 obj <> stream xVIo[G YKj;E mc5 edZҋ P,p8>~CE hv0y*τUV[)n ʚ꬙|WF#竓M\j,"1M fѯM_pIfr<$%R}> stream xY]oFg|KXcLޚHMb(Y#.$ѡx~pHV 2$gǹ;R^__ گſ#Ӆ%V1%뻅TL& LYJtYnr\RJܺ%I<<K(- Kmu<ևaXx&Y%aJî-2EA-nI+y[)S:unI/wEf#o$)yɢijqۜv?FJ9Ǫ{*Wn-iM ,~V$DglV'ǮF ag]ZF8ؑd('.ҋC%*sƄz1CJ5Œ-}%b[al4c ³_T(*fMڳ(JۛMu{æ*_x PTƜIjaIjSպkSF+E{V k}ՆrXVZ@vCDS<:-,SBE/ãx6+&~xS@Q6~KJ*bѯ=;1ݪ>d3C3z_6sRWGˊ a&> <1?_Drv{=%bY[x6L36ַJNPއ:xa e\M(T3?RGqi2]yG]CgM2<a谠ׇD?&~ZW!*Aѓ8lڃE.fY,#SJh85%زtc~77/S_vs4π21JOOc Q6c"]::'bщ*X-cٿ{>MbjifE{TNØY9f+ld q>7mOCͰg5WtQ fB{(}}A,I*-N6wm3@sbD8EbIޞH2 ҹeO4[]htal>0d^+rSS% I5y7M(!¦ xu}+ |-n5>RzJp Գ@v7 T(ѼkQ"4~AX\+s &LJ2M\)a/x`8-itVy(kW4աQ:`tjpE<=l8X3t& <m^ֹ9!*Dqj 3eyid'rETEaZC=F%{Vn4ӅLQvל24J}T2@ҡ nYBM&շ!܌K1u @F5'>R @ RWA (H %=KyrEK X4SʠyDWhm6бb 4K=RC PYDj)#ԎcΌ>5#y괬) 0|ÇXW>ʗ.TC?}a[7/~A˖(& T/uş/.#, l8NP5 AL,s dRk\KoRIG!GKy긝CpY&TI[.:ܛagaE +tc*o6e ݦ+AMQEL ] > stream xWn6{Ӣfyy] LZo (d[NV"{EIE /lq^fAO^g ZZﳯ~F92[lg@Zma6} 3< CPsBάPCoWUVWT)r2Qvد_;d*'@ *P/V+|X+RuL ("cEgQ"ۻ 91Ԅ }{~xMGttn0N'ՉٸljPi=UC1PY)Sv翢ܭ=c"LMkH<0ļyҲ؆]N7=enNM)F%"86 iwes0=BxÇP} QEM"J^Jڔ(S]ZYTc.֡8Z؊8iSҀx髛f<#;di=z[a'7,k},Œ*'+[lU07HHxՆ-n~MF@X3l?<& &@yƃMrp0s "8Yd?=$%n^gPcɨh1$`" G Dԩx,M,`DVG}ٮ<\O^IYн }<{R-tMAh"{c_#b 8(^D4rC}c x~.iJqu-.f[Ձ"Oo0hD'&ln`OX% bm @Kn]T<]endstream endobj 100 0 obj 1239 endobj 103 0 obj <> stream xYKoG3/|a 6fǶt#1_ ouOW 5` ͞z|WoSĔǟ{||SəN&b*b~jdOVա?]9Y5^N^4,Tj}zB&MG)⦁0ECpua=ΤT*?0X,qKK1- ˴6/jcomڪS׻$ƕqozPvHAp5[`8YȫJ KjGîWulڲ*WUxk3,~:.z4"Ty.Aȇݫӱj]p&Z,&CқE`m\2̙ u #hܶ^q;LbZRͦ[5Liauiriէ_YPNv>LsQ1oH@)mN 3xƾDZ@B43jtPUG]lNzR g`pu@rwHK0 d0%\.8mi*.q6DZ3Utx]jȠyEPSۅTBJT Xk(t.|5 @ޮMAMbVU(+ȟ}Vɒi69 R8U8Rom= 7cMǗ+f^1'$l{=)#ȠPaՊ[5 dNjKV/rYIwĩ"SUޠ`:y$;S@p8jnfA< rU=,9%]U%}r(Yjuզ ,zmr5hKOJfq\2+Ǭe{JN!SJ[D$@s|ZTĞ^Mt.$I"nRD )2+OXM BCZǝ;!Kyت2 `8Ar4ZZVA7b&rEђ܏@mAd?@lPLl{; =*~(Q, 9V_Nχ דO#[ќn32,נ1KzpA1*KurT LNC9w^!_3riNb/*zn~n'}ʂ>+G$1CN9AxT+ "L.n.)!F4VdoS*;ca(#?616@LAQK^ 9ydFx{4kQXUry^;|%s+hǎX:A8C49l;hKce45 :e Y[&/#9I>( \MΒ(3Fڟ:{W}[v>S\%MCacAamтvi !7S)Z|s"ّοv#EdUdvpz]3xqWN0t=_rv[dtvVfgISRW7?4ag2M>iz? DwhO$<0:9n"P -t\4-Տܻ12 HcMpDrڳb50˾wkz/n *qٛ'Jf/?\]5]@۵ӿ\O?ś|~HwqN^N旿M㩞̿Ld>;u?&\vg~+n@8IoAld%-@AIIP7M&hrfr/tyU[ $f~udI.QըxM.y;6A&7 WHJD"Yendstream endobj 104 0 obj 2237 endobj 107 0 obj <> stream xYM͙'ovYL.)Yed KKD$":*oyt~iY,ܿw{Z|Z|ZRlOgU,-)XQR?qW7w!A-<-oٷ'ƟT6W/i*. ڻ=Un)BYv8Wuן_V "aeGgTuS(T|kC FXcQכ:-!fbO; buk1](p#8Wt3`DJQXaVnHA1 H5Q~d0ppF ѝXKSDz Xw~l.lrTB=zNBs.޷Cp$\w9S8/,B\)>c$QӳMҝ!C͈83 E+%5EDjBJqZfѵ3{?j#,y2paf.Պ^6u1( "N( 7b(pv yN o!8?f;-$:@)e1J"ϑDM˼=B9H,iADnƦuA"9c4(χz m1UW/E ‹ioK|ɡe+GWE9= _Gc"QK=-+dSf߀LH$B(iW23Nq^B``W)6bFP3AKթv֜JIs!{|ѮuFy[Y)6/ڲj9VLnހ E\Ǜ&^uԙmFXHJ&/ z3 ݹnDv&1Szd{=@H9X`r}4)*2Тx8誘ZL@E>jF4 9b^m:rliMEY ۱(rG_KlTL+T2IF@I&13&5 R6{H[ꩶuy%LI=zRΉ#gk#sjyi&r+WY5j^]Kųx'x<9)aee7?kA[P~`!'3UX֠3x520!^;Ґj0R.3t{ooI*;ԑ@k#PFN@X4UCKNzBwCm)Uֈ!D_)|5?>^P*9k-ak87ACY̕W1fu%2Ydr83gOJKa`W<@azʰ5`j=Aq`ǘ\LC0*Ћ 6 CZ`3N ԛ@1;*ƌ.mDynYb2)..Z}8_{}?ڽ+J&)&9a)cW%I +9Tۘ&wbg> ߠ<>GV2wy9ը:BGC*mD("E2wTtuTʄ4Xu]dQ(ʃSps.ȠQOy ZFp ߴ\ׂZD#NN[c0b?pq'_u7~ A@! g iǯ4 hq f> ”J EJzθϘݲ?%]s Y}uk['K :hSTq ?~( wlLUn3Ro85ennp:"g)G?D2җ7]G*O>. 7r(n8IՉ7V 7C)Zɿ5('$lҎPT ib cS$'-,(W!H26bLU(הifFTㅋ%e}k.TL}M%C /t$ R \@i]lEO\dлF4嘦7endstream endobj 108 0 obj 2727 endobj 111 0 obj <> stream xZYoH~c}2HWʭb (ݴIYhB2]WRW!)MIqFOm+(U򮬗ղ* 'ƛ1f  rQ(+ Q00rShRx]46*?T!rfMA6 tU^ql-8Ys68v4mkSEC!wp)HKte,`=s). #IS`&`E Gv^hl+9IB&e^՝allALcpAJJ u8@ͮtL3E)9#ڃIobS>p]\V /پTOhgܤwmB *5zf҈ kWp 48V\۝YQEo2ﶚ#e_Y8̰ 2tć  Òo[F&ůvK(A/$:Z7vQt?9dԂA3Nhaջl//~1r0JMReI 4EU lͫI\]=R`Y_u1 ^ֹ[9I}#tU%Fh՟Z(ܘQH2 V+Gwr~  9Zcw#K]WT "W>3joVc/U/Q*xA*nsuY{="%tPXrvۀRW謨`UiPX²Џr Xͯb >Q/,>)Dܖ WÎ(. J(ReG/ǪML` Q&Dm074)9`ΛfP`x MzZx#rQ7UW,KRAd"KS}:2Pi<áѐq~U [DXѨ&'$D''bgd >Ϛx*]E YNUCBf$8rjvIWYߴqljvGBVUɟԧkP=- W=gz q^ 8jD~X>9$Mb+/}?ǏFBTJE5C*_VA^(ap|5O1'fe~7(P62,`\cQ8D#Nzb)?$bJ b>,+y f!M9A }ƓَOOci!m= &YnÛ׼k+ DAh&oU (NFUO^lat98s7)~{sSlCX,ilsȜ=T* }t4n]" ZN_m}9\pmǟ,D-v>q}'*3H~wa tD:,b'iE)x#2\EL1oϿT?K~t]V@i j̥*5T꒪G1?޺ֈEԑnQuo(_OObmg}R:|j2F8]X@@~Qt3eFNendstream endobj 112 0 obj 2932 endobj 115 0 obj <> stream xZnG}/}ňĀױcȑȘJz[=U=á(@쌆u=uPw眉s盳s?ÿg~7\g\(5I}~9{dgZ0.gϿg0~of'C~O?'yŪ[6զnO^.y`Jjͽ)EߚyߖeȀ{SU~?,6ޢtax?DK߱ )~B2m{+s:|=Ya<m}%g(vv/3s. .ѡOfHt:ÛRqU8l)O=(Q?k$S/e* |8h/?l;c3aF`vxD['Nt2'ZuPq¶! LX^/^Ҍ C=6k ,U%UeWT-@L\W5CF=z.ٷE0SNhrG2硩(sUK3⦩jp_]cyJZS] 1厥cwac\& AVmp=@&PR / UsҨ,Eub%in Ɨ`8o&Gx5O7 \CY% V!Ґ??[#.~ p#~Jaե~ĩ0i:I;N|2/遄凢,EK'(3hh ^S1f6Ah@d&kKhPӒ.T0`]"nIN%˲盤t[mn5ګ}Dm)[o$iBG#=E }m T-V60o]eݱ8!K\s\xA9DI`eI]Jph1-O(۶չ䭉݅w~Yo99K;ʙ~X}ĔK s ‹KN\5O"S݊c۶X1FQ}_PI}aeIfNk3TȮ k~^F RxZhMwŁ&5 G{?JD"d *x39=4ƟhH(aH{(lGkKH(!-@ 2srvAMVsPU7(r%V75lΕ5`@SV{׮[]aXyv?&E?zMOKԾC}&d-c!zU٠//S,rhˆ[0`ƦSc[rS׋^J(Zfi|$ٱpX=\q5ɡ85tDB]IܭLpO l5C~t9gժU;ӔQ^NTr-s7ev$1pA.q(V񉚣2}"aO] pI¶v+c(b:B1yfp{tK\UW:6ye+#~(scdÍ"mu.lKca$*~yvO ؂qO="hU {L ($}"mcUk-RRFE<Γ\ѯHG˪N0̓k;,Z!(|G DLLۄNoԐ\! 5-БgLyliE#,xBX%FgE/Y?ƌendstream endobj 116 0 obj 2815 endobj 122 0 obj <> stream xY[o^<7z(s%H]Il DHLRq{N%-#r\ o9fv3'n-Ymg5'!r_ ss)|~pDzyzvޭ6u) +~KHBCStUA #րaQ V1 VG[IhY[mQav tXvMsXɰVks$:۲s$fMv81s!0D!5 ƛ`8.I}+d&r#( o 6R@[<(6$ςbM.~IUSe@!c8r^כt?1ŏf^rڽ 1ˡlmۗ/̸ sQ SN_Oڣ9Z[$99۵]X@ l.h]TJNJi}Ё/1to<64-¹)wK j&]=hKi3-KnMŐf,@KOR2{X<@~btqtЫHZ`'t:x!'8^^)"ms_52 y9zh <&c|[ڹJ 'XÛE#ZD[¤p(ƿoNjMYƍ.Dm|qOI39_b vwquԫ\- %p[JD G*#-pj~!n_6@۰4Dv]dKmA1Cl? ڱ/O~ L!զ,v/&lm*o8U6!kJp|雨S&c8gYI xØc͟=fr<.6čoM!ahM3C l "1,KM\[Շ-_"ZW.:L:nc%qbb˦ a:aHN9։wv1*ۯE&t~Bmzam*ַqNF<]0OJ%!C.{Wnx汷vpr̮"WN#:E)H4vc8t TCDرctX+9e [Y}%B-̰ULU+| #u׊.t Ɖ!p#s~ޕmjC9UD3:#evo@ ~s| γXbR`cGI!L c̋ݕ/FTYe.]Wi#RP;v21@38^HX$&*Dz6_f`!yv(p%L'LSUSi)s3Hh*6WuEllOden5^USlQit;K5}N.ۺXBEo+/R YmxO0- c r^ V~ˤ3p| hIs_մcjȃwݐv7f׳O.'@KBU'Ƨ1.$# /nƺ38huL7 =άEpJ§xzӉ,.&z@+16eʢڅ4r_4QyDZr"=C  U&(jA@q.@=).R3< B၌j\:]{.i _1ܳ)R;x!Q4QMMALNS)n.0b&&YSm>{nc,8CKFzy`c=9W26OAuD}_S(,S[s;M[(g~2Jt en  @A ًS@ (<;i}U2oj|~Of T~0^p7c[sBWٻy9ny=9eٯg~o0E*%474'8h;A 40ti~F%tRN% ÁTA Ç:FtK￝yY n5"ctLV¥)6ģ&s& e"Swendstream endobj 123 0 obj 2668 endobj 126 0 obj <> stream xZKoY$wx]l7Yx+c``DYjHZQ~}gF#bܜ~U}W5]p&<şBcjxyqvAE`JWgiX k?~{+<.q!a>nO9YFxlSѥ5KkK?i#)NveR>L>/mcZ#0\MLxp'CROu iôLWm;a$] ٫.?E\[mNkfb
Z22n`0nw٧;C  KU׫fs0U%5vuw%~w1t-50W#> T~/~|SιwemwH$B$JGȫ;_,euA(l`3N<'>5^p=!b` * &ЕKzI-iY7]:=&,;lHu0P`2$ fdu@#IiG#:urŽIvpwaG'SxCR5z? q ~3hH"EuB˲`=gQM_M{J*rs1% }N@זn\w(`P~ta~cWߞޏ$%\{`G,PyCç"(|RgQTcj;F(E97Pr1Xe9 R( {hS\]M[ w,#A>Y.:O ZpEX ,I (&}i=/'-tBBU*'ӣpP"WE%_.hV(Vs Ӊk2!] zY_K ?f7mO}:v\^~,RRmK,_[LPTGǺc$[218GMsmTNjLf8nY5w]N#@2'=B(0^{I]tC U$ӁvN‚+y (BI' (q%a"@NhR0 7`aMCeGs=uQ{_{ M+C!BMf(BD٪ǝ^5G0П4ևg:`W)1 Q~2"*!'cM0l)9$<@flw=fLeu_\ /sIeVinDž ˊ `b$. .NjHMi R٤VQgP.Pfw,ոyvo7tX.kMȑE!4)a4@1Lv6%~҂^2ΜBsԋ‡T.%ZuP(wUvD/:bl}~ \d OY# T@=txQ8n|!K=nyI49ӻ,lۯҟd]Dda6^X>&a+IP 50M'-.gS۲C_?ZܯT ;Z''i_ (Uas񩰅`?a˷ hTp/; q=# N m)X cUQYG/.O )VS ۆjrX! o Դm.U5o|f )}?!${ 1Rϒ(3_ Hjє"E+᧦$ H&+McK.)\:z7xso7“8-zkUq*{c;I%19WnzȗD#>\wҖW؁ٖB 0Ӧr,&TJ\]WҨrFvo9%\JR#^cOB*ەm ~S-vSzM/oAZ%k$-d.눥m<4x%Ta]Aۄ_,ǯ@ubBg/ߜy8v8;!W8MZk a4$tT\Š/`56C (je>|<UYSFJ)wc_E=TEsCONJHћܞGoXt7L(k>i|u~SRmOE6˘P"l)Cp"endstream endobj 127 0 obj 2870 endobj 130 0 obj <> stream xYKY'.0Gn؝C6~f/ 3Z"eߧ]]$x-_}W͏KĒw[|\|\a,Y햯nW] ͔rysH/P5I-~xB材zuv[7<8xNe`JX^Jw*0 !ø2P:qlS c)Ac_pL+ uժ캻vRL=T~ؕbFKpaԱ~^}e)6 GfxRñ*!;<kw>oc^U_5u k SA88ߤ9ƥ;Vm_2hkG d Pg{rS)snpqBLrUX ?OLQMW@rڤSLN |ȓRW<8,! T*"~ _ۖa"X,5P`tʛנ\J7Óv^# ^ HQ0N3Ԋ⼟kQQvŇyp@a^| r3e:ĔU_%HbYXcprE;O}ܷci,lc1d rĒ ;S>8 aO AIq;ak[ڼ  9? Q*2P$h>lL{R 'XE<t6C` 5]7 -Pm0#n-8-' U oJA)EFQWϿ]#gt)S9E%,jk2uk"7֪mKI(T: ;QS=_/v#{j}_n2g>ƛPv}xc5ɯ߄Su)Ybj>;Mxc)"@RSq<Z]ձTA%SQzF+y^:ó@c<ʙ//| h৉ (#4]tɉv@ Tluc-nr2zZN.{ h =2L̢HOzI`{;$?Ty)JBoBv0B DX!ͻ~]g(0ZQ%?3!U }Lw9!sCR]f<{=Eq̹> stream xXm~T@ZnZ$* ;D%,wvy>Zgy~^q&V<i~sGW3k]mb%b~edگ6եo6Y5^xGWR3睈fZm=aW&?Z_ϝa*~U`\Ӄ AF0/͙#oxKqe>j-!x~xdY0+<5TX0)e< ; ς/7 .{C܁lxOqs}Wuv1P% \,D& X+!wkav:8dUFxמn0,ҍK4A꾺ׁH'g̦<;&ttY=Mߛ=˱4@s61S5\0o Bv(r Hn a0<9֏BD 򼴓S 3Qc@Z\`.٭?UZXHУ'-?yԇgahIa׌"m9S?CVnBr.+rjbb@3֒XahR6RsMv|F7J*)OhjxݔCC9\ފJAAA'ͪ}Fz=A9$A%JRHJ;/Q x> stream xYKo{D~?H 8f@0&[$vSӏΈ"A@Oꫯ*P&Ζ'_ONXXf/'?뻓6aR'Z䌓9aF-칞PlUn&>TʈUaUҸzsVޥsyk~ 1RE,YB5ymV,n^p*Ȩ6)S87/yq٬ڭº#a!(冏UX0.ha3e \Ȯhf=,+"U=O>\獀\㡣a+o%Ѽ:e)d p:|yKcfd岹sbəT l{EvD]2vr̦Fj_/w qUu Mc)˻~ r ʈu4SBV.!l^/<͸l:b@xU #:76X?7_50cn"X#16՗p |B$Ǭ2NtZn^5?XZS6浔a34Qڿ| `iS\ǘB+ȦZ,xXb,&<"sŶ\D4Zv#CN7ȧ`iʛO(_x+үrZSAxW- UIp 6[JE> \BѸ͢W-xЭhޗg<G ڀe!) %'ר?>=h'ϩO=dMXn4RZ>t ޾T8kA~2eTa"46l0 f.<`;@I9_Y{`hJ^1\o" yWqI1 ~\1w`+j<صxU⍸C-L{f]˕9;w h(YNo^2K4!T.m- bϼ䷷<ύ<\*:M q c2E1(/6472> sA] / Lb:/Mz>H +iG'6GÕ`#UTy@V5Q O0UlF유cce%q-lizz9mkZc`ME:Xbjw܊q:b_"HC60$o[M%<ߣa1<<VFjS# a@>85 Gz OoTBCj(o("L9yT"rA"Z`!mԝQb##<4.ȵnO,ȝ;K!F\PpxIȆ`D-pON\&J#豟 VT b(lͲ:©j33/gqaB!W>>ak I![Q@`H'=ɾ_e h2ɱ"R#PJF6K 7( }ڭI/pL٭Q@wgrZfb/Z ֹCzӣ?F2T. {$u"1NO2vm- ڵ8qc9iEH8iЧb(x /D@[|b 5O GgON`c! QL.SR8lXԎ6gb,DPB[/gfx7wqPneʙOcȅA,::0ʻs0jUgE}KHŌۜDB?N\nY~u2Vc{sO4ڬ-~Y$)yu3@ܜ6%pr'wÚ D~#(R3'JݏzwF*w&Cd]QHI'jw_L (%:TEAn2|^ZZEdCĮw 0L,y>\4endstream endobj 139 0 obj 2372 endobj 142 0 obj <> stream xXKoHvo$Œ1Y`0ms#2Iկiя ] ٬ꫯy; 툹Ẍ́1I|4:/#h>8R@(&Þh-ˢ$\k7] 8K(H򦵋f<b4z1f"!9#t[WU FTK).̐Ԙ4-$" ,.&Tĝ"2<.SRfXMs]eJt;~yw9@ft4]& qdi\ kwEmVMRM nȝ)+Xј#DY}D2"S>c2&I.c w2ZW1$<EUy}I$i x 5q60B %3Hƭ J ǃUY拶J&h类}.h3 cpv).' 4uX:(bef2&ɚRK,A0OZB+5*SJR:LaH!-uk¤<[: CLLկ(6"U-%FRWu-߲ d`T{d@Y!{ l<sÉZբ?V;$)ȕi(/$#wHk?(놪Rֶz6 RWHx Cer:rfM.=+JB͌{`N-eڃ9 Q>U4_(HGIсmβ602,1a=6l~܍]7H9ͭp":ޮb3 #:oODtF, %mWͪXdU8,8ׂ6.#vVo1c?yd'Y Ab=V6uqWk=DOJ2 (9Pr^C)]G3i^.|E!z?Pk P`w~MG3#qi:4LbVK[|m.3J ^C'{IYR,QM6(y,t=}JH;VuDYsc3b_ȸS8p@GnWDplն_xtՃ1,|!l&pR=Wp@خCcmI0(UkS즤 cEUF  wyJ#i^G`ơ!Im*RlV'ZJH6OOmV3U) ߐt>wGepP(ׇ˗{s m5qv ?@LR,xATC*xn?t(2s ɗd4P<˔NC>lr<{9Fqf_\RQn)O&!zdzϾ ?( B?=;|؀sxGL瓟'FT3d M-[U c>NΎg_uŷ .k}w'>Od6 yKTQAӍFt&|σa nKǧ'Vpðuj1P ,9b8&oIRwendstream endobj 143 0 obj 2104 endobj 146 0 obj <> stream xYMoG`ܓ@zf FPC3Cɯ!9eW^5?MX'٧Ofb2g_'\,W\LWϿ<<y3ql2eweIK^_ί7BV4"DZogLJom8cb6?x}/Wa3)f6qx3/)癵a'967I.;޳?cqW};P?8C3.^1_Yݻ=~B_1 <.C6m7ee%=[rv~'i#d^=?!BS߳_d|Ҁ~|Zje9|/ټl`\fs3`Swer'b tEFE-it݆Q1"կ\&+rwZ6Bx584j]-m±% WC*}u} c`uq|K?Lfx.qpi>_šr aQxP&ͤXette2mٶ R 0oi/cNӢiҩƪA.cy\>.>kruc+(V\"j@7]NNj?9ro^o\37qz,cFRg-q幈Y]Y+ WTQD" bnmPm4VBFǽku$#Bwa%ܹ]6}0 =I̢ED ʥobɐkaq!Br6n*@WRRN~^7uu[iA.k3S sn~أ P4%rM$4en28ġHnj>GюZzJ$>I-S'NsUn"#Uy֌8nDܯ۔: yY6c- (.mꐭeTi= )@FEfd W ~FX:+|m-zY#ol/n ŸK$:P1S, oU7jZx."]U%2)<^-v" #tݖ-B(! 0-px0l@@_~d{DwJ<(gn1sXND)¡I1б`]:L0PMexϤ:{A!T-@dn;z'- AO$DՖ߬ J[>0g71\.C;O}61I̵a c5mxjAcj,cn qxIG vh -Ztvz o= 97Mjnr8 XCUF}{zf<藝ԡ#1ֳAnҠ]D#N2 J>dKbzIdz)MpcyrP(L% 44:+tO,PS`鮍>to tU LikU Gnmuf@6!D9x5IT8"*B@`n0eAl*"'tDcoN=LÇK M{hgޗA9,Z3(GPDL'Nz72UУ!-q'G>lZ`[NBFjN?,@]y/?CwWfҺ[@cgxQAR,ptˇ=ig ѵ96VE)'E*XU!7 `ReO 9> :uS/y)D(:3_Jendstream endobj 147 0 obj 2456 endobj 150 0 obj <> stream xVKo8Who] f7y(i[x*Ӷ==Ϳ59pvcr| ,[6Sƣ-MyC3oQY.K\fe{p3` 8[ErZ}ugQ a69K)5sI<-gZk٤n.1ńSd2h*Z&9)ٿNA8SqK!6hTXHKmVs..f.{8a\#FtƥM +RUmiRӱ*BN[(+(R -϶P^kG}c`Lx<޶0G Wn ѵ3y!(H7L0܆0b0DǚPCa&" iN`[C}臱hч`1!8UE(hpTe/3™>9ES@R~#!Tƕu8 ZSIuTm1ƼdUfrb56 N, >RK8MF׆-i_GeҜB}X0gz =L/h K5T]TԯiC}-[:_!"$f'sF40B[Y#q,§xsYeRCȦ}VI dsN1yGuC]vMXU;3鞸n־Έ['EC{]K= $s2qy_n|Nݭ^=ub-#槙KZHZP;~-SqJ/i|x9uwYHP0+D_IM7됊VhS _Л+ IY}J/`܇Sv0M΁Dl!ݩh@IX\{EZ`vijJI-n+.U=Æu",xYhtyI$HǿFIC|TvPv\J{m<!?/zendstream endobj 151 0 obj 1052 endobj 5 0 obj <> /Contents 6 0 R >> endobj 19 0 obj <> /Contents 20 0 R >> endobj 44 0 obj <> /Contents 45 0 R >> endobj 48 0 obj <> /Contents 49 0 R >> endobj 52 0 obj <> /Contents 53 0 R >> endobj 62 0 obj <> /Contents 63 0 R >> endobj 69 0 obj <> /Contents 70 0 R >> endobj 76 0 obj <> /Contents 77 0 R >> endobj 80 0 obj <> /Contents 81 0 R >> endobj 84 0 obj <> /Contents 85 0 R >> endobj 92 0 obj <> /Contents 93 0 R >> endobj 98 0 obj <> /Contents 99 0 R >> endobj 102 0 obj <> /Contents 103 0 R >> endobj 106 0 obj <> /Contents 107 0 R >> endobj 110 0 obj <> /Contents 111 0 R >> endobj 114 0 obj <> /Contents 115 0 R >> endobj 121 0 obj <> /Contents 122 0 R >> endobj 125 0 obj <> /Contents 126 0 R >> endobj 129 0 obj <> /Contents 130 0 R >> endobj 133 0 obj <> /Contents 134 0 R >> endobj 137 0 obj <> /Contents 138 0 R >> endobj 141 0 obj <> /Contents 142 0 R >> endobj 145 0 obj <> /Contents 146 0 R >> endobj 149 0 obj <> /Contents 150 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R 19 0 R 44 0 R 48 0 R 52 0 R 62 0 R 69 0 R 76 0 R 80 0 R 84 0 R 92 0 R 98 0 R 102 0 R 106 0 R 110 0 R 114 0 R 121 0 R 125 0 R 129 0 R 133 0 R 137 0 R 141 0 R 145 0 R 149 0 R ] /Count 24 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 14 0 obj <> endobj 15 0 obj <> endobj 43 0 obj <> endobj 47 0 obj <> endobj 51 0 obj <> endobj 61 0 obj <> endobj 68 0 obj <> endobj 75 0 obj <> endobj 79 0 obj <> endobj 83 0 obj <> endobj 87 0 obj <>stream AdobedC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?GBVL%\`/'ߥaŗI3>,?[[k0ţl6h2OZNn} ėK _E`ZhsYH%ϓr3lz=zVAimEv\/"XRςVi-&M)0BFݘqעRäY-𰿖Y- yɒGE 䌃=;?gB׶0XR=(/"SE8\^GĦ=Ȩ~wN*i-fo-C"ŒKy1w?N ,+//E/, kiv#Gm __???|MqB;_OG'ςc,R>K{/?(괻 H<|WMK>+}&@괻 Kw/??;|Mq”QZ]%:|WMK>K}&J(.;Ne%G'2ϒc@P>}V`;N%%G'Ϛc@R_U^g_ h__5Ȋp괻 L5|M>k}&!J(.u4|MK>}&J(.?4}MK>}&AJ>}Va{y:LEG&2ϢCXQGivs__4a//?h.G&ϪC__5ˊQGթv*w:KUG%ϪC`R>K}bs__4[/?iEV_X-}M/%ϲcjQj]Γ1W//?(Ի 5{'%rϲc18)EV>SU//?_Jeu\ >KSQ/?_J%u\R.^C <kF;RXDBߧqº 6yeMv3q+NGN>ӫς«O^Cm- !'o"ɪWsk|ˌ #,@pxWĮhݬuN2Jߑ[|G}VgZqKm{Df7*ޫٗ9'?ɨtN}ViaWKPV9\<裑Nye/ȶ5ՑbmX^Wץ_Yt%CiAJotcX~Oc ==+-Ntl>ooˌgY_Ut6iͮli&?iyP$q`n f5;-;x[[ۂ,xO+[F?U/"7WoK}n:V&XT)c$(I#s*$kM5YXydV"7W?ѿ"uh,M-:;5(LpT l%28<:c'ROMF'Xg̘*TrOC/ϟD}|#5^.Yp)k"?Ə>ƶ>6yȥEgGOKΑ>Ə/f:#}?#ih>炔W5ϧD'}?#]^Şz(_?hoIOGiW>Ɨ'}#]=?Gtȍ4;ϯDo H]#_F?"7}$pbWy>ƏGȍ4}v`8AN?ϯDo3}#/_W Q]>Ə 3}#]# 3}_7}>}Z} RvZo4aiզqb?hӿoզqaϷ>GiqWcϿ>G&>/@>>)Evؚ4bY(O}ƗO}ƏLiEucX}Ɨ /OɊQ]_=hǰ\>*)Eu_o"x4}r99QNdX}Ə/ Ss]GMhʲ?\a}JsэoL x侁^8QYw *x4eYyưZR7Bt[f-i_QӾ$aShQ.p[h$px$q\xN^(.{q5g<?q- Z2mw 2Î~ ʳ?Vo;_x>ߏL9-^X]de<:zg=c`Nx{j&ӵM8Ou^_*EoK<kP2p2OZ^_+#]mn1#4'|uq*ry:QY-`BG:nqz?:&$Oo9UbW$R$U,i7130WOgpdd m `LWW7*\!G]դ_1]aUv$1lsvr-鸄$貅P$'!w1@llXRZ9n|(0#e _kKQ_9d3@@QEQEQEQE1Q@Q@Š(((EPEPEPEPEPEPEPEPEPEPEP8.nm.ѷ2pd'{@M.^PP27_9G{@Ki⌇w U ꤑA3X!XIy[:̽MQ^&*m<~"Gb$pxpN}ENueiUѣC[>P@Ienr27_9Pǩ-F|ՐQ]2 0 vr* + ʏN#cGC W۝pTz\?R?#r=qkiok(ݮןW ^_+Vw+1X]%H8ʌE43R;cLs.g9]g|cA*)b 1b@I>יo.OuIm(K+rH \nK؞c(0?\ڞU h"ƥ.p 8Lo Q+="kڼv#H@b!Wm_/UVf z`dtE{hWkR8ds3]BO#@)?G75kimnic6K`?Ue@3Ĥr229}y yejq8p Ǡ>v#6:ԙU2Iu9M[- yd!gyI|>75ON/;%gߍs^*=f0f.W$`Nx$ 2vcn$ I>Vm':''ɃzҦ}7@_yC \hEiTE*غ R2T׿{o-$X::)` a8Q֠,EHP:G̓{ck?YO_*]g)?4Rs2ȳ9w8 Ah&yІU¸49Nx.C Uغ R2Tiky:]FI*$;\YO_*]g)?+{j_'Z_]g)?im[M}噥gٳӾ>f7/EĒ4:awv VqS*{5{n"2yolUl oGz7׮r<=f͔0O|żBN"y[-SA ڬ4sl3TyXH gקh'z?ѿK3sF&'$dr~f|Oc9sJ4()ףE??_h_^k*|O_h_^k*|O_h_^k*|O_h_^k*|O_h_^k*|O_h_^k*|O_h_^k*|OXPFMqZq{} ݢѤQШ92=(D.nmxUClx>Y)A[!4 E,B[YԒI>BO#YHKjSY?U AG_ig+ ^Lg9A(Q ;ICFG0rc6o`PX MAyxf)a,Y @'wAIE42M%qhYĮ 6HlYkRwӥ Da#imX,ga ,G2:6ɢ<}[FY$<#}:bXa(a- ׀:ej٣V?[MfAym p8ɬ!E|W*֟0j_Yzr\yu=,ĪߟO뎵],G+ HSKyϺME}ICHDl_Q>}5e؅?uveiGpA *)->8㹔Xc@A8cB$8͟6/_bu޴72P-`2ʬ*)P grqsSɩOsa9W&=Æh$Al_Q>}5ssw-W,nRA^x$ݠ ؿ怜7+(*N3I?贠eFR=q#ݮןW ^_*itGL@u yimčdr芬A,FHg=J[?n',HgEF@IQvBS$lPeWV# Ҫ[* 0cn?{`c7G Z3率:J7I]YVR  bZB9!lT ,m}k8LVH2XjFI$@rH''8I?o~W(+Rmx[ߕ 6<--c @ E&煿_lPI?o~W(+Rmx[ߕ 6<--c @ E&煿_lq;.~d3@ TfsZ&BLSO;@f I!gN*QA(d'8$1'y=qQ*[$R' vOw+i1`ʽ}S8RTr8Ž=Jo6HU pOAQ=k0,db 88T9mȡհFA@ dܸn@ڮ_`-` .ARh TPA,Nse{RgfY'Hp O8'֊(UB$O$z ( ( ( ( D\ɿ$O\BJZn#\mn#\mYIEheKӤP @fx551hrxmgTszV d+yӥFF`J pxY1.ֈ6]~#$]$[El9AP61|a~U*^"^/$'7˂7Q ӋZcMF"8/1sV$kZ2 q#7.H֢? !o}? !o}Ӭ#~_Ei?3B;ԥHe<:ѹiok+oJB=yus&В^_*\ɿ$2yua*cGcb2rQNxͣ'>% ͹7q\М@_y*!$XqN}K܇}@| l dr͝ߵ[>63 8: T)m p!;ƁA88feSi4K0;mP2ns/\'44oѬI."ؐBl;8+3t7oNs>FO$pPHTQ@Q@Q@Q@Q@Q@"oR'M%-7@V6Ju7@V6JB:J(2 %{;[v/8݂kd῝:!ܦ*$Q wջQ3=08=n&7eӣc"yN 3&('VfE9b+gT'c ;C1eP `:ީy"8;'H!ʳ zv 5 aB\69V bODd0S+b¯kZyUf>wJ MsG$;ʴNK8-"Ҕs'o-'ssSXn/ͣE+ c#֟˾qhBqAiϷ1rx}%ڴvB8ł#Y#|9w1d$W&ZhgyQIBHmƄZHIY2 z֯"GxK#?E4qst) (M#x\]irSH77G"Gܢ0?%|3[rKGH7ILbt5ooSt5oo#( Q3=0Pc9o,c \:0 H+ҲlXn&ݤ8*U~A=I?M{0U ŕ@'TEqBvN˶Cf {W%X"8ʣTO d]J{oyU,}O@t˸66j#]%IbW>P?Νŕwvy$L[t돾*} Yrp#H%r<du=_V-`wmLqW=`=sҀ \DD8l$1s]fFmp@aб-?{U ps<[ۋ{y㕔+nGʪrGP\'/'hYcFxURp{IJ2,m/-W2p?y;m3I+(,P,8Lx!6nld$vuՅ*n+$erq96H˜S^R7m7CAa1h7>݄3*XNEk|q7\XU q'm&"9-T'hOJvtq0p&#sc=2@)iehmR;YU{ew1 }ks50o 0U]c%j:pڽF9VdZM%inJa* NqwbʠK֪Gy"8;'H!ʳ zzT{+A$6DqF _uV3&Ukcum Fd|䃃I  Mعqmsnl!0G 2Jį|~';+7rOmofqd{u%[ϳJ | 6I{ٵ),&$hMˀ Ǥ{B{e8bđb'LԭS>HU&1ڤz(Rt\4rɷh'#oiFb] oI `7E'< u֗ib)%Ca8< RHu'*Mlϵܠ8=ݮewe\"NA~bW331_)`pľ Z^ۙa[E,-vf-{t&kTHɊ#RpYr}8,u識!t "䬊Ȯ60~@OcU-/RMۺ(1 l610r͸`7<` La,3Ct#"Ȓ$aԌ`{ ҆ۄ4ˁK#ă[1 YqЉ #?&6w5b  t&9q6eYZT 9q^^ n>ۧXͬ7g23Qd ؿ6ȯ ut#!W*}GpyQEgO=oo? /OnB|9{{{|}1cz{t폔;x;c㠧W.G98ˎ1Q@Q@Q@Q@Q@\Ǵ75w?7x!wT55!PJ]J8`HY04В8=} Kkrn(-/"–-=Ƹ 6#\mwB0&+xYH\e݂x(h"Y`%F zRM+,qE9gv8U7d9@Uc(HjBGeY#" 2IB:c6vRX1 $pݙvF2mW T Kdō!*RB` r@ #FweTPY2I'ԯ\L$hm%H#R'k9@1I%ͬ~\wInqrȱϙ@|۰FOPqtVMZ]IJ'XI)78h #~d2#F FTo x`@H2AdGPhWFfUebkA*pEsR]iL>[XXu'S0چS6_*321v9`v$FʲHC0;f-m[(@%Gl0ygm^I$:G#/h@Ӱ99#:n"20 Aur],p*Bφ !frXn 9n^O` S@LwFAhEQESt5ooSt5oo#( Q3=0Pc9o,c \:0 H+ҲlXn&Oi%FvN _|h8RO^c ;C1eP %U#eyPrYcxe={=e_3a9HpWhʎXHdzW..n#NFO]kN^+hT>)Nxby^s]Y\ F&Rq\׷L藷r[\d,#*h$8Ӎ=oXKe1Ң,O n#烆kin4S0dy# -r621:o iϗ Y!gV5b ,X!yB2,Pr6N'mF%O9T<X+A":6q_Fh$iʣ(YdLj øĖZ4r- 0@@1)5uZHiXV6arx<`լ.S;F~F I qNhvf[Q;+uNFUSLf;K M,;I'%T[;b&%g& j܌[MomGJb`@Æ`@k%}v]z䍽X Ni*tM9(/-T ,'>`rZA{BdܒѰ8;X15 PjN(# [veQճ8 nCn["ZEk"KaJw1[qDXd \%Hģӡm'cy=Q@.3d0V:ېpGՊ((((%:%!%Q@\Ҍg(F11]X2JRPYm[cf;l;U0YrB>6moceq\WEl;{ u+51&HqR;pjt{w,Ӝ,A{1D>r"Jo̡.?&%[Zn:܂شrr أ›i3QMBdF.s7JE&6-?n@U44 &3sЊd p8{ DIi,1ʪZ) N2NFy`3bYw Lckg8Bgٳv]і2T9I9ml85jLyrdP"rRd9>UP[[?M7|̣8kwfHQppA4!u9. tF&AbrڤI٢mm-de2[‘)$eTpq-?N]!>k=޽V>1=vGQOwԬU 2x<0GP3o_AeLd.ڑD1;T1Au^`6-X2x|p@$ B )L% pф p2$<6@/$W8h/vr3ʶdrNg2ɵpT_PSYy\z 2[&dLm 6i<6ph^~yPusmQtc}s,l:DTy6'\#TҶh  }91ky EIv[pwZca~85 n"kx<,jh 98 @tGb@D؈;*$800(( XӶ>WHO=oo? /OnGr?lv#\tGa!8Ժf5+v6H6Ǒ9=EE><O%L4@~b.d,W<vHqҸ[WZKMfKD~n UէA%1^~iEHNBt-6m/38~kMuBQ$OGt]wa{b>uw$#GSM:;d'U<⥏Ext$xRDNb5"o4(@(*o,ѝ]69QmggS$*~T1AG~*^jLX\O_6ȼ[[n~B{*0ۺ1ޤDFρ̠>0`@si[֩L<Q6PJgSӭIVMǘҢ5!u,PI!9V9d>Z$mmbZ*Hʒ#c $1mc$7 q&o>A aA݀AaYj;~7:8t@Q@Q@Q@Q@ȑ{z F.!#}5>nP \@ Xz&U#E!X8 z錀j^_Љ1Ԁ?AڝTz?(c ( ( ( ("iok+oJB=yujkB0YIWݼpG*-'S,7ח?#~U){<xزO!;`VbH‘0& $sC`~n#y=3p*jv 7#bd_`CC9)w8fC7) Hqg-QYI},/*EU]v+Fp@~j̺J HܖP6bJBw0u+8}0g ++ UۀA;J* Kb6R@,[ m~lpF3@(kڳ"]Fк$ R ܑ<K"w.̌7U܂=PV{j֑#mܓ# e B$:)x+ NMN#&DA?NK;V0~1yT=Q@Q@EȱVɷSR-?C:{OHGQWSYr XA䮵;Mc, fDBpu=qu7OO4rC"냟Gjs9^s>E^SK1#9;3EbEv_ұeJ #bʨ iS_=6_hbL34Vċ{A|g\3 o;lTrir\O{I;' @hZދ-N*Z۬)w9֚HQ{[+A$`R L 1%ciwBح o?k@m//Gbk5Em//Gbk5Ei[j\_)  =9>j=?qx|U?v=$OooNݱ[7@#e=1;0 =?%{{=Fhl#` "ij:ݭxؕ=cg j.mŴ/2f7 L߭ϾtO*1k,D$lX/p;Vjoso?h(((((+FR=q#ݮןW ^_*cDחO*$h+w9Ӷ+Fku:)yl^)9}̥%JA#4Y )ck3K!Q2vqONbv6;$iÐK/.C 89ϓs%xgPybC4##BK *2wZLUk,6U #mQ@-4.IrDd.T<98#y}qw\$1'$h ]!`)sloon#R:FINI#` Y IGc @ `<ݞeFt0Ύp%k7K`p1ҘnJ)xaY݆0cNAwآ3IiVK@H#Cp`y;`㓃Ғg$jK!,w8>a*(((;JE!eK2yJz"Ub fVk AM/Bj /jlbDv;$[hz}>74OԿ OY?R)?µ~74}o'hGϖRjo'hDO+Y?R)?d-K DO笟ѦWϖR>ZI笟ѣY?@_>ZIk'j_'V&FM=dek'j_'QZhz}>74GϖRjo'hDOWϖR>ZI笟ѣY?@;$hfe.X66 ;]icPOʥ@2ONϷk}o'hDOq96r r0zS%tZ, Ɍko'hDO(: =w&FM=d;lA~8û08$LaEPEPEPEPE]{e=#, \3,ۈwt<fEo./#s܎Nki31zS?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(O ?>|#(H b `7Ed `rF09jh? endstream endobj 88 0 obj <>stream AdobedC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ??BVLAqҰbK@;ncߌ#8q`Z=:]mx3 !<` Rݐ5bK@/"xfpᶵl\ ʨp' X\iw &T1º pGhbY4]AV=،qf $1dW _E/, +gV8YeMIIy]1qvnElyA FHv t''ԟ4|& TXSB)?K$dvQˡ>wb(W(r#(kt+__4}//?·G|릚[ G6f\b܂79PkRX^M3IpfThÑ' УAr'ςc__56tM|ՊO@;U'8'qVAC[VH䪖(f c$OMj{/?_N\[%+}&֩ܤdd˓2'MOuat1H]yd8VH#F:W3{s//?8VU?9|MK>k}&@괻 O>k}&y":Ҋ_U=λY kOso_4K>}&1J(.u>}&)()h.1}M/&2ϢCTR>K.O&ϪC__5 pj}u>}&KU\( ;?%ϪC2)E?/O[//?_K%e\ХOSY//??+}MsGթtK>&18)EV_Y)}MK>&J(>x΄x__5fXkEp9P= r·7׿Xjƽp2FkԜ[5>ӫς¢u+Ky'4 Yʇ<éM=w}=$19YY ݑcryz^]Y#`JHsy9p.ǡ\³CdigN>  g?o}v6oۛ83qXXcX d*01$ `xoBc{W6ބ' =?1\'fCbr8ں??❊ԭs4چ<-Htlg NuyGQ ̅v;$$RpOH:֕eΟmmq3Ќk3]|+U*E'M;zz@s B8Pz<D7:Gai-L+dI=+_q$IRE@"7Wj+g%jKa57zߝ ;% F(b```ȹ '?^\fѿ^Ι_~/ϟE}|+TkQIrm#+hEr:b2. )du Z?"?1ϟD"u$9]s^7$MN1H RU8 Al;>M^)u+E7:m9<1ϟD#}?#gh|gSn$ c %WGLux5Cww{9K#qWT3ϧD#}?#֊i.Ik]BjmksHX݃F:J{ Yt \Ae 8”|d,NW'ckHOOAӦl@g;Tt-*]JWM\9$s6hY\\]A,  < k$i6 H\wx9oIOG#zOGJ-QrH,+=*{i!fi%,+T1s@0]je%7Zі@w]@bORx:_G4ȏ4i_j+q{9p+wJ_G#_F81@/}#/#_F>8A֔Wu>ƏGȍ4{ 0`ih?"7 8J+ooդq"_-7}?h8J+ӿoӿoe8WcϿ>G&>\#bib 9J+oO}Ə@>3ki?>G /L{c}Ɨ!_Ssc}Ng.)Et6_oɲ?\`mwü] ۾3~5e<?Nz_?7g<r7{ą^X_r۰>\Amd$87 ;sX>*l̶$29< gvN(֛+.?WI77Sq.aHye o|g QK;۠[igYDGfB2A֋9!K'q+^Mؐ8yaLSд+{-, V$7seʩ'w@:qW]1#a :n<N}zsT/5-ߑ,c1yRn%v ,y݃1րm+ᢙѾ8ʑp[*oEtqsuO$Q^%[Y@YFDq?]Ea+ ]'x\]nQ@?WI77[P"O?U`yq~YcmKVGաEX2MiXZbkwF`xש{Ѣ(QEWF\W_?3@P^_*yuos TiJv@u*zg{+/vHtB]@A CSnտqM0-S%Id,. p={ݫѻVEv_]<~БLMwNտqݫ:]..$ 4 d Rq?_&տqݫAT/5GVv@;@G\[w.ڷ??]tooso7jt}//=}/{+PiN[} ~zVuyyv@;F[w.G\[w.ڷ??]tooso7jt}//=}//=տqݫAQW?Vv@;@G\[w.ڷ??]_{EOqӾw5 tڷ??]o`%:VwWzz>RmN$/&2(&Cy3C< u#}*nТտqݫ-ŴH@wpFpG^OU߅ v@;F[w.mgki gOIqg ̉$ht 22d7v@;F[w.o"2Hn 0 -9?Wv@;F[w.A-RNf¿tnտqݫ%vO/&F$d$uSU]ڷ??]oEUݫѻV TU]ڷ??]o^kq_k lN>?Z??3@wVfY~ xpOkNyu kuE. R(i"2)Rd$`2s5XA4m`iRf P8v H9u [IDh%2{)rM-9&&Ӵ-aK3Hdv,e00ăAOn/QQWJyGunnU|ʙM.sʼnau4I#2(!KGD'9 TIF\\J\ lFp7g~cL>]*9$Uhy"&7yPA#$,Eر{jі( oUʃ7'$if[zn}qڮC$W 3\\K*}sh@Q,ʽeT壼H<)R NB8݃cPQ@Q@Q@Q@!KIIeJ|;66XČFyOTl( بFT pGj6 Q N~Np}Qx9J);03=kv˺^j} 1nI2į 'A@ Kov-cf6>l@;h[瞂֙ +4#)*GT}܃ʶHrr_ɕ^YJ̪Ƀ\vPԻKcE#p$GQyS)ܘwU+U:/䈓ʘX03*iQ Vyq836vds[i =.'tCBb@ ڼc ( ( ( ( (( );pH*C-e$2qdnV +!Mɴ>#Ff?ɮIќ̊MZTӺHh. D1Z6 `ncBWr:, 1t<`J*XqA:6k3ܻ;l|͂2bq1%[$a hN01@iXTn.ck;o1$ӭ =qŘ 㝤8volm oCCjhuݺȣݜ6>oCJ tUF,6u۝ّF19hmBn]ݙchQ/-^QBn*8$F? |CV(((yu/5y?`]?'̸$ջ^_+&;F[$IVQv9 צ;x(4͡c xd)0FF0psYEaԤqXd$=3Q?eӳ_o4`SG Sy`}Pr9Ryְ v& o$6쌀FIr͵B\8n8'j ᡎ[e^IH9P܂@\AVC;T*ѰubI8 AFmY-$,;S1QFI3$LIQEQEQEQEQEve 咵ʬ4`]T$g=˩ӠU󢀉luBI$zsHYbOYq;d⢞W0,Xiyj6o߳ݿێ9sEte*(S&FC0b~5*Z}ŋ'rAP\y/m"h{i$uP@ۖrw-{w ^lΪzd S9[QI-EU1vrS9#rpO&]Nln4hncxFx~PT,E3Yyv@v!l+vO1e9%Ecr<2$qs幺yE>3d$pUOY  98WzQ"2`@)Փ#{ !d0&}5< ,W`:1Tm~ȒƯ6\F,A=bmwNGl~mcna1$n*H$c+k-ݙa9 \Tw*xKѸMmZbU4^+2v#$[M``< J+2C FӐTyƓweyR۱*6U,D.yޣۀG4#I6_bP34q,K"6Qr4UzXV+ϤI W-g{QwmnN2݂z*G҅N$IT㌞+FG347$r*.сHH%yRiʇ<# |#*r>R ۽/ح A+,Fm4DbH#p m3T2+nf`Āv );o4EuV)fv2wYLLAg llXefVgVw*7xq4)-?@&-̆6X'[z|re9PCb!伛^bV@gTl8!bU819aňm6Z(QEQEa?<fByu/4 B4]FrB팂p_ >l;dV!YFxGOojDC FU` ssFm47>twn.I8s8u1ƶrLq\޽UZQc΋w<][jBSX *bEb%O5?xn,Y|#crpFN@OZ]jIH䍑d'*@ qf/M#>dR \8Gl*E@mo5kA,e،̪32NC ΏuqN]ây[D>lg/d2 Ѻ9F\ڥp/$\Xw~(9Zi2ֲH.E䘐ah@v"om$xLr@sw2@/EQEQEQEQERR@Q@%-QEQ@Q@Q@Q@wy?`P^_+y#+0=Byu-$b/,Xc  F!Xwd&;E4 HpyӞ[;n5orrM & HBl z cwF, y@)<0:G]5fMܽ,4R9hO'@ p#Ə=c[(㔕o;I-#9<;CmO ر\l(34\7c`hk=.m2%$ΥX]";  8> ǥ+"5, 028#x]H,rkbDٶYbsɟnXztvKi4ˢu3 U)fnPEPEPEPEPQEI7wVj\4TmvdqS8^{H7Ť&hX`#3R-Q-H$b'dā`ϩ{Jέ:$K%e<++g,A=;q |.E=UxaО!bVH/m5ƶIn+ڸ 118 cFSoCT 8<0U ̮#0f#Qrrzq2yrcOM?ax# wd+m2b,9a*եC5 ܼI tlXI\mumZeo472, V3 f=e ` !m[fgsi\/6t\|~Q|=nvCEjG䜁d(((J(g%7æNHzq I ̌H`q4-kh:<X 5SQk 5 )')?Ig@-PWQ&!-*fɉw @N};kAi1?9۴41ۧl| <=qӝ {?ޞs>?:{t폔}1ccN@$t[ۿNvt}z{wL~XӶ>S厞;cΐoOn9yzߧ;c}1ccNN?:{t폔O:@>O\=iH~폡厞;c:L~XӶ>P <=qӝ {?ޞs>?:{t폔}1ccN@$t[ۿNvt}z{wL~XӶ>S厞;cΐoOn9yzߧ;c}1ccNN?:{t폔O:@>O\=iH~폡厞;c:L~XӶ>P <=qӝ {?ޞs>?:{t폔}1ccN@$t[ۿNvt}z{wL~XӶ>S厞;cΐoOn9yzߧ;c}1ccNN?:{t폔O:@>O\=iH~폡厞;c:L~XӶ>P <=qӝ {?ޞs>?:{t폔}1ccN@$t[ۿNvt}z{wL~XӶ>S厞;c{o?<fByu/4 B .n-m4c==Ei? )PݯD:mnnH&[wgTKfBIV^dF{p{0"Q7çl f(D??P %A:zvdF{p{1Уh@FH8g  %A:zvo!BC=i"Q7çl H8g h{G} >dF{p{0"Q7çl f(D??P %A:zvdF{p{1Уh@FH8g  %A:zvo!BC=i"Q7çl H8g h{G} >&(`J9'#`cOjC=h{G} >n[}(jA_o.D??S$$F  '~tW>n[P?jA_o.j1o.+!h%uʒ)KkC~n[wۗ}"/_ E7>n[}g(rϵP~n[Ι|nldfhЛRܿ3}g(`?7k-7zE嬶kV9Tb́k # bIF˸21e9 y?`J54ejhfK63yy%@޵nןW qoMm&DLc;==D&mR[iVL4UBd;p=/[]uD\2r#s;%I$ʧC{,lgX˰%0I9#$@o]!x$i' 22Tc# 2A  4ktd4N K2SPYxn-ŵ< |If b_:l0lEި Fy$ Υjpi $-arg( |fRZ&ܼa8`@ Ќ:Yz*\\96;9` ATSG?9HZ6bX)DS 8A<  EFg#@  AbşыPd9$#1S\?F-[Юe5 d1z tB,J I1zp۽G=Km(gH8IAz6lBeA:s4[v#'#ɿX6uTFyl9Hi7GNzt愿FR6h# %XFx$+.8n.nĩk%SW!V6 $`猌"_Ȏ 'HqyEtf[@B}$ -K,cl {}3Umxfv "55bߙsC9&IxWC\#&? P#55U<f=ByujkBaEPEPEPEPb2IP 0G=zzV/m5yw"IU3YI֡v24l}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COKڧۥ_ͿƏK进ci;T?? Ml}_Eht?COUG[H}oIt!FUI#{X>ZIb/TXUwќ1 4QE`!+ItH[ ֙x{u,Fp 1ϥ76ݛ@ǕOy^*_]>m7?ŒvosW羗?Qx{t 3mٿy^*_GOC(ͷfP1x{Oi֗Wn]?-s1z6ݛTI["m`IųŒ<fǟ0ץWF\Wz!Y-4+,;c@yX@‚;@ IX\*@,# <`9#2=vG$1@,dWspcVs2S$3y~`9ǽgˤ^%̳f#AٕB7_ )Tt-v5 #(%%R `|hJ+fHUm+g$r:"[z}ф,nY@)8 rHMmm-KxD18fxv[[3g|grY;{ITژ]̟gml |gMd|3@$lp2q.BX- [5ATDۜts1˦ηWbdBb I9SԎ(n(((((9 \37$<Mj9km罂92l F|;@tbްXMI0j դo;o,qI=I&ƍs槬Km*KnBgȦ3J( ~CS\*y4MHwV8!IL0ǧ$1H4ᘑ 2sМb܈##0*A eɸct;$ P0TXElN$=zlzeMDABN ^AKy`I$M2T1*HnXqz&h#$C;X0 Œ # @fZ?֝fZ?y?`HwXл8$74 B),< y>fow@+C3z??;נ +C3z??;נ +C3z??;נ +C3z??;נ (0 ЕL>/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i >/ k3z??;נ i FFRG<ҭfowGg6EhfowGg6>i<,vv9'6cQaXv⫣^m°KQaۏ 3z??;נs /Gn?*_*?m^9+TUVݸ?;ף3z??qRU=Iڬ#H[}NNxٟN L+8_!,\Q0R@$Hf'HS+>stream AdobedC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYs" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?_蚲[ZlѴ*''# WV_[|56eoqU.5 ˛WZYɳJտ畗?Ut[In"31*~bz/^OIG|Aap4K#*d)Ҥ9Lr*jVVrl27Pf@ ]_+i>я.jB-xJr}LO5og~y+?ƲlqK^x⅂|n% WM]`[46+-\O%}I^ѽy>?;տ畟?K ֫<H4[%>ڗ"$[98'm|7.k3y+-TRn$sXѓjUVWt-Ŭ/Wb1²OcW_jUVF~]bҳYvO=) $q p ;P68FN:s#TijAtc7?畧?@^RyZ&PYrңu^ZeaN :x!մX-Ь*r^fH:ȣ ^oנxP8`\XHUNG\Ƿ'=Y>]Q߭]){Pzp1T\iRNܷ͛z_J/o~>^ss[߿(=-^(SQ{zm_vķݷzŸb^"s-OPYLmf-#91U& {^c٫v[8 L1,y ݽ;:QGA9R:KJkf)`ň-֫um%,u p{[\y،1!`2GnZ+)<$ wm%G7{%r[{鿓Qu]CMX<,TF@$skzh1Y+.ʯvK6X.$%$.I7JŬ8E1$tuS#M}_WMfyl+Y òo(cCʓE֍c(@*0`uߓ77¯w+Ÿi/^5in%{<%`EBTm瞧N&{yVvH냎ڻ?|-zߥ kN<1{7{d+b]Ob5\pPAu_?|mٖk~W)\^Kc}Ak2[TȦO5(}O#4Z"Jʣ78*zt?ٖk~),?/Vn;rĦmmn4hŰolZe[$}8I^9'Ofϕ_6|Wi)>]W?/uQ X PO~}$S?7|(e}FI) rNzic>VKNr95e{A¶ZuL211~`vbs[x4 Tp0v§=Tg[b$_yfvs]}ߥ ?S=={9g 2M /d@Ҭ7ٱh/ګA#o(,2HQg>£BM;JۜSMx~>[ cӞ}I#VX$cng5}}-`H?W)'B}b=B>Y y۴p*h5*Ok}g '+A~)~g>߱{z}b/a>- Fks6Gm??Sߔ_Ws,gn͞:+ ~R}}`c*.1VHwlҜ>}c)~k>߱J]8R>k>(C|/KȊQں߱ϴ? _ϼ? ]a< ^o[ Sh27s?PkEow}d጑ɒ# }}QKo\' ˹ND[&$2IUg0,ҢA<1+`1=l}}QKoSxZ57$U C{D8XH[v: ĺ%۬#3o`O}QKoD\INJǖxFK(2_?Ebjz!UtݕQAff $UB'iwn!n7yn3qʥ4gvUE$zY7Fs- $÷j"$1`N@9*W1Gtj\* r0Q\j:<ර8 ap,JdY1jFP%m,. *1ßpEe_4w7"j s0Kc *swOJQU>1#FA!Ab$@+)FAu'7v4%IwU s`&R<7]Kɴ v~nqp2q-33o1b <\2=sҀ76v^o"LWq!^%ΥNI@Q@Q@Q@Q@Q@Q@Q@Q@Q@US<ӥίUvU^Ǧ_DE@̽MQ^&*_̽MQ^&*e}os+acoN3ހ. <?U量UU@IV!T I$TW/u`y ʱEQR-\,^qQ܁Ys3z|?q]0<2_?E+)B^EFgWdRWnןW ſ1=&];dvf>q}kEHehRf2=+vV6Zs$mS6Dq^IN63OG̡5;upxFP?H4[bH4[b`Eնii~LRBvp}a#:QVcd[xU`Jd0#؞(H(H+6U-%3V7Cw,N;gk/%RKWx,  ug$G-URФ #;38xehah91PFFF2Z)nKs6]gU᱕ R8ʀdABABwwyVy$񧘱! f oSGJequsq5 +D!{.ݥPpl3 #أ #ث[4\ v$3 Sr7oI:7rF,Mbt߷/̂o!τmmǯ?$G-G$G-[];cl ;B.> 1W;i:ծ~-z>g(̽0F@9H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(I(I+knKD I$trh 'ثGsn8$+{>-.TUFBB0jŴ( I$0-{~Xk+Qy-5W<6jrH';G +bYO_*ggK+Oy~,ݿzqCYO_*]g)?҇Ox/ͷFvbgn899= sغ R2Tb?1IPAEsغ R2Tb?1IPׇ+M3EP74&b A'ҶɼW#%AQ/_^_+_/UwV7_--o$o2`UU3& pIgDZ y i7Zp c 3ui.mZ/tSU!I=`0FcV]V$r$o6(|ZnV0g*wp>e>;ArL)y\EQRPsNrk;df3f8$xENn}j-qC$ic5yȩq6X̏e@+U?y@l0 O{mm/٦*Y 9XS Zuaa ̶FfU I4]䰹P/8kw0MyY?\}խ姚Gf=8O&&lῺ{KTVӫ­$+*`y \^u:Dow.tPuu$sHm,1%7jΑ *ݙYH$1T. 4wqMbIVrH nrOZmjW[H& eGʅ2`6`iEƷlrm(Y# V҉ I}(\m+z(<^I}Cn;ca n#s9 VŲ\m,n! ]ǡ9 ?jE q, oo-߂@e@.@lnl\wqtb@^g1Rj6ѾK-skiAav$CJӠ&_QGd|"B=~yuoȿ\[V!X"~3'u%U 7tbrA'96қ0bvyy~}ێy݃uguAz&'(ʄ}L ~s,&qWe_E3=ޛ݋q(C@!?{UխiQO~bK۫9۬!eRUmeA98牧fo&)$EryZ2 \^[Qs kZ~Wqs9m"+KWia8xwI.7[́qNG$]ɱzI}B[[9Ÿ,BC0Ap>Obn͎#/, XKpxhtRj2/>@88^zAo%m"$8Rd{BU6 h[_\5]Z ,m,[evPC0[92Zkef,ۄ5,F`#H~ICkʹxg,ABPdd4Ҧ@#3J'-#˦)},hei$ l|As˜V+]2jcXqPG| ӚīydIW҇0v@z;+kTn$TRLCee Ah((((((dC"89t01XwX"Wۃb࿰Pe@m!s4OCwѭL ZXӭp\^>dg9{.{՚( A Q A V A Q A V A Q A V A Q A Vo}k{8x i b8;ӭmEy7d|"烍T 8<0U TialV#Ǖ3Ο1von~ͥ[Iu2eLGdppq' $;wQt2KFd,vu+Ub4P3bN#jn">ZO$0 ߀} I˩9kuFIiK&ܿp8mW,%H\yfgۨ#hi~So_|1jh'uLjYf199>_r#Zf(XCrŜXϧ@Z,P[\F %,X@ʐrs/CodKDyܲUٝĠ@VOL-ˣX!gYC# Usb e=~ÿ==YY? /Ona,4bk " {hVmJ[@r=WӶ>Xn=ӧZ(Š(((((&_QGd|"B=~yuoȿ\[V!X"~3SQ_$;F,ʸqg#Wu6R̿ knl;>v9 ,ъS!#bś~#9-g#+\v7ȹe,|!ci6)#4[׻uYyaA }ߛܭ寙8i#|v )DSZ:@姷VBIP m9Pr00qe5KY UA3m dwNyC ]=s3tFA#6.DAV<7%gw0#"#;?|VgDiS?!, %A]JBnRѲ0r9{I/,-nVKl+ `䜶 XR[wgaXϱXlTgNs9j.Nkhlv)z6mC;as&9S_v mwu)[HG#"on0wvzTW]Ych1(aJ]rv=b+sjV0Dg 9-p>Q+gk9-W-$w:q r3t/MԱ]E881̠$)8$ 3͗}eͦαܳMyF;V"&0xL13mލKF U+Nl.v7ѵK]E[mf g%pa@ϳE6.3vc}jj51!ZLmcl86O'9#R_[^m]*}1cz{t폔}1cz{t폖qFa{}A7Cۧl|z3O: QE1Q@Q@Q@Q@Q@M/}Ez!X"~򭛿BE"qoLgC6Qjv<ٜY{ޟo AEϗ7I38qjA\En/ e IAd)snGv  @!BzC>PMjnmO$C;W Yay~<D̖ nb9S~\F?xrjXwEm-Y^;Y]R&REP cO;/Sy+ȓfvWns~cd-]"#ʧ'jw *i6.cR?) V% $"L,vȰLkʭݏ:e?/wub m ^_U4FqH6tC^cbǫu>-6S1sm؝xAS-`5qkyoc}yi!DRR)~Xؾÿ7bXClk e~*:8ُ5!Ҽj]Cϙ{1 o'+K+6Y--9_'Z=a`)( 1銺eve#u=:]f1e] 72>d 3H6}K|zqliVW[gtdwsU3ZFdrM 0$w*93zoV+;U;y'Vba&,λ~l7^s~}n-@6w@"UtGf'\|h?kԖoK[}SpڧoLY|U#Jydww:lƨ|h [ b@26ps ;#!ݲY[2*4W#8 8aQ O\-c 2阆Fy:PEPEPEPEPEPEPY? /OnVoCۧl|Cۧl|z3O: L~^;c\cј}:AU)(((((o}ExFK(#ןW ſl?/*c:m^X,;H n;O; K B:P[B(1CEo&͛|.;2[$cWs`11WI-n\}; J9 AFsste{CEsI#<~ Dń1QO2Y 9Rv/Njjڲ 4b$a%\d8]&{{쵕ehߵpͷ 22Fi5^a3>ba"˵K9=bi_vK D! 8Ū uBc8'hP RDJ$M څ.~`͍pdgasmk,pkf#P=*l'K(Ĉ!;w![d~6p/'K{Hx|\9C/|-nߢ8O<2.QB e'#Sgd_L}gJe.n#K%t.F^3=@ڡi6Coq<@Oͳ!XarFDe%ڵ J)琸<ª豔ȉ+܌m#1+f ( ( ( ( ( ( ( }1cz{t폗JzL~^;c:L~^;c\cј}:AMc,7QLaEPEPEPEPEPxFK(2_?E!wV7_-fyuoȿ\[S]iiy,En%pK$`>]rRT p;8uޝoyss"O$12 2c*{#44HPR8x+ =Y~D 3RIB"+[Ra'ʲF ~d d9:z\Q4sÉiPKndZC(6#!:@О;Ϸ0i6-u(nU\I/cT21e{R҃U pbk`qo`QڨIX$4ӫ\ˌ0bA9ƌJR5V!@,e1@Zj"QlgBB$m1/'p^y9F:e[wC;8 ^ $ydP'rV\@&׷y-$v|qʡ*mͥXCN,ĬTAjPZU5msee+ dak9MN{y,B2@e+ f:JI0Acdyk Io]hf~l%er3ʔ6n9RI{n~NUvFuL\K IQnD!*r΅-PXIP;e2C1>SNot ]GPӶ>Xn=ӧ? /Onw1>?o*EQEQEQEQEQEy7d|"βQ\e-kB$'ϱZQX(Y F$ph!9Ic& ݰ8ּŵC ̗w3Qy%E>tBTtTgI6tm[y\RXI5ts7rlYWFbg/Yc8 @.fV }k!~V`;3k:>o+q՘*&Vk Ϲ$@Emj%͉WB@#3)-FJ%zۋW %c١hhV%í3k,H,Au\i^s{=:عl"O$ Kpxޫ]ZOe$p]_e.h.*O%Hmx5s"f[:u|E22(f@%rHSg^VfCQO;p:Pz]ΧFxn._R/(ʕa$܁?( ۽nV(4^QRfX,dt,FyF~)-=@SNr8z7S9??&MEAGԪy2=L~^;cMEA^cǷNpBT4? /Onw1>?o&}1cz{t폖qFa{}AʴQE1Q@Q@Q@Q@Q@M/}Ez!X"~򭛿BG"qoLkDK>Fd%-Xy7~1BlҦiUъlsKX,pP}=+T` k+b;ry-cW ^ۦ}Mfsp֭V8l?ak w z*>9QZ-cW^E^d-cWG@wOTxG@ XUWGק*<# XUQ*+샕*(?QAʏ?!cAۧo7_[f͂@@xzµwZV5v8WM 6kOd)LтblmWvW-vȆH)VG` (#j >/ z}WI'd M$^YB$6W!O`DwZm v<|HPN[vI@'i~/ }_U(N,mc,kHQwY?Kj ܢ/ }_U(rT|/Q}W_ +RGڥ_€7(?Kj ܢ/ }_U(rT|/Q}W_ ui$FtapC AG_cZj >/ mvvp0`Ory'V fV 5wF}W_I+rALc((((((o}ExFK(#.|A;:H4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(H(H+8H4[bH4[bZ(G4wܰʯ*r( endstream endobj 90 0 obj <> endobj 91 0 obj <> endobj 95 0 obj <>stream AdobedC  $, !$4.763.22:ASF:=N>22HbINVX]^]8EfmeZlS[]YC**Y;2;YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYu" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?nןW .`4+R(cB|5wUf>ҋg@6+#99ۯ 77@A3cޡI*oMQxi 'أ 'ةۯ 77Gu(H4[bH4[bn<4Em熛 !o}? !o}X5MrLM qtԿm熛 !o}? !o}}_oo"!I(I*oMQxi 'أ 'ةۯ 77Gu(H4[bH4[bmSX{_CeKq,crXn`f>/+ A Q A Ve_s泦hC}0U2N: uF˘2peAzsi @`qylBF*ǹ2;6e}Kis̒!-ti >/+2Xڶw ,<{~V*N2A=M% :w ?+:u u[eD"|1N^_)E6:ͽЎ4 v)TMjf3b)gUn$6;]Bzg:ZuT}էO?ڿRSm.Y| 2`9 d;gLז;[&FBcpAQOqV]CLx3B#l*pqGaqt#M` :dI 0H#9 c *Ah|"]Kd@0{'*yYI٣|9%݂xFR{**5p,@2FN# @#;I=("-GuHXSlʖ_1eIsϨܝ=*A;T[OIDCװaI~9+9+rMKNSP3"#\21Dn$nڭjZXnnl@GjL|)9%)Ul% wY^v2~c<Zimnvf5N\{ǹq&{t36$#V8,Or09jv lY T   4Rk[β (H ( JeI|ɋk),HbIA8 NYESy,1|*n`GPARGr"7hؕ nS@y%];,3y@vʌ20 AAm-/RҾZ2p~@uyڒ7ʿq c@AA_#fY|;/aaOsC~>"k ԚO쫏k7_(߭ϾAqA c7GU5?oֿOPqA c7GU5?oֿOPqA c7GU5?oֿOPٛmRZV,IRp:0U5?oֿOPqA c7GU5?oֿOPqA c7GU5?oֿOPqA c7GU5?oֿOP.inLd2,0* 32 m.bĥB,|(9Bp:u&~>"??!߱ʸ~~>"??!߱ʸ~~>"??!߱ʸ~~>"C0 1G@-XQGs#$I䜓Q߭Ͼ~>"4q~_(L~ڳw_(߭Ͼ Zoj5 7)ڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?oڇ7?ƟZ}?Fk}E3PfϳCioֿOP?o(u!?kT mcپfEOەi.aad232> Y8y,KF.&l1cDiz񁏥l\9Z1,ItPlߧzcmq^.&,+"mUbR-a) M#x\]nQ@iSH77[P"G??uk+gXyI&(d#=3p.Դsokk%̍4EpO `sƔFquZ| TtQVf/φ9|& F}z ˸&;iDKJ\Wݐzgk/OIwckq CKӓ@[E.c>b+f&ާ#<6GOEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEwStB/6/3ZZcC[ɞ+h_¶2:ȡܧnX&*/u^wMd$ܰ9_t+O'S&_72"Rn1?2QD2mأgl>l'2^BQ}a c|'*19D-̰X]X,b28s@:5-ů4i!PwRANXT, )UoE e)'ǒ´Vs 6MtƲBFBǎr:. wEmq< uMGVkƱZu)Ox[ 1eqA̷Z }$1ma[Ui ٕ#wθ+ ([Xn"|G*a@:qz2Fa7KnCB&Vۀ Ux$}GV:=Rl7G>p8qLv\ۖX_Tf8pw-Y/ 1(6]ĺ'kK>gԠw4(SMYKIj#氵R R-DOvR2줐@6)#]oM7Gjm e%xS9yC4+Mw[pSlf)`J.>R8{inA^@m21…w!¨[VmeQRYm5 [clmG'6gp{.ej}69\DСzHw2nR'.s,Vf "#!(]:1 8>osJ,͵W cnxp9=,JR5V!@,e1@:]ݜc16I$JXٹAeAڹ9ϡk0r,B2ā GVKm;RRզL/;F>`MGn%]c--RlH/n1hB;vRm67`b[C8 8 p84z2Fa7KnCB&Vۀ Ux${TeЯƧfܛ?inX˳}u՝GV:=Rl7G>p8qHPXQ$V< \1l#\ԗMfkkC3b.Qtj{[k;FhePTn7؜p9DF3m cp=N?@h1kU@PY=I'ԵHцuRA8,pN' K@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@w7^m_N^_)m^:c0*馽X-`heFJn0U(gu_+]ױUEb;{{I""Q%#6d SHEoaKmXmp,1GB㠠 Y1 Ie 3 =N8Ze B7UBG##'M*Ux?jeg8@Nv^+p/j0xE/ceUG9a$p:XIbI#uxnVS#ԵGT8rX GөڪT9,F#Nq{:P1ca`sr8RU^fG`;a1Fz. x.bQK&$uUau_(U$c1@._8ZH$y7T<`m< 9eN# PH'ee-۔ ^p Vm-Wj*f (`WvW8Vt[飖]đ<pg(qgwyؕുn^Q6wdmC^_VɨKki '1!#6xlwrܼ35b)q<AOVMW@Q8^yYIlGʪ`Um |~CRܺ$eYVS YUq.HžF@V8b3ˉa"0A<vVWݹ@0˅zG{Exq:5.=ӢeF:gjk}4r}|s˸0GqX~Ҽ u2%*:V]f{EHmQid~ {6(N*v# `<n]r2I G<(@BsQ^i} ܬ[T"9Hpa;F>nqTeE!*>RDݫ܃`˷YY.6H08- .,ffeFf;sg$XE?a !l; Pp siGʪ`Um |~w}60%CpT|o>7s$jϗKP[7hNFpvF0qf. :G0Y<Ŕbqȼ7|%m^;7*A\`IG'hVޣxX`Y9VQFxYq<12ۇAT# UFq'4t-壻Aj>De-!n۝gr+gYL%(E/,:D eq⤟dnⷽ6 gbBU`pܛ:U+}7lnnd1d` '; xzx-٬X`Ƭ(=+hi$Hmd$l3lֵfPޘ%yxC<(lX*a&h gr;zc n]GHeEr񲬄+)FPpyPFzcuİvUBA;++nܠe=Hi׺Uq.HžF@V8b3^VG-7<# yX \P'{Exq:5.=ӢeF:gkR/lm YݑoCYzU*fT/1gT|VwМ)2\`͹]I taڲy)*Ux ?x s;Kq/ !bWh]AU7:U+}7lnnd1d` '; m΍gr`. bXg%@ 8$d(47Z4A Vc Ǘ:s%#6-%̇#qV (`3QkJJoFM̑#8daMFvtL1E#l Bxt ږ=و[İ.ex(f=s 4õdRUc1"\=9C T--qCn mBUp::@_LSFlH \IfXU@fo=r\0y2W NT-MCKDjpҫ^VG-7<# yX \Po.%S­ Y_v.GUY$NZAXrgIUq.HžF@V8b3ۍ{.,(Vh!z +O}h.oDK<ڽw(oU܂!bN$GW.Cr9-<yt-:be=*F@O^i[GwV|ZBݷ;NVRYRKH"P^Yt9È< I?wo{qm2qĄX=7ntkVDnb8O8vST[YcyYUQ{9-L/tWbӲH0H#*$g٭j͹ҡ0Kx4y"P UnùM]dѱ  @w>Ǩ{M ֶM7BCq Ē]Ʀ9edi \!=IHK*f7y72D2B0G.EYXwE1E GuoSEchZ8cGϸ`~(߆>B/lm P.pNpU%Սskr;VW{#1m_$ m Zy"\Pp9?,PT}vg>!k0WK-c {s4tq)R[}wN:nՍskrZ|B;I`Aҗ;d:|c8>clInX*,1݂|O}{ mѶʘX@wlIc+ɢP^fdCpƏX:|8so-/iҬ#07Hu u>Kyvg[dm,[1$}mcLF&2Ȓ9bIƱz*(=qKBn-p[Yf*{yGwϨ]C2RI+L W֗ײ\Aq hh<QV@1<㩭&k(Pr9<x9ǯCuwxsU 8mNyfV\ ps F[{ [g2*nYNHuG^j6WWV9VKv*rC~:J(&k @j[^&8Ij@Br$ݻz}MT$j[!Fqf((((((((((((((((((((((((((((û^_)m^:u!Moȭu^WYu .mn$hibW rp2:rkֿVc mg-={ҭ@n>A%ݍĀm ,JNGNMZ^{ @6%r'#&Q@n>A%ݍĀm ,JNGNMIsl&bH$FS8 fEQv64+9895,5żXrA]޹1f*֗$ \ɫP/OIwckq CKӓUlY/#[hkF\ k@n>A%ݍĀm ,JNGNMZ^{ @6%r'#&Q@n>A%ݍĀm ,JNGNMY4$4TU @=KEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEa?yy:yuͷ{ֿVc%-CKrFǔ2q wkֿVci<~I/NtmUERbF!HFهP1* WaFmvÅ'z%ݾuAu} "TvߡY^ տۑb d'8b==iNé]ۼBzZ_Y'ǒaIpѕ gw {{elWenf ?w,~W>0O9ԡcVEehĬy$׹ivV˓+?$ THp=W4ɵĊ;1gpN$*܌8-rW+8.h'7訾_Aw\.1!Ĉ8I&6yw4/sƍJHvϝt<$˹K I 3$Sbv< qׯYwztZ%ŬapUʲBO GaӀkAՙe c&Lֱy{bpC xn9wPh ,G+,r Sx(:9eRռW`fNYIh:zwu+J,\R(y!LA@%-CKrFǔ2q wkJo׽a}uo6Xd)o OjҠ cLl~I: 8'=1V%$qYNCЏcR@O4 QUH|qJO=1YTW;FF!'>rOycJ0X^jAgMfkkC3b.QtiI?ooO-"2;wYKRIb}ˬwqۦ}#nR7 *uR:^]d`Hst֓THт%K/([9]5Y EFC0PtbGq9O pY].a5].2n7d纒[{vhiܲai 1g@A7t Tq մ^]Eb]?+;sUW{[JabѶ7/|n@${j;}HXDxKp:Gg %–wHw#6RD*`r8-8HqHddi!au1fr(2ybT$rOycJ1ج'kkhDŕĊw. #clP,Ix xčXA@IW~#l[_$ʍ.0p8lF7/8#L㸒&xfپP$a|t[X_?^K+ p|.Ҿc9,͎$v1@ oHRT&p7bqyY;X70\Uwm,v'۸9RumiPH&H`_mڃ쌌rK`m*+2ڹAil-c,GTY?PIJHD`/N cn?1?tUJm.8 NN:dԒ@,jk"=Wpgw{x4E OTbgd0q۷=̹< Rdh2 #ހ'[Y4V)6 {O֬Y;T/ V*eCq",I$q[Fg3n!eg%B.b0(`@N_H@{d~bՙ-ӌЃ*KٱinMqI!hpy\3LK~"5Cv}qQNO HrjI'ͨ!gVhuM"@U@͂[b\ $Ϋy'rsxnS,F6AbNA }@/%"K9%NW[؂ /5GM3!#i5z7|OjybѮnKM!ز4.ϏČx 1 -R&{6(we< 7֡hlM]i 9e|lY$9.l[#/v3 A#9I dtOhY`]m>< @٬Շ?.5M"#pY e$gǛjp ~Kf+c ʽe瓳'L])-ŬGFs $EtәV[W 2>m;X#f˵[yDJek`%,ieq9+ybѮnKM!ز4.ϏČx 1 k?aijVM,w` fpױ CY7wL=ɤg2;FrTU"U8ᙖFa&~b'9끀X#چTխ-e$JYHj2ryNR#9ðwL@ 4VQVn%l dpG4z q)Ad+dK?X#u߶k?ahf?VvE7X#>٬Շ?Q@ f?Vvk?aiP~٬Շ?X#u߶k?ahf?VvE7X#>٬Շ?Q@ f?Vvk?aiP~٬Շ?X#u߶k?ahf?VvE7X#>٬Շ?Q@ f?Vvk?aiP~٬Շ?X#u߶k?ahf?VvE7X#)P@ґ*kC9ܛUzơ?c*\؛%A $/jKy$H7182s]#_d_o巓R\HA:Z%Hu$O9.ȿQ/TRI7rɩ.$R gg\{vDT!}pC+cJM#_d__Uk~UCd_?B/Q?T6E<*#_ .ckw#Q"a#hbrO Xc͞ @f^G<"]ܷ9-8?d_?c7C~h!M4͑#_d_C?ƣΉ{ qsV.ȿQ/T{BF2w32;3,XI"FLJfoOj穫;"GFȿPC?ƙ/TlyU?o77C~i"GFȿPC?ƙ/TlyU?o77C~i"GFȿPC?ƙ/TlyUFzI{׈b"a#BK "yESns[qq ~ȿQ/T!GolyU"G@!M4y ?ߦfȿQ/T!GolyU"G@!M4y ?ߦfȿQ/T!P<ėDΥC$c8'~ȿQ/T kcPQ/'Tˎy ?ߦfȿQ/T!GolyU"G@!M4y ?ߦfȿQ/T!QYEjt$ҴON9(zN?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_d_*/_Z?6E<*'Z*/_ #_H#*vbA ,a)E? |T_UM>rܟ/o.~T_QU7'[-? 2 APz([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z([?G:€,Um=?}z(D7Z?M~rH F A>9i^QT_]%١ `ms C2l\ˣ]L >6:gSOIM2 jtM58IOE`;OѰ?M endstream endobj 96 0 obj <> endobj 97 0 obj <> endobj 101 0 obj <> endobj 105 0 obj <> endobj 109 0 obj <> endobj 113 0 obj <> endobj 120 0 obj <> endobj 124 0 obj <> endobj 128 0 obj <> endobj 132 0 obj <> endobj 136 0 obj <> endobj 140 0 obj <> endobj 144 0 obj <> endobj 148 0 obj <> endobj 152 0 obj <> endobj 9 0 obj <> endobj 8 0 obj <>stream xyPW{רu`Ynx2Xά|cU ]\qhx 嬹FM}'fMd^RQHnS3Ӕ-)uX>{% ]~E/\8ḡg(QuN>O)pUՆr{9S- :HSwR(V$kR2`rF֦ZHҍEy3£x͸%QjeAJ<`zOƩ(vHx7|W"I_wchYtP2]O7k4hˌΪ|aj4jvnv endstream endobj 153 0 obj 2467 endobj 26 0 obj <> endobj 25 0 obj <>stream xzxǶc&@P %'Bޫ6`[$.z,W[0L@@ )xMrs{ߚݙ=sί{7"""ҕ.>|٬oİ/G%胗ZkRQW/Ž~MtxitQvbشLဥi!ALƯfĵfdl]<3sےYYۗNZ6G|8e<`9[V{N~{ؔ19MFL| /?A$kE b<1XG,&fQ`b 1x!Kěī2bK&+y0b%1CN"cj"FC  8KPCH>w/:xOЗFO.+{ߡ_{9:cBE; Z4xC ի^mymkC:yn& ]Ç?1bG)-揖ǑE6>~N< ɺ$ \BB_T&G3A(D!j*Gb:@ Ilq4fB|WXBpM(A@AL[fuxl_`B@A Xvu7$)J0AtXrAUQ,0pXc_ 0uehR,zw)(^re<Ã-nE BPKDdk 25リSw[Qy_Bhϔz#1+uQWԔP.]pSveJOwx }nn};@63ܒfDhCʹ,{+Z9+F2Ihй729&ܔ_gu,,YDq8b 6‘U}mWEsoBe J/ͩ/ NRu}l@@Qyη\aN(ޡZ:+aKF#žrsZA.=}G"Zܬ$ ]v8 V @Pq[be23xV@ :D'6^w|=E*::!o׹4@kīEutryv,z0%h=zMYHv*[UU-UE55%6g+Y"f &7-'='M%H#+k@l'صᚫ ?leg#-(;/{,^a,aC앸%}kh54߮tpV{\t. Ŏ˓)n;C @m8ژplkp6fChcT'0|ZUcc0RÇrϣmo H\7?|N`$wH $kH9_Ayp6绎ޚ?{H~3qyj$/trN=ݕKGOZ4(ҢTWZ`D%Uű6[wk+vbDϽ^zu:5P*Kbcv~pUI6hlUUxTY ގr# @n/C؇eMH4wAo6GR0}'{hNU"4 M~ T tJ"ŗ" v-ƌf\ZE)z#P_T(3$ ύ *\:x%~,rM \֪2D6\T^6^c$Pd̑c Sh  PS[i 8ӭ{8N@St:l>^z҂+ WHFORT3 ^[I=ďr5KF:ʚ,rڧTW,E1J'%]5y97VE~_{ٰ'v\6 O^(%@rbd"АQh0>kS :Nx Ɗ2oذqy!^ᘟ;kwy=>P@r[!~W'!P$z!9U-@d:B. 835-uI_\WGo`~6k:ŨugAQ[3M+Τ%2 &&yf㫚b3 OK>wlJx>|\헵ny%zOP* ̷n*=k,6%713qb$4Ip `Y*](Yâi<ހzFv\<-4t^ rҲ5U[bx-ӺVK=l\}t_.ɁP9ݺ:{Y~xU/"Yu(5HPSl+R78ySJ-lیԤ%,vN'O`c J?N Q"3EDdg`}KbK:Ȥ0d^[1@̈́&NS=9uж>ޱҹA+K )J]/!X2/y mlͤTǹȯ0Pu%U;\BŘw.=Y%4Vpv>>l>T<3^i#XOSnކt.*ZIe6AZj/ }X O?~Nlgz5e%-fNXՈiۓd h4 fy:qmgeaF;ıce|&\Y@P^JqU&Ɏ}-oM ;7: 1Z2f¤̂`--3U+.B+]Dpc# &^~&FFfIUii6qXm_| @> V~h>/AnoU0Qe&`oRy[;V:) gUy|AXp@N8QdgIڔw+iIE<'u5+7;MWʓ+Y&f)]K@zh -fbp}b`Kckw{f=GX:J2c9Wם[NMެ'Cʊ[adka>-V׉4:˖Li>kLbr| !( _e`{~RmN7c j,)[Ԩ (QPc'%LO3La٣O.8`7p#E8%mXQ~y Z[*4 D)B h\Rs,iM`+Ue4~›%D/ E$"a0~lE2$ZXI{iX !4b+݁g(|6s1{KU60ܞ[/%$!3l LJxܛF(*:ˬL&i^bS"!uwvAM,Mz|YX5ٴ!*+꣋~ykEMjLx< L%]&ir VȠڲk}@ 2q}8)חeR[>RSVO; )X=IQ:j_M;=.gC#ݒ#O2l94kLBGdo;2``*$kAəOZGdDXwBʪZ]^V`͇Cɔɩ 'Pe=8~2aX3dbp p𯝹p+8n ג reQ6rNTE89egr/9zQB+[; ~alB"",, 0~Lb=Ih5$0O擱rDl\ђE̬B!S]"%}w݇d>9l*vZc]k\ҥljFլYە6Y!APxXQQ(t 1dNCV7_lu*Ү(AP|ͯ8[ɇlH js̖RqR|h*^B_)WUe:'`tfFV J6ZhjʨYFuyh3%"Ѥm(ѐ&a"g\VYѱLojh.ى~께q Kssku4LBx`ֺ ~sA~QwmOq>YY*ͅ=Ǚ >CCNC8w.c/EvbüM@ַ˶1&Ҭ1hLZy_(K&2mҤVylF|7vr-ԁHPư  E@̒{Ry9e&Ӵ9R!lě둗(6/b ?7ی( ܇T_?|kvF/W2J` }cFnj6{-iwg Jp6,fk HB5ŷ٤ fmvgUIaY  qSL]-/Rp6rYHݹE"g=jbKr`QeyYh7bdޭ¾RUKz OT@tWb`6t>];_շ\s7HMnK5%bNjb2<`X$ƪY`>X/unSۿ3@ݓJrwST!z a7 xOϰN9ukfJ8āl[:;jgbg;]TŽ\Nv/,Zr-9:dL쥭>Go#le;"zb!ړηiZqJQxƞ؂];U@6r[Й&:4gYE(NSkdMxs+|n iiNOqPIXPCU, *L$r Q‘#TduXSg(@˗V2k>{g(~*E1FN^:Y:g%sjQINg7j78֬T( Fo ԩEkϑ0ٺ.ˢu݀*@ܫߘMy~1`9S-<̶nj T'>7M0F~Up_92򽡛GTTՇDetwvNX͓s% zA4 zatꝝK/WW osaoVޮ&߈p9R󪾻m ۻ{ʏO]-Z( 6-KF!zjfqXmv@9(XPTVԂۘWf6HK5Ԋ0RO\44x2(nEI#hh"W})Yt@GՆx&?/D"L�EEOF-$'UXz'mX `|? U[o;tiCM4{U0 ,##MUzIx<=W*qAQ,yhW8>pP) jjoK#.'Q0 j8 Ƣex}fLC38V]C@XoA"Q(>pُJ)T|Ȟĸjچآ lY!Y4(LJ08o,4wm# , џ:su!s/Sؓ0T]yy]mvYFzvNO'|YD=\EV*uUf\WN+O+if [}qg'e`SRmz |Aml/n@}n`2m^b&טsO~#O)ӑX װu m^FVei˭֩HZ.OKS2[j[1|.]/߯VN[!1;ec)KA O->MV(d.&$/,zZ:O]I_  RBQҷglˠAZǴ[CzNʧ)ɣM\]Xp:0S"Pe$ opӹu- 4ҍ *#GQ&)-i>;;-A6>1LϠK 2,K^a]Hst"N# g>bx#o½ ?h>Pkv]Ho;7z>x^2w:UZ˦m( BW[AU¶-p_e_C>s9@1U@bbiM~ψٜ]ʳYSlZg2PQX#{?O핟ZEs金SsjEcPxRR"c\\[M`Q~Vc[ k/PVsQg+oĵ{a>( EB%+2fL)%o-\L<6up+=r,@nqzGȷވ031qv{?pбcvU]"oaI3eͻ <ś-.8 Ғ8L \Y8N{.<&bXzI`xHupo}%n cÖLKN@;*ʫHg59z n1y!܊f8o/ cZz?D|8mryH 5HW/? ŀŋ.cUu+ ,jjC4ZRBs;ζY^tDMVT&= Wj p+p]gH2\ZcVRah~6<L9vkؗ;F7ؿ?'H–mDx*YN_USJ|z, NYݍp:\}: [m{g/ʉ˃}tQc~Ђ'tf_S>C+ H 7(Ԇcn\}U2ۖruMz26:@bͼqþ1\ц7zu(!HЋyFP??\yNGYL硍g%_ktPPw l\Vu44 kEH& 4uXvWaژl <-*S1mҍ/?d;8h+ < `-חgNd;ҼNz.,/& MF3[+aW5(=dOlxmI90HfflQЙ: jq5DAAL+S0pKO' Њ_1dOx&Yiu; b'z{oCV}pb/~sG-+I˰516C+TfP1HGke[pE7<|8h!UE6!M*ͮ(/2N)oLNfȦ4'X+_h+MfA (GcQ;4> endobj 22 0 obj <>stream xyXSgO󺶗 scmkuŅj*JYfX&d~'!ȦBX2ӪVPu:vs;KI静>9O'9~QB(Hm;l-Eٱt1I!s985g0oxcX8"f+nMKW]6w}qAzNZz?(*%9¯y7dbR)j5J^Sۨ*~MɨR*z6S˨-j+5SX5^FB~ߘgҭе1Ɗ6erjʃ >%"ՌG!1v?}ERQ 2L+vЪKɿ(@/* _2C}g<Kإr,31|CMmc;_oU;a ^kӹ3g6&7%'-1gQLTr`5ޱxǫyO>(/YEdHj"̬6 ԼZx\2ΔbυZiȹPa/O! (IiqOXW Q.ʺdoBm dLY<:{0TU1@13d@Q]g47ldԈwKy6T!v8ƳW,PZ2Jdmf>ksi0h;\ k+GF%d4Yz#"k*߽j!W RZ ǚ]Sp9{5n@ywsUVM&AgԀl:\WwWȪ(cMfBA]B\/g?{墴_;߫l& €Q7 t ȅ= YdTP64;~A-+ iedzEb -W} 欆W~aͅExFVbQC|/W20f{~,S}4Ӂ%xL%S FGlkv—O[>a _(ENz0HN ey9(NɋF% "m6p?!AO˫̵_2Tr)??{VGvg%6,?]8s:à#:v=\r 8/}<^@<|\D92W9}u_oF&Hc;ap8qX:UVbA6D\K$s gq>7"zKJsg9jiŠ刜DK]7/`,-%EB ˴n&0JLctz avL ByFn˴fMhdTd{+5F-]+i8@jV@kz/[Ŏpq<#0Kz)I>l̵Ҙ_R.[_^Qw?:_J.l0{A{-gS`+x~3"Wftv5 qqY"]@TR\ S{Źy7B;*(LeoJ])ujjq~OWo\irVyʙi)N endstream endobj 155 0 obj 3015 endobj 17 0 obj <> endobj 16 0 obj <>stream x]{PT*uCJ{0C iL12l idd/$1 ͫ9pyK.~aRVJy"^{&|HRL`~X 9[fdu6 D%No~j/F>~[ !/Q׍,H9mݙez&.b&/LɩYh' 4 a{if-##A-\pvkF1 as S`tf>/;DU MeT|bylWO{pjD|_\тN |v{z!G{P"` &&wǽ91F^-̏\nD\&hY8˫;?qWv;C6cbFLz>(ak>R^0v>q3vfgTtg--o52Nx^ɩȝTc+dG 61Upf,J>##EY;Zi@x9X_6N)[pEAݟGZptlaKn>Tr,"ˢŮ2QL5eh!u\-w6gf7Nd`X<,'řV/xWn + \Rq(':ggEL\⭲SXwJ;^2zoX:0 =K,;=\>,ڲrݫ5lyG;-hc>_ΌT[O4eLjp)  iawE2Tاazg/)t oIߖC 23@+X*MYòs+@/~6޳oo ɨyK3Zڍn;g;sw؁mpZi"2qv8Q v»;Ji p~mbyI k;qn9 E)e0*DmCjc Qjކwq)DېĿ endstream endobj 156 0 obj 1624 endobj 12 0 obj <> endobj 11 0 obj <>stream xyPSO|R4W.WW[^[.PZZUJ’%, 9 9o KI"AQA-Ƹ-tzkc^/It:9}gyJ$=rVEϝ7gM Mhryj?AΩB'I?=NDLKWD+3)Ӓ:(*$G.\Zeü f4-jzPZ*zROR2j5z Q4U% 9Db.pQA_$h=zlE+b0 y5"e&$85uzbG6gٛqʜJdݥAn]ZSm<~_]9` 7%st3ɷf(ǘ새o?TmxiX7%)C=Kv,Co61 Uъ./}tMl,C %iL%nkikWT #Ph,4B#^<K6%$8QP@fVKeY+^ٚ|R axXqB,&oNOΞq=dUYoڮ3s%.=4P>?xw ]sćO \_p T˪'"vYjld\XmePThJ/02SA;Y))dm|x{z_t'gkE#gs=Q tRvA4V〫- Co:Πh?0=jtVPRqE܂GYۼkX p5WZY"$!|1Aër1 ARG95o/9t/myۺ)f/&9d % rC]H`y($aq-W|yf9#KiU_Qqa.[Ms0NL tvi[I<ʕcpԝDVThۻs!tY@+LI;S=N fipZ~XpՋ)ZZ[BY/j(;Ǯud-kme#3gvʙCa- ^b&Dw~{э o{Zһ7@ꠀ[$ckT,̼ɔؖs&%k /#F@̩K8L|żQN|[FsW/[G{wزy/#/L96}Gю]]8`?wb&_0ҦQg#dh*,N(U9CO8zv7vxNӫu㹞oLvMLjkq+%TbҊx^"$[UB|jtL`oNm+MeyvIq ,Іreʁ ze`ߋIR ъ8QfՃSǦ͜KMeB>gS󁺏(֟{'-'3Sn)bukC'd6G ãjkkv3Rw9(%S~su)U 8K2=Dvj k,:GT~D0Q7M!3d|TBs3{{y"e%roKKI =x'1&X\:~E}j endstream endobj 157 0 obj 2372 endobj 35 0 obj <> endobj 34 0 obj <>stream x}Xy\׾Ȍ*i wbqݪVJEEDA&}ߗB HBEK[kնVm]ZRON}10 ߙnPvÙ7/يKmׄVW; .WgCٌiPTr2N8v{lt\rRXLаcš37%ń?)ZDžy$DlKܾ1d_~!vUxɲrEP7%ljI͡Q;Mrʗ^Q~fjZIBmVQz=ʝZMzr\(;j25reM鲛ew̽cgC$it"Uǟ0wĈ'4;hvr$ONU:p㏾'*|qы5/^v~9918 C*9. >vYiuIs/ Xxs^ѭTNW@,t68Tb8-Vv-.>ƫuB55mY\OXv;Vc ط 9Z9š`QbpYG]lfqA4%94´@ /L _21'#X4;bu^D?B. rKYC2 ^)f6ӐU''%c>p9gk]#lv敇 ag=֭Q-A.4 "7 WoⲱP ָ@p {S=JD;`.ù~Ds.dgC [Ζ:kZL?TBod 62}͸y3֕1H B^g&ٗy{o#[h( {ǵ<7tHqƋ:P\#TYФҦ^_ͺ,uj=ASyF޷{mj}i!h^H y.ROd#^R)ɔf0 p~ -D 9EZ)eC8*,Nd?'?Jlԙy2XWNL5N.驯o/kTU*14(G%FgCJ2ǷQ)*V֌c C\)tц:-:ԙy*v {w~{`H7h + INњ߱i!Euhe52MJB IBb`າ Rհ |KX:Y" p`W=pgNXYԫ NЧ3 ̃aY6n $-J pPWr@2MqFR"-)f"3{o<5-fh +)UT.u;eZ*U)э(ћ"ŝ1wd4 #oy7UX+M.n D>!G QIXA2G(}s""#K|VV}Tt@_8vq-sY1*%eBO%iql}gAD[ # lH+54VuXR|QKo)8 H;XJ uOpAܘpDV`ֶ]9̓Z&)*Dl8u Z6ٜ{\4% %^FWB?߬`8Od,YߘoYX PK+ϖ!{`7$LQkOv`/XG*s7_$2jSI6 9\BЗ4?NYX}W _HbL?IΦT?3;8%m&+c':G IH>A?߈|ar:ș(=>>Ct9ҧH) ހ}`pNۊI-xhq۞yG=:2Ih65&99Hg#RZZN2yھUq*rxm8hU/?t( HJȍ(n , ЛC kd %f_dqVUhJ,ǁۑxI%+TH@$WgUյ؆Ȭ8V+Dz j[ޡp];HpbPCaS\]<׹mZ\yaA}pՁY 3#!Pf(6{ ٪$@ g3B/ry3hBO=7C^:͊C J?Ңoi8+GȽOGz}e` ]׫^ ,׃6=SwQrb`Dh+ Zgk_ 7|ivw4A$>_ X|Q~shp}=TXݛTQzOeg킶Q>E烎/iE:R`?.?qa CkBPD; g%C>j/azYB&0.aו;⾕JHcrdBH\YELBgu%zmE\@}!<&OT-yhRt.D]By3YPYi?k"+4CÛA5K冬2dW-7Nh2d2ڊ &1er/f%@G |!o+$ 'J PK?YP<-eh*wdEW0U^ K 'BYHC2%3-&r_~0`{:9N1Xs9$48KICϫ?ÿߣo Nz d>4/B U"iBbD؂v:AS7К)Dq&+_<.o :>07/ZhVeC#۝?ǢV4o!⿃&_UYFf:\9IJORQ+zPeu1=H!_*?0=u`]Lg\~),#9p]+M?-8f'Ğ_G;\)q܈5lq=cLKXOX=W\y.<א3Edm˴DH6ÑPJҦe(BQR^5R;X.7) J ervrsLaI!c_6#ju#\4ӈjCN'p4}SqBXPW(nT7B-jDG6ypt =k;#X 2Ö?1>owm@}pQpy{qsmLF3 m8o>̿Z Zt`݄h<o/@g?7]"SoWoɾ33a„dB,w1'oe)X֐s({x?#įRgZĥ:- o<' WwZ߷C3$ٛ!Lg{g1%]B2!Cu"pݪ3zBN&\ih #zmߓ$DcqwT/+ 9A^SrЋ2lNO(%Dc}RFX8F[?+.to&xԕ!h dh(k52*.,x;SctM \PS9uޤi2(UOAV4W^ }9bNk.̢L7 (wcQiMvT 6Ù|hz"wO[KK{]voHEǤX&n DH$M@g^?Ef ~ܬ%5'!}Z9M).d9ζyq/znV2&wқىH`tq^po`nȦFSgGbSmuu)#̤QjE#S`Y/yYn:! vڼ3XWkt%Jh.Z^cUcYhhhfwL̍2keSJs4F6gLDlɿZm-hDF7B!3Z.@fU>b1(/AtG< 7Lkn+mVh-K+@: u=߬kߴzu.vIdzZ? q,At }EmbUxZ=Tϟ&Z,=ܜʦ,g+MZ8 MdޙO# ĸ&u!^P@A0' G:Vi+WUWXKKuP 60xb lVmѦX`*>~Fۮ:#;x/·Kv.ΖCȪU >*Ҵ:yQʿ*)宪+/@mW\m\mf$IDE5}S=t1]qm#ö>5r@#+!r6|OELYPϪyņv] A3h<:ї`FP'q(Jlr,#qЯ;Č6㿈S- EԤ/aT('ly6'u](E,Lj`;QF+d.ki>10ظ 6vMxV,d j;[v8o^R endstream endobj 158 0 obj 5630 endobj 32 0 obj <> endobj 31 0 obj <>stream x]]LSg9]yi¤% $n^ء`ȶ&F6$eEVʠRi J_ Ç|-B!#lmA0u硩]i'G:R"q{ޔd8x7_XE14/.9k7DOtSAؘb^(Cɩ*Q\('Mw09̖Sj')rG}J0-=7}ԪגRfem6lV;b=8UerkPҲbgOG"y=}#"3 cɠ 0 Wnt~*%)_ZզU;܊& .;xBт5j6F#WÆ"E#8|u*_~3'CdOM}Cߴ-r3R,"C/pOIJ V cC< ~]s]S.aG=h*$ev,^So*4zY/v>g<{^ |a(.v;xG\D a7,tsXQ𛹐]q!'Wgn\.hE%4ճzKYF[\iKh_D l- ;"w&R ~uN¨Subh-mH3BozŐE|#?]ߕ;X߲0?a CDK?' #DBHr\{lb,;íqЦW"5FC4ʼn+( ͖p$#~ǬQK0#5\8ٍ\@S`l5&0` ;U/q09̀><+qmmVEN [&ൠ )_.ĸ endstream endobj 159 0 obj 984 endobj 29 0 obj <> endobj 28 0 obj <>stream xcd`ab`dd v 44f!C9_ȯ?g.$L1wfFF7hʢ gMCKKsԢ<Ē 'G!8?93RO1'G!X!(8,5bs~nAiIjo~JjQ#?C ##:ߏ C>oƏ~3))<6/r| /d-0}3n9.> endobj 55 0 obj <>stream xX TS=!pq%M &8UkjmժuDP L/#IAQV;(Zo[l罾?`{ﭷV`ir8{{Gq8Q+ܸbC߈|iYD~1\U_ (-==(?G8ciJR$3.=dmJl\zr)cCȌK)fIVr Ըei{6,O HRj&]I̞3wA2j&ZNM¨Pj"ZADM©lj2A6QoRsfj5ZCͧ":j)QP|Y*P~Sb*J^" ri/'sM?/7_WcF Ifh0Ű_/^=B2k䤑#Kz)1֍ztu(!/(@ +܉hw'kp7/>T@Ҥ) =SV& $[׭¬fjY^j{ZUN!uDx y hhES`=x)Y?vIJ 23_yYp'I[6dAшĻsܻ/fxI")û*Fyi(6C {w̫7 kPdeБ՚z2+`.JwLj8؟ypW :4{grFڦaF7iuDwB(U;{GcCKlҬh5;c6Gյhײ#xBOyq "3&;ưWOJ<1tbBd~hVYupx%<=<>9m\mWA .Ue2,+F_zz>t:T*MnA`X_T(s9OuE (p 4e*G6jfo#zkr_Z&+ jñ=Q+IUc*߆ b'wQrҌL;ڋZ,3}DJ|fr\ز 7uкIH/qVK౛kQ_Eϝ.o"x%J`3eVc4Xof򙎺&G:֤aq!htݑ)Qv"TǝvV瑿$#.?O(gYԋw`yc(@cM܉fvipȅJZEj&  0hԷ4}\_ip?ܙWbX ,`]tV$FIɄ`8jVS '-ś|횼UrT9z]}y؇5xT*8/.v{Q:]K펒_#rEw,I~~Eh`e]J\b*"pVtölk <3=ɔ>te;=ī):=X7@GF,Udf3GO r1ۻfG[yolޝu@>ljCz_<;3lyuom[,ݞ?T~Jh:QOn=y8%V;r̹,^@IN"fA}'hΖ}{%?e; }/f.zhFdfޒo[YGigpK5^V@4DmKό6h7-{P9uߏ? `<;`zٶm;V$20Spk :A-b ƌ|,!FT&e]C'#ٚ} wJc%h"ͻ84Lhdlb3ڄvZS -M۷EKM!2" J-ކfm_ђ_m_!8ŶL̎G3%?fT"t0zRZ҄oʇsj3ev;Qt z#[FBT?Nk5qU3rk*jf4ZCJ~rΠj) Ce1Ƌ-[.ZвFd, .ݲ2"oҴ4We0XiYx 9quʌF1\o_`vUDS*ȲJZ5+Ldx7G{WˍP&8BԈ&2nrIx" ױM~>A 12N|ߋ5d"+|Z 8L'2y}ԔN ƒMv&G C<sߢkFHfsnLބf]z΂cN;_` ʊ7_)Ի|.j"47P[a!cS&__xo4d ̭_^&H)L$T2%kM*̖ &u)ۭE"Cl3_U*4N@&DopBrƒ*rs@b9n0wq%*z?#{7)*}JIe-W5g\{״PHLK; 0qq XK]aK @{XPâ *Rȗ&paRG 2Ж3ܝG2 t6&.iWຶ~cey!lu_ %wj}ibs|Ab/DO8OO|II@?6B#vJnL@@6BCKo3M: /;Ap;xށxCbE# ZUAhQ!B_35wi\B.3Pn*ݤ'2[sgw|ֺ\Z+Nj|ƒoϷYp3< Z6Eku mY]0lerGQCz,p59|i51S F—V5zA'L^_kY(Lʀ A׿H_wy E|RZHr5Z}t4>$d̛%yrǒ+̫Jҷ<%VWq֑#R^E \L?޼fmѕaMLukEtks*UUKP̊vnoAQ>,K69Cf'r(zc /.|uTQ&!1GN܆CY)6n%Ҽ46s=kWԇB8DJvstĔ`=!B:*B#D`qSޘMBϏ?"$ؔČ\w.n'!&v0E!Ei ¤ PZ;*S YJSɧp!d6C [NFvZW@.qInTލGRE6}h']e>F?x7J۬Ot:.@E2ob|E|v`Qs X46R8k`JBF/WtzZCe#5^`$-okk{fyyaJ fXq2iA|̑g|r޻X"CChjK?t`kGGZSY8xp1_2Ex4 B(7%1҅+s4;] £4pQfr_cC3Qܸ_xVm쑔X1&''Bg-y<˻iӵޯC6kB-1Ύߋ&ۊ= $?!?Rt+G19bt3 w=Ӽ2=OX@gJm`Ŝй+笚/jt2n(}?b^p} A1r\NoKHNQ)Mte$OY 6ES up>k}jkc vUCT+ ѹ;T! ";*5fEcR1X˫\5%–cG6V&@"yU [6JQt9foϠMhx-C2sMY6S Xݤڤ6uű7t0jeXs\SYv|!gH9-,5<[d;m>#&3i2 qIΓ|hVN6j$#| +D dۏFAh$,p9Q!,e MUl-JVZUVQV@r9PF;YNN44dAPK웕b""}O&pG[I$~/fy~(0geˮ+˅ %f۵3<#ij4VMxrd4xiӫIdJ#]Ye2EE@z#;!do=>`~V#%Bݰ{j9#>{-=x֡@ߞO1vE:wƔ'7Ke%sk՝*a&7RYֵ<&̣#,;ÄCEYP endstream endobj 161 0 obj 5618 endobj 41 0 obj <> endobj 40 0 obj <>stream xy XSA9ǡ-jjDZ"8#2OB!d"HH XUV^okkkmk!x{;|̓wk}׻~!ߘEBWDvIʙg<叶KO6pc!~~[9qeڎԉai)SK \075f墴džfĭܹfɮwf'[O $oIxeʫ>k34姞fEb#>J &wg59"xxXK,%^!eīD8xXOGNL%"D$XDl V' 1" Fb,@~FůkȻC:ۆ K% T=>ݰn 3r'v"F:1 ,ɝD^8fܜyAT [9OM|_Oɤ3٤&{/QoowDz;[T;G TL*A*)L_OFO(A2&BS#i179WZ #ݞH_[+޶C~ḩG0V CizQ^*_$(*LNХ1EeL!vea6+*5Y h {譜]bu4<8^5w3msy.4\gg1ۗXJ EΚȠ3;gi *5@Mk(R(EAY)K7eRY𾴮kݗθ΃gu)n_:# 4/ȑ(l(z@k%9peHmE28Apkꙉ& 3p;Wa@n^"^b%RoaQ-p)n)'uZ|*ya WP{t ʣ5?[ t tC (ֵ5gvG86U`~b Aq|~Wpd@y@tZUNyUFFBqB84Ƚp-8ZXcJm["lXnHBա 37?d[z|l1p `E)}K-[b98/$7{ =njkX9ޣ7 l"hhE&~f'+ޟENGɩz9Ffl2HzY) DJX'tBݬ3Q{ݦV]l-@R AwЬh2O'.HPDƉM-. ݀z7u`7qt*ͮU-='$ uin M` z5/;[<B2}b]X(XZr\aBhӚ#kЖ>]-?p^{׮fQ4m34LC<4Q}}՝m h)iy%quw=஺hʠ+iLEpɋF[+Ֆ>, en| ;N[ h QTZVa6G]jEzL#:#Y堆؆X,X%XFz|xQgOn9V g"-_?rhK8B4:]*p?_@ɜ34Wq̈́pퟓ9NƧh !q8d*:OH7}:[էVVceDBGs;wU kj{WGX9//0[ x {fNGg $h+|3;|NFdn_Ag8_~s 9ԤMHA MI!pKJ3?qKF&SNUVumwƅ^!e69>iGQMp٫MPd1 ~OT7EM3pN/u?h|dLfskvSl NܤroeM5ƨ4]r( G;*egLnN6ѪU*@H5[FV8QJ~ TK+))9MS!gG!S+~zyթgd;saFSeܙ p .Oe4{,J^|ܐ;yp5p+-%&z@K Dhs5}#t1&n(Y4/ N0!`\vd6V%)V}eAVrZBF s0Ed*pFyfR? '~kIP|S+T'*}cߩC)@/-q=l5UsiȔo5 B|gXeY!;+k?z^hldrZ˜dVkĘfla>$e{^TP-ر?`TlO0J/*-Հ Y uK7`qjjD%o&#U C+n(lL)8WH:vŕPTU,`Y7{'$I!+@vv\@lA8vv0txW'eYp{Ԟp,l (WMKC[Fzm>̻Ewwݪ~o"+7&7çpE/yBЈ&t 0<6P~@y,ۖL|}>ȧI8@'|^+)c!d\wO[jQ,cuc=^>Yz( sY0tzuZKkMC#u7dnFmԦpКps}/sl-|w Xw}V#6G2,{TMJ78@_r҃k  /T,6+ )&˗d0JBnYW#20K)쾼]ZUF?{IY|#7:+[|TΠPVh+FϨ=fWz[[f)P d@J Hѧ6~$AWY"Lmc~n*5r{ ЋRjjmnb|ͨ_b=bsNQ>'>|a8S^IԸ,S|zzz0dcTƕ]-LYs.=K܅T'퉧V@Sw՗o;|[[' L.ܭ' =CֹtF*:F˼A]j12{4_*pβ& X^iO QϷ;tnkTưI|HHWGvZjoyáŘ>Ci{aP0e4oM撎pݞLb4 ]*!VS +/CޠUʅq7w|+E]䛻T5+oRyg"`a=Q&' 㩁J~evZf/um]srHG}Uz"w{orkiiXY@ 5rEX.ILIf3S2vў4ׂbx˶g|&R],@-6=߆o߃C˘r|4e?n '˼O9pTʢk0;d{j er A5uNˆ /ΔwK#Q]ղg鬏25w#e 7-~܇Nm;0u#c$i/ǙnkZ}8Һ`L= ԫ4rpij)uYqOl4vֽ3ճzr1'7R$u{5-vJ;}ك余HojtWI2M Cy/P_us5c_QKM5X*@LQ!wJsZ䔼Ȱo`JEဝ$70Ш(ନp8Jj-2۬Yc.`Y b}w84(*?ե+[OFWIّS]WMmlkZeHi$ ĥ rIƤ59T`w9jwMaS?ܮ|nusޣ.6b_nn`^HzhѹEM#J)Vb(χ֬+U縿az@Gw&}{Np$<8l$o,e 0f^Շ;͡9X1Up%%'$&' VkRN2JUoWtBܯ )dg>># yhI!C'nnvָdyfqܮCnjc  DFT %PJ0͸(Է+V.p8礧dY `h_`&O\ހww2^@^Dָ[2)q”Tā@S8R/^mg.}[\Dl#/Lq)*L=؍1J ^#Ãmsrًبs'SvB5`_劍UjqYn[~ŧW1Il쨒곰>_ JVOg찐>3?U}'B?iH N A('(d@FKd"Mf\Zj)sX@~!G{gC9OV)14V@W-ʃذ_fE0O1z8ZZࡰiF0'n  _q\ںu@}h4<;MNJkW!OZS Q"M>@9j8ؼSd1hbۃ`~TLmaL|"MzgFX"09e|m2 uq.Bz?tF#>%Z\*9p1RBǵl*-z8$i8{ˇ>o ~@,c$̥堁f9Ӓ2,]6xƒȏI/beh5 FdU b`*}X=R&!tEnw4~Νly]չu͎뫣wHs2FMY SQ4x1æo_9x)"봕ZP&l 9;h8qvEE/Z7%0ڶCt۝QZZ_w͍ͦ g{JwWC6'm]:t]%ka2y2p3],7MZuwp#R- endstream endobj 162 0 obj 7412 endobj 38 0 obj <> endobj 37 0 obj <>stream x]kL[ei9/YLl1[RNl.D SQn]J/=-]1@\:GA-s-:ay%/'yh*BD4/=;-/5)7#'KU|̞ b"7tIbǬt|%gӪ4YUe9U" EQ[R^ؚLQQT%clt%*-K>w#QqOib'dgGGziB+wT7PV$-d7R3W F|{e1x3$qDīqQDcV)p͟vP;3_Y!'kn bl2YՍ*(mVp v "X8ⴞA_b%@vnHۢ@=c qhN_? ̜y48A6u6jQMg]OɎn T^"fkp'UI[q\$Hn{+?]8_[tRqK 娒Mk .ׄGZqlڼtӝ~a}Z*mP .?wIp.U,6@]=O!=N{t,ϯȶ (f.jx> endobj 72 0 obj <>stream xu TSo{]@5NBgki> eqaS%A Y -amYæBNm=˫oX_;83μsoQ(PDĎףvn=644s&rz_Sxe㟶x׾ XK(/O-+# ?)7ho$)73hkV$hGa~R$IW)<5Ko[vRNnJ^~Z􄰌Dqc(*" j? VRQ;H*MES1:HRoPm&ʗZLCR" Ő]hx3Ħ毚ofA?,Zڢ3>+|$X}z+۔k2ϙd~BsO i1=Ĕ=.o1]yIA,fQ r.zhrk8ΙV\~f'wu>ewE}ì%cRҪ7o(@aTYֶB+e紝LefF^J=p}ppalŅ7MJu {c^Z/<'Ip|wVy%Q&$/F [oU/!Y:zrp b5 &mp))#X5} ͂ / ܾ#lGuYYI ICAw^aT36^DZǼјBIB,1VjmmUghӱ$m:\Ĺ`yEa( `eۍE = &O3Å jڠbq *PiYba-Q%^W,*b,;'}vJUd|W>9u(K>M޸7X>GC oM1IzueUP:iEQv|LzsJ1a}ßeg^<{^?)guwFR::\t [N%19`7|x9!As -@^mBIZl,a %eIKsp2郪I8gz"C _qi9Gګ/H;Mk"XD2yeuwu_슋/~T'R{?r|gvG{GX4, R!>35G&;-=.F3N7ewA/kdl:eT>Ba,k5]tRfoOH;./jJi5ˡIU %Ga+dm[PŌ7 o5QYeI25ڙ1NH E9\^EO/Sa!nH A̜T;!AQPyM1]rӆf) HW^&‹0X3O,a|=[DQx>f]S1BsiX b}ij䅥@.b[ IPjrw+RT3Ņd~-vm0~{h8a<ْ˥.`o~4A "q >:#Dhù\xb[LP?ڊBO=|5+UH)]{ݫ0p$mFd[212761Հ^+|9xfBF;2-С7X`+wJa7q7} r3x%#QzςX>:c#IH6/;= xȫMMݴ Do.fv_x3< ή9rnM$&<յjoHL#tJV@,BQ:L3i6O=`,W5cL4dwB/ؕ Y 0Ƈ߻? PglZs%E glL& i{zl :F[ F]tjNice†d(2Sۅ b)%*ѮȐ[B7-C#S[e _ς >7fO> x]||=0У)ʞkwawJz0dG/dgTsiR) ZJTUNmv5ٵb /,Ch7H_;U&EZ$yId6lZc[K5m *e@ rNCBi"C9=UjEeyuI!Bz Z/r.FXeViZ5Pwz=@]n&sz]?${^=F5(P> $j%¦|8ufir|(*P+:OyQbśր30 y >\(\ݲh>E7! endstream endobj 164 0 obj 3319 endobj 66 0 obj <> endobj 65 0 obj <>stream xzxTU7*tTPE*]:II>)Lͬ33)Q$*E*؎k{]{Bs=>I^{{oGЇ˻mɜ3,%K?:~<7.[';/ڌА|7~};w+$n#;B" :|a% 2f ̝([7/̟^,xFq᳢Mo^vN$'f#3b$xO"bb&1C,!fwKC=2bq/KȀH&z}ApAk5mYQg^w7t-WpEI*U'c v&hxU Rs14dEP`(P+98YYc4׻*)ؙ[6iSox29>_AUZ)TBzizlHz 3Pcn%#ufggLWA[28Nc)m׽f뀱(܈&n@6FqlỔRc%^_Vgnݳ-x* fcp0t{Iȝ߳w$̦:mxf4T#dɊJh+{̬wp^鶟nw~z+ե:7dFP(RjQ;Q]m$gkI]=x?t̟dJLh5 @^k*-,II<|K᳢ԖƵ5FnBmM$M&L#ኲ^4 Xр4JL8Ri~c>dR"t6->5N?y+\ e]!)QI3֗$)X f&X c$y^|sWG  sicI&h4،O.zИ'͍̝WY`JGNw)Q$[1CƁwO>uinh>AL7*Ri$4ɔΐΝ5.u~4u퀎I.kP)u$51׉s\׊@\DC)r+PcׅI z)VVKrmMg֌+oYUU&=hy4Nf?OY)25VDIooι9lNՙLrpфjL5ۨ;*QqD9D.KŤlz@K:0Q+Q̖\I h_!}y*yzB~gsϾ~wNqܡfjIxIxSg|_X !I2 |`8ݮdGF@S)GAmUWI^QoSê zБ33p=G_}iG0f[7/U <sM˦#惀>JG[wa |*zØvކ;x zho%v.`;E4E"}妥`o]0;Zwξ2z#)F)vf'< T8+8'qKlЋLQ# X}7 < =hܿ VMPzI0{!ZkrL > Je#d%jU"Һ:8]@7HPssӧ <j3N[z)Cy¡8pvvnR5Ith4)TWK~uT(HBn <Fȡ$w5aԫfRe`}{oNa7<}.쥔XY5X]ȩoIFɩ/fDl)|r䏾sO_yiHjOP Ac>y˸f/xqZai'\3ةn8?죌 ª:Ue'as9FMkB"Xn]PPe8L{+67-2L)ch\A1?E䖤9^ eO)G2r&RcvI'odux2, Z!Q̢~LJC d>A /yH5W嶹 apЉHo# '? Ȱ YC&h8:/ʬ[V-I'Em;>A./b7pd;$^[`WFV.!u>@2PnJsN4jZݹioU6pW9$ MЙX~ˡ-%:U9g&|:+wm'' y#"i֬WZTza Gwd}~1N%Ϯ۵3x >>/ :{iyU+V,J~^(MIKi";#8z8(xp8O֖.U7X6^/aU ,--9ܮkv9^4NjIK|uA6T0GC*M b"28 Y 6E qfi6{s t:?;Li@Z/M+["[('R`a팍%b]'\L7ؽs(Is,'4DfBd+-@@Q)\Hq!3?VC!{/j #A0$ɸYݼu](,xU~~i Gi4ަ_;۽ueZ%Zi{6W"}=fH6jZ+~xLD$[(nިZ)k!_c4S%6nHd8JPp'm:t=VR_nGV\:p.զpKIem(h9ӵ,|Ӻc<^NK$k3@W;E?Q`c{%44:^Ta(ZX =Ý[im>Rc͢YL 7TOXez'Y+5" !xi>*g^)V*Yyw?r#ѿz9'y \_]ԷUj$vKzcD@44>Z["➀/u[P(cqK|j4 IV_TaPT>ݽY*06 =٬Jer}]@@}6OTV+{d}0H #3r%chR&1Zk TiW675ZE e,sRkE ۷ ׼/~?oym׬&v4QUz7.a=e@·3ఒ nЄ%BLjdMU/qfq` !תyVSoj0w_y /H!_T7Z8wPB\O"龮WyʻniU1ﴷ;IN{zr B|4݀/C1*YQl1瘶2!i3R 2$[ U(w ==>`ʂ^f;ӟw'I@<&lZfwwrsE7<KIoD$wM%AL'Zy Tژ(aƎF$֤鯬>9xk74PxbO,Y߫:czBlKD2kb/Rq^HR"3p)Oۅu[ wwLenVz^aWj2z*FBhĵJ^s1|0+i AP!|CP) DjgGI[6wz{|;d+Q$4&ij^uzϻN4irISn{=Ư[/:@ h|e҃X2a[(\bՒ.y "y- \Qn>޲T)FH)6#OHFępfSJH={6.-V`q\Q \Xߜihp\N/o8tZx}ȡ$?VCCy xr`F*r){FaJRf_*؍هs/T#nEKMK`훦H ?_ $ pF:{+  @:CO!/ XsvOԤ#JfםFUl-uu5^ `0VdH\|z~_B.> tHCpɁgnPu3x C P 9B |MH86=ɗ^Ow_T0Oq#&k'wJbM"bK¯A֫S(Ūa f7%q[ŽӲ-&|C\7n7\ NMJ@(S(  qsC*ـh)jS7̉wt|a94{+c|*{ʩڅnEOYDo%ᣭx6ߝkciucXFɤ&h0YZ2 i˜0']Rxhn*P߫j󮗮mə/{FLgX3͕*z~7T1 a`f.ϗ)xloIL&6AUlfPL1cX`qXZ۰rNx;|u l[v7jD !w>tSW47œꀈ;'4R OL&G.tg̯!E\Hܯ$Sh0,t(2 2肺֏B@4ME,zm̞d1:(d1pR1Ҝ5]iy2C$aZ%ҖHm8OWQmf֬H+ ;^7rJb\qoG7dG *Jܞ%j >C/]TUK!L ?f)e@f,KKX$SR,`D$.t \(:秬_--VIl#([TB}m n ;/4pQIc|+dsKGVYn#{k̈&Ⴞ0 _IPZ+nlnqW61fglA\rL29Q/97Db/ʵ YHpVVA9Pk 4 d7dzOM½T'if.FChQ11gܙA+y:sSt2;QԨV   H4RVع+XJ7\w)ޞ|qo͂ϸgGv <~}q9 @d"@}!8%mjgAcA ֥"F@91#YWTW\[Pk.Xb,LVHqդ=RxI6 vsx0+7/}XVDb$y| T|0E.+_l|QzҬQܷ%ϯʐ2 =;;} ϗbvmt+@t"4hLFkr*Yi;@o4HG<>:UUHQ|Pk^s0'r[@|΁'y  8ȃ-VS(7s(EX fmV;!;s˞޸6,,N^ԃ &FiL&) ɗ>yp|mXcmf!N– 8 ϧ oUdukh FlK3zצ33۞CQy 2l׫>0+51:N=w̥3Z6BY=M +*BRقЋ?ߣ*OUP$ScpX> V L2d k{YnAw=&<ުz2$`Ҫwc C)|C8CSVV04aeb]eժrnD 1.W ';biɆjAe2PTBr)_ptЇ; lZRGRG^RFCۺ?JBf>ϸq>c/%b@GKtks3#YY-MXP&[ڶuHkKx??y/ FYc\^%0ߞl}oקcvXsҰwt:>D.{E8u':O 5Դ)>;oY \ v:~{Y#5Kfo})ӜX p Es(H2SsɈy_p?_`#{ss NZ S:8Dv 4:yc;)iqvq΁I7Kg8s$٪m:ǚ+- R{fv;R׏0&a&_>~~s9; E"(: DeX^p cf}oV &qh4Myތ =mO?U<죅>j*Dt^S{LwS%R 6GFZ!|B_D-KG{7Kԁ$UGjMA3|ְM .Z^Yղ/~XNSx,%eW-ܱN*P;O}.4fWO[c t o6PޗՑWgR $U԰%kjh mlU6{[1KH Bp!}"R-+ڲZ"5"ֆY\SY,zvd endstream endobj 165 0 obj 8730 endobj 59 0 obj <> endobj 58 0 obj <>stream xyxT1ko@DƊ***EAQHo!!}z̚dzI&$!RNЄ"M Esx,Qx7ϽC<{gILZ[_y&3pL?hܹO=ܛ˭ܛy{hG;B b ''p*puVT +Z-Y?1e+gLWZ4sr7̪Y;{JmTẢi$KW,xjӏNO\¨^|r]& 1x(&f/b41J㱇 9ӧܖ۞#o@^'#fj<+?;B|[/Ԡ.tg?]pw{. yvȹ'w{V,3}m`/Uޟ;?mLw:Id<9ޅLj1)),- 3Aa貺:G&~Lj4U/Gc-˽ zBU&k.ҙ%zFh %RjR*'޼/24#fT)KWI&rٜ@)"^ad룦X]T};tV9rPS2nj:IZ/Pz^.݄@.7;ќ$L۰Cou9֩v[ PcP[E^;HmJ(*^m [/o8ÎW@*bƎ!gt„W(Ԩe,O׶0Q' $xRC'M'U'&z@Q:=7ѨWO8 Gjf )qX{t^Z., d\哲 Ћ'V-e8E1)*¨18$CDD*q_ۊߒ\3FN>hZhV$Qk5vJ䷘5%p)y/GLTT1: fI(]\|zC"Q_32ޜ}Qܓ%M8CL8q&@3d™2BGI_zOd~d^tKR9:a'tnt%]͟$Oۃ`CvEX1"$JѨ6 dg W,ZtUGKJТ{d ; Z_tlވ8DoXMXn,҂ pQxΉ>ouvp" ҪtE%@b$ 0j(K1Sh-Aw4F%u%l0ʄL ƌ%++a%vRL&iEJUFK~oP=j?@J_. }bke C:@'s-믝<t˹ )?@Q>> R\'@'q{+nFO:uit,_,'v?ȲձxO?r>}ѳ^ w7m$]!i/@,N&^ (q]w1N2^`aCuȹt/qM-$֦j^ #ƖUخ6$T-%c`ˍ1K@d3- -͛鶴/N !ip$(M6S^˧:s+ y8ZI_ ҁ'ŧ˙ *c#G;-:nw;NTS|`lBWWom:hYl F.GQ;8_Qn7ƣlF&BdTO:Қ,@vbL2mWUu˼-HWܼ~_qh]:㾊g2%cy-Fq ;M@#Lؔ.G%5Z3-RFz Sa<.ƾ>`J@12kers4g 8Ld8 GWZ1ptm""/7pY:ٹ _~RS=>+E}w=9 Ds" uW*Ʈ}w^| Y=6 )/8p8ѵۍ TB撕[r#.[Z_3S#ic} ukGQ @﹂q 7n \ PI8ȂԸO, '\:ooP. X TS#eRX |J? yI]pcgc}c4ԺN j;*߀)? ߄լ[V?T_4lB!d{Yiz>3`+-"*DSXH|1lQhW$]% ?rsh]M7\̎±3>~}EN:cn(~3/k:V(.!Gg{ Dj`%XF DSB:oO'V SD˾WƬsH#K:Id9{)[ᥤHKBXdRȖ7P7xiG]g"N" pK+lbI V[]mjz_$Eb{P ]l U‮]_pgJ~,K(D5\s-0H{[%&TiK\.'=&+2{A~gvLHvymTk%jߺw{!B=;1jB@.XV&m6|wk}}>ٿ1, b#S\X) |{^F 7nYy $zGZF* cE7.\- R}2L#xhmk7y2ll|$bm T0VJ(֟M2bϥdZ+Uy>č2?ػ㪲ToNL4w%uAIZba3-9aiΡZv|i\nƕ+fLv쨲zᆒ"*IoQh;ߗ2$*[/ cWe\|(qMQ 'dTm s7T!~׺٦)R0ւXrKO8@ nHB7ܮK|IXaE*ZWwp+ER n>ϱE$O.DA*e&2(pkܜYkV9 j"hz8 -%.{0_h, ,iS,I0-Y&WDѤ|N˝20PaI! 6[FEѣN$`qydN}]7fV@7 郊"J.kYg^ eHI18}05վvFB%}iAhS5j Zo+lDa= ~o[~k !b+ҏ/ ðJvKov0zW>ٻvޏ+`]c9pSt;7tu&V EQ}g۰sVwa*ԙeHC.ݹvg.KفY ^ z위{zQVF!q.+.l *Bouw1 WX{Z NT`öepqj4fjGkCc|1`">Xr=0lC WºCzznS~ۮ BĚp3XRQD_@A*YIÍ JW_$fcdh| o$qpMOi6!0 76H5{CQFT9ʁTs`dgQOJ?ւcM*X(k#fpO Ř9e͢o[tlxdg$t+ +7 Ou8Ǩ;?*Ky0Fu.G*ĭ. i|8Y|^O}&)gh8k {kL=+w 6& S^{$ _\8[ځPXԊf #?|(ʨ'2^#W*eRTqk0+au#lɩ|ҋ>:Xe%Wt<( qHzL|dF }K_^AgR\- $ w ;p?mh=I_~A_BI2vҚrC7k KaB())N+"?lںyȲ 3`qz0'2K8s ; O /.p->X(W*ntt q`ĕY<0?34ӳB[}ܵcC%"&ޒy }" ٩ޒbL'fˆ!q|p?~#N>#>8t(B9Or9E\NeTO44܋PSKIZl#lz}UYJDTe>̠K od;Ʉ)Z)*z+I~;vgfy5F(EDMܩ__[S]|+v~&}}rI~'2ղ.tv셋ص>6i@;>ɗkFMPQά U`Iy@'a e$b8ӑjs3yH+FIN=6rQUR+**V詋~r<dMuG7\җ @e1²(ɠMѠ!K_ʲ $.Zh@.r|AA$Tf;e"ɜ5EF- :R` [9#\y F安;zK(d e|b*_-;2,ڊZck8KR.Ց u4]P&/[A CаO3gWkG{8`D U fpUܹgSkNQ:c|)u{ 2ji]r$7cBhk4fvzgAIUdmZgoƿΟM/A'3wI endstream endobj 166 0 obj 7011 endobj 118 0 obj <> endobj 117 0 obj <>stream x]]H6Rq0Y $|HPTF%tujp9dFhdhHV dHl"QEEiuYqfea\.ˤa "ߤD~vJ~ۏG(xMR4׫M U? PjECbP Q–P5}2{2zJj޻f06qw*r=~H1IDan _ak0zj6c>*@?/<f V2S M I_{ &-4`~J?D9fY!g͉(dG%D]jpcl 8XxInpM%obGG062Lٌ$9d$z,=W"^HǡRyIQ~AYїz<"k`]g4Orepϋe,k3d5ʋuUt<]Yu`oIK{V]ɧIƗ]颿L3""~Q?ΚDm9fR0015l&[ݞ0C> endobj 42 0 obj <> endobj 39 0 obj <> endobj 36 0 obj <> endobj 33 0 obj <> endobj 30 0 obj <> endobj 27 0 obj <> endobj 24 0 obj <> endobj 18 0 obj <> endobj 13 0 obj <> endobj 10 0 obj <> endobj 119 0 obj <> endobj 74 0 obj <> endobj 67 0 obj <> endobj 60 0 obj <> endobj 2 0 obj <>endobj xref 0 168 0000000000 65535 f 0000054135 00000 n 0000224499 00000 n 0000053902 00000 n 0000054183 00000 n 0000050257 00000 n 0000000015 00000 n 0000000341 00000 n 0000152143 00000 n 0000151871 00000 n 0000222256 00000 n 0000171031 00000 n 0000170760 00000 n 0000221806 00000 n 0000054238 00000 n 0000054268 00000 n 0000169027 00000 n 0000168775 00000 n 0000221397 00000 n 0000050417 00000 n 0000000360 00000 n 0000002544 00000 n 0000165651 00000 n 0000165391 00000 n 0000221032 00000 n 0000155255 00000 n 0000154718 00000 n 0000220466 00000 n 0000181128 00000 n 0000180935 00000 n 0000220328 00000 n 0000179843 00000 n 0000179604 00000 n 0000220168 00000 n 0000173865 00000 n 0000173512 00000 n 0000219653 00000 n 0000195707 00000 n 0000195468 00000 n 0000219493 00000 n 0000187947 00000 n 0000187551 00000 n 0000218975 00000 n 0000054311 00000 n 0000050569 00000 n 0000002565 00000 n 0000005475 00000 n 0000054420 00000 n 0000050721 00000 n 0000005496 00000 n 0000005793 00000 n 0000054507 00000 n 0000050865 00000 n 0000005813 00000 n 0000007735 00000 n 0000181824 00000 n 0000181473 00000 n 0000218460 00000 n 0000210333 00000 n 0000209889 00000 n 0000223934 00000 n 0000054550 00000 n 0000051009 00000 n 0000007756 00000 n 0000010486 00000 n 0000201050 00000 n 0000200540 00000 n 0000223377 00000 n 0000054648 00000 n 0000051161 00000 n 0000010507 00000 n 0000012766 00000 n 0000197112 00000 n 0000196807 00000 n 0000222932 00000 n 0000054757 00000 n 0000051313 00000 n 0000012787 00000 n 0000013218 00000 n 0000054866 00000 n 0000051457 00000 n 0000013238 00000 n 0000014831 00000 n 0000054909 00000 n 0000051601 00000 n 0000014852 00000 n 0000016260 00000 n 0000054974 00000 n 0000080976 00000 n 0000104344 00000 n 0000123903 00000 n 0000123957 00000 n 0000051777 00000 n 0000016281 00000 n 0000018954 00000 n 0000124033 00000 n 0000150639 00000 n 0000150671 00000 n 0000051953 00000 n 0000018975 00000 n 0000020287 00000 n 0000150769 00000 n 0000052098 00000 n 0000020309 00000 n 0000022620 00000 n 0000150824 00000 n 0000052253 00000 n 0000022642 00000 n 0000025443 00000 n 0000150945 00000 n 0000052408 00000 n 0000025465 00000 n 0000028471 00000 n 0000151044 00000 n 0000052555 00000 n 0000028493 00000 n 0000031382 00000 n 0000217673 00000 n 0000217453 00000 n 0000222684 00000 n 0000151121 00000 n 0000052702 00000 n 0000031404 00000 n 0000034146 00000 n 0000151200 00000 n 0000052857 00000 n 0000034168 00000 n 0000037112 00000 n 0000151321 00000 n 0000053012 00000 n 0000037134 00000 n 0000039670 00000 n 0000151442 00000 n 0000053167 00000 n 0000039692 00000 n 0000041867 00000 n 0000151530 00000 n 0000053314 00000 n 0000041889 00000 n 0000044335 00000 n 0000151618 00000 n 0000053461 00000 n 0000044357 00000 n 0000046535 00000 n 0000151673 00000 n 0000053608 00000 n 0000046557 00000 n 0000049087 00000 n 0000151750 00000 n 0000053755 00000 n 0000049109 00000 n 0000050235 00000 n 0000151827 00000 n 0000154696 00000 n 0000165368 00000 n 0000168753 00000 n 0000170738 00000 n 0000173490 00000 n 0000179582 00000 n 0000180914 00000 n 0000181452 00000 n 0000187529 00000 n 0000195446 00000 n 0000196786 00000 n 0000200518 00000 n 0000209867 00000 n 0000217431 00000 n 0000218439 00000 n trailer << /Size 168 /Root 1 0 R /Info 2 0 R >> startxref 224630 %%EOF apq-3.2.0/legacy/win32.tex000066400000000000000000001126471171626402600152450ustar00rootroot00000000000000% win32.tex - $Id: win32.tex,v 1.2 2004/10/25 02:06:08 wwg Exp $ % Warren W. Gay % % Needs: % gnat-3.15p-nt.exe % gnatwin-3.15p.exe % \documentclass[english]{report} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \setcounter{secnumdepth}{3} \setcounter{tocdepth}{3} \usepackage{graphicx} \makeatletter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. \newenvironment{lyxcode} {\begin{list}{}{ \setlength{\rightmargin}{\leftmargin} \setlength{\listparindent}{0pt}% needed for AMS classes \raggedright \setlength{\itemsep}{0pt} \setlength{\parsep}{0pt} \normalfont\ttfamily}% \item[]} {\end{list}} \usepackage{babel} \makeatother \begin{document} \title{APQ-2.1 Win32 Build Instructions} \author{Warren W. Gay} \date{September 24, 2003} \maketitle \chapter{Getting Started} This document provides a guide to those people who prefer to compile products they install, from the source code. This guide specifically deals with compiling and installing APQ in a win32 environment. What do you get from APQ in the win32 environment? The following are the products of this compile and install procedure: \begin{itemize} \item apq\_myadapter.dll for MySQL support \item apq-mysql.ads generated spec for MySQL support \item libapq.a static library for APQ client programs \item APQ static spec and body sources \item APQ-2.1.EXE Installer program \end{itemize} You may also choose which databases you wish to support. For example, you may only wish to include MySQL support for the win32 environment. Or instead, you may choose to support all products% \footnote{At the present time, this is PostgreSQL and MySQL.% }, since PostgreSQL databases may reside on hosts other than the win32 environment that you are using. The choice is yours. \section{Does APQ Need CYGWIN?} No. When APQ is built and installed using these instructions, is completely independent of any CYGWIN tools and libraries. You may run your APQ application in or out of a CYGWIN environment. It only requires the win32 environment, and those libraries that come installed with GNAT. APQ does however, require the use of CYGWIN environment tools, to perform the build process. The compiler used is only GNAT and GNAT's underlying gcc.% \footnote{Microsoft's tool set is also required to compile some components.% } However, the win32 environment is not rich in the way of scripted build processes, so the CYGWIN POSIX like environment is used instead. \section{Tools Needed} In order to build the APQ library from sources, you will need a number of tools installed: \begin{itemize} \item CYGWIN (see below for list) \item Microsoft Visual Studio (Version 6.0)% \footnote{It is possible that an earlier version such as 5.0 might be sufficient, but this is untested.% } \item makensis (Nullsoft Scriptable Install System)% \footnote{Dowload it from nsis.sourceforge.net/site/index.php% } \item GNAT Compiler (3.14p was tested) \end{itemize} The makensis is actual somewhat optional. The actual build does not require this tool. If you are prepared to move the various components into the correct places (or custom locations), you do not need it. However, the built APQ-2.1.EXE install program is highly recommended, because it provides the following benefits: \begin{itemize} \item makes installation easy and foolproof \item allows you to choose what components to install \item registers its version in the registry \item is {}``GNAT aware'' \item provides an uninstall capability% \footnote{From the Control Panel, select Add/Remove Programs.% } \end{itemize} \section{CYGWIN Tools} In order to provide a POSIX like environment, the CYGWIN tools are necessary to facilitate the complex process of building the APQ library from sources. If binary versions of the library are available, you may want to use them instead. The following list are the CYGWIN tools needed: \begin{itemize} \item bash (shell) \item sed \item sort \item ar \item tar \item cp \item rm \item chmod \item mkdir \item make \item cygpath \item uname \end{itemize} \chapter{PostgreSQL Preparation} This section shows you what you need to do to prepare the PostgreSQL components of APQ. If you do not plan to provide win32 support for PostgreSQL, then you can skip to the next chapter. Note that this chapter is only about preparing a PostgreSQL client facility. Installing and using a PostgreSQL database under Windows is well beyond the scope of this document. \section{Shell Sessions} This chapter will assume that you are using the cmd.exe native shell sessions (ie. not CYGWIN). \section{Source Code} This document will assume that your 3rd party source code will be downloaded and unpacked in the directory: \begin{itemize} \item c:\textbackslash{}work \end{itemize} If you don't have this directory, then create one now. \subsection{Download Sources} Download the PostgreSQL sources that you plan to use. In this example the download file: \begin{lyxcode} postgresql-base-snapshot.tar.gz \end{lyxcode} was used. You may want to choose a stable production quality release instead. Once you have downloaded your source file, unpack it to your work directory. Here we will use the file shown above. \subsection{Unpack Sources} Unpack your PostgreSQL sources to the work subdirectory. Using the file downloaded above, the sources unpacked into the directory named: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql-snapshot \end{itemize} If you downloaded a production level release, then {}``snapshot'' was likely replaced by a version number. Change to the src subdirectory, and then list the files there. You should find a file named win32.mak (using cmd.exe shell): \begin{lyxcode} {\footnotesize C:\textbackslash{}work>~cd~postgresql-snapshot\textbackslash{}src\textbackslash{}interfaces\textbackslash{}libpq}{\footnotesize \par} {\footnotesize C:\textbackslash{}work\textbackslash{}postgresql-snapshot\textbackslash{}src\textbackslash{}interfaces\textbackslash{}libpq>~dir~/w}{\footnotesize \par} \end{lyxcode} \section{Compile PostgreSQL Components} In that directory, you should see a file named win32.mak (the prompt here will be abbreviated): \begin{lyxcode} {\footnotesize C:>~nmake~/f~win32.mak}{\footnotesize \par} \end{lyxcode} Note: you should always check with the documentation that comes with your source code. These directions should work on all recent releases up to and including 7.4beta2. Build and install instructions often change, so check for them, with each new release. \subsection{Check for libpq.dll} This should now build the PostgreSQL client library libpq.dll. This process might fail at some point.% \footnote{Release 7.4beta2 failed building a component after libpq.dll.% } This can be ignored, if the important part (libpq.dll) was built. Change to the dll directory to check: \begin{lyxcode} {\footnotesize C:>~cd~interfaces\textbackslash{}libpq\textbackslash{}Release}{\footnotesize \par} {\footnotesize C:>~dir~libpq.dll}{\footnotesize \par} ~{\footnotesize Volume~in~drive~C~has~no~label.}{\footnotesize \par} ~{\footnotesize Volume~Serial~Number~is~587F-CB45}{\footnotesize \par} ~{\footnotesize Directory~of~C:\textbackslash{}work\textbackslash{}postgresql-snapshot\textbackslash{}src\textbackslash{}interfaces\textbackslash{}libpq\textbackslash{}Release}{\footnotesize \par} {\footnotesize 09/19/2003~~10:42p~~~~~~~~~~~~~~90,112~libpq.dll}{\footnotesize \par} ~{\footnotesize ~~~~~~~~~~~~~~1~File(s)~~~~~~~~~90,112~bytes}{\footnotesize \par} ~{\footnotesize ~~~~~~~~~~~~~~0~Dir(s)~~32,435,912,704~bytes~free}{\footnotesize \par} {\footnotesize C:>}{\footnotesize \par} \end{lyxcode} The example session above, shows that the libpq.dll file was successfully created. \section{Create Staging Area} Now create a directory to place the important PostgreSQL files into. Create the following directories: \begin{description} \item [c:\textbackslash{}postgresql]top level staging directory \item [c:\textbackslash{}postgresql\textbackslash{}include]directory of C header files for compiling \item [c:\textbackslash{}postgresql\textbackslash{}lib]optional directory for DLL \end{description} These directories create a place for the PostgreSQL DLL file and the C header files.% \footnote{It is possible to install everything from its original location, provided that you answer the configuration prompts correctly. But this install procedure has been designed to keep things simple.% } \subsection{Install the DLL File} Copy the PostgreSQL DLL file into the staging area. You want to copy the file: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql-snapshot\textbackslash{}src\textbackslash{}interfaces\textbackslash{}libpq\textbackslash{}release\textbackslash{}libpq.dll \end{itemize} to the location: \begin{itemize} \item c:\textbackslash{}postgresql\textbackslash{}lib\textbackslash{}libpq.dll \end{itemize} If this directory is not on your windows PATH, you will need to either put it on your path, or place it somewhere else that is on the path. One suggestion is GNAT's bin directory. On the author's system, this would be: \begin{itemize} \item c:\textbackslash{}opt\textbackslash{}gnat\textbackslash{}bin\textbackslash{}libpq.dll \end{itemize} \begin{lyxcode} \end{lyxcode} \subsection{Install C Header Files} Now it is necessary to copy over the C header files that APQ will need to examine. Copy all the files from: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql-snapshot\textbackslash{}src\textbackslash{}interfaces\textbackslash{}libpq\textbackslash{}{*}.h \end{itemize} to the directory: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql\textbackslash{}include \end{itemize} \begin{lyxcode} \end{lyxcode} There are a few other C header files that APQ will need. Copy the header files from: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql-snapshot\textbackslash{}src\textbackslash{}include\textbackslash{}{*}.h \end{itemize} additionally to the directory: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}postgresql\textbackslash{}include \end{itemize} \begin{lyxcode} \end{lyxcode} Now the PostgreSQL preparation is ready for APQ. \chapter{MySQL Preparation} Like the PostgreSQL chapter, this chapter is optional. If you do not plan to include MySQL client support, then skip to the next chapter. Just be sure that you include support for at least one of PostgreSQL or MySQL! \section{Shell Sessions} Where shell sessions are required, this chapter is assuming that you will be using cmd.exe sessions (ie. not CYGWIN). \section{Create Work Directory} If you don't already have a C:\textbackslash{}WORK directory, then create one now. Note: numerous shortcuts are possible in this procedure if you know what you are doing. We will be taking a cautious approach to the procedure, so that the steps will be easy to understand, and to avoid confusion. \section{Unpack MySQL Sources} Unpack (or unzip) the tar/zip file into the C:\textbackslash{}WORK directory. Here we used WinZip to unpack the sources into a subdirectory. \includegraphics[scale=0.5]{winzip.jpg} Note carefully that the {}``Use folder names'' checkbox is checked. \section{Build MySQL DLL} You will need to start the Microsoft Visual Studio 6.0 at this point.% \footnote{Check with the MySQL documentation for the necessary build instructions. This procedure was effective for MySQL version 4.0.14b. If their instructions vary from these, follow theirs.% } Select File->Open Workspace, and then browse in the unpacked subdirectory for a file named mysql.dsw : \includegraphics[scale=0.5]{open_workspace.jpg} Next, from the Build->Set Active Configuration Menu, choose libmsql - Win32 Release (or Win32 Debug if you are debugging changes). \includegraphics[scale=0.5]{set_active.jpg} Then compile by pressing F7. If all went well, you should see a successful completion of the compile: \includegraphics[scale=0.5]{comp1.jpg} \section{Create MySQL Staging Area} \marginpar{You may find that you already have a MySQL lib\textbackslash{}debug and lib\textbackslash{}opt library directory. The former has components for debugging while the later contains optimized libraries.% }This APQ build procedure will assume that you have the following directories in place for the client MySQL components: \begin{description} \item [c:\textbackslash{}mysql]top level MySQL directory \item [c:\textbackslash{}mysql\textbackslash{}include]containing all client MySQL C header files \item [c:\textbackslash{}mysql\textbackslash{}bin]containing the libmySQL.dll DLL file \item [c:\textbackslash{}mysql\textbackslash{}lib]containing the libmySQL.lib import file \end{description} Your directory structure can vary from this theme, but we'll refer to the directories in this document as noted above. You may have installed MySQL from binary distributions. If it included the install of a libmySQL.dll client library (as it should), you might already have include files, that were installed with the dll. Note however, the author has found that you need more than the include files that were provided, for the compile of the APQ component. So it is recommended that you follow this procedure, including the staging area. \subsection{Staging Directories} Create the c:\textbackslash{}mysql staging area directories and subdirectories as shown in the prior section, if they don't already exist. If you are using other directories, you may want to write your notes on this document page. \subsection{Copy Include Files} Copy the include files from:% \footnote{The directory name obviously reflects MySQL version 4.0.14b, which may be different in your case.% } \begin{itemize} \item c:\textbackslash{}work\textbackslash{}mysql-4.0.14b\textbackslash{}include\textbackslash{}{*}.h \end{itemize} to the directory: \begin{itemize} \item c:\textbackslash{}mysql\textbackslash{}include \end{itemize} \subsection{Copy the libmySQL.dll File} If you built the libmySQL.dll file from sources, you will want to install that. Copy the file: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}mysql-4.0.14b\textbackslash{}lib\_release\textbackslash{}libmysql.dll \end{itemize} to your directory: \begin{itemize} \item c:\textbackslash{}mysql\textbackslash{}bin\textbackslash{}libmysql.dll \end{itemize} You will need to make certain that this DLL is on the PATH, in order to be executable. You may prefer to put the DLL with the GNAT binary directory such as: \begin{itemize} \item c:\textbackslash{}opt\textbackslash{}gnat\textbackslash{}bin\textbackslash{}libmysql.dll \end{itemize} instead. The choice is up to you. \subsection{Copy the Import Library} You will need the import library to assist with the linking of the APQ DLL file. Copy the file: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}mysql-4.0.14b\textbackslash{}lib\_release\textbackslash{}libmysql.lib \end{itemize} to your directory: \begin{itemize} \item c:\textbackslash{}mysql\textbackslash{}lib\textbackslash{}libmysql.lib \end{itemize} Now your staging area for MySQL is ready for APQ. \chapter{Compiling APQ} Now we are ready to start into building the APQ components. The first step is one of configuration. APQ has been designed to allow PostgreSQL and/or MySQL support to be included. The preceeding chapters documented preparations for both, but either of those database products can been omitted.% \footnote{As long as at least one is chosen.% } We will assume in this document, that you want all the support you can build, and so will build both. However, you can easily bypass one or the other, with the appropriate answers to the scripted prompts. \section{Shell Sessions} The APQ work will primarily use a CYGWIN shell session using the bash shell. Open a CYGWIN bash session now, and make a work subdirectory there, and then unpack APQ and finally change to that directory. In this section you may need to switch between this CYGWIN bash session, and a cmd.exe session window. If you downloaded APQ-2.1, then your unpacked sources should probably be unpacked to a directory named: \begin{itemize} \item c:\textbackslash{}work\textbackslash{}apq-2.1 (ie. /cygdrive/c/work/apq-2.1 for CYGWIN) \end{itemize} \section{Configuration} Before you can build the APQ sources, you must configure them. Run the shell script ./configure in the CYGWIN bash session: \begin{lyxcode} \$~./configure THIS~IS~A~WIN32~INSTALL~OF~APQ-2.1~: - -{}-Building~gnat\_info~command,~to~obtain~some~registry -{}-information~about~your~installed~GNAT~compiler.. - You~have~GNAT~3.14p~installed~: \end{lyxcode} Initially the script should identify this as a WIN32 configure step% \footnote{The script eventually execs the script win32\_config.% }. Then the program gnat\_info.adb is compiled to allow the configuration script to access the registry. It locates where your GNAT compiler is installed, and later tests to see if APQ has already been installed. If APQ is found to be installed, you will need to uninstall it to compile APQ successfully.% \footnote{If you installed APQ manually, this test will likely fail to detect that APQ is already installed.% } \subsection{Configure Edit Mode} The script will ask for a number of pathnames for input. This is more easily done, if editing is permitted at the input prompts. But to do this, the script must know which edit mode the user prefers: \begin{lyxcode} ~~Please~choose~your~preference~for~input~editing ~~bindings: - ~~e~-~emacs~mode ~~v~-~vi~mode ~~n~-~neither - Choose~e/v/n~? \end{lyxcode} So the script prompts you for the editing mode you want to use. Choose: \begin{description} \item [e]for emacs editor bindings \item [v]for vi editor bindings \item [n]for no special editing \end{description} If you are not in the habit of using emacs or vi UNIX/Linux editors, then you might prefer to use {}``n''. This document will assume that you have chosen {}``e'' for emacs mode, because this permits some special features to be highlighted, for the convenience of power users. \subsection{Microsoft Toolset Check} After answering the edit mode prompt, you'll get an assessment made of the Microsoft Toolset. If you have Microsoft Visual Studio 6.0 installed, you should see: \begin{lyxcode} Choose~e/v/n~?~e - You~seem~to~have~the~Microsoft~Toolset~available.. \end{lyxcode} Here the script is confirming that you have the necessary tools to build the APQ\_MYADAPTER.DLL file. Certainly if you built the MySQL or PostgreSQL DLL files, you should receive a favourable report here. However, it is possible that those components be downloaded in binary form instead and then placed into the work directories indicated. If you have the Visual Studio installed, and you don't receive confirmation of this from the script, then check your PATH variable within the CYGWIN environment. The PATH setting probably needs adjustment. The Microsoft Toolset required by APQ includes: \begin{description} \item [CL]the C/C++ Compiler \item [LIB]the library utility for creating export and import files \item [LINK]the Microsoft C/C++ linker utility \end{description} Before you despair of not owning the Microsoft toolset, consider: \begin{itemize} \item If you are not building support for MySQL, you do not need them. \item If you have downloaded a binary form of APQ\_MYADAPTER.DLL you do not need them. \end{itemize} If on the other hand, you are planning to compile APQ, with MySQL support, and lack the Microsoft toolset above, then you must now locate and download a binary copy of apq\_myadapter.dll. Otherwise, you will be required to use the Microsoft toolset to create that dll file. This file may be available in your package, or perhaps made available separately, to reduce download file sizes. \subsection{Choosing MySQL Support} Now you must decide whether or not you want your installed copy of APQ to include MySQL support. The only real reason not to include it is to save the installer time and effort. Otherwise, I suggest you include it for flexibility. \begin{lyxcode} Questions~for~MySQL~: - Installing~MySQL~database~support~?~(Yes/No)?~Yes \end{lyxcode} I'm going to assume that you are answering yes, to get your money's worth from APQ. \subsection{Specifying MySQL Pathnames} Once you answer \emph{Yes} to the MySQL support prompt, you are prompted for two more pathnames: \begin{lyxcode} {\footnotesize Questions~for~MySQL~:}{\footnotesize \par} - {\footnotesize Installing~MySQL~database~support~?~(Yes/No)?~yes}{\footnotesize \par} {\footnotesize Windows~pathname~to~MySQL~include~directory~:~c:\textbackslash{}mysql\textbackslash{}include}{\footnotesize \par} {\footnotesize Windows~path~of~MySQL~DLL~file~is~~~~~~~~~~~:~c:\textbackslash{}MySQL\textbackslash{}BIN\textbackslash{}libmysql.dll}{\footnotesize \par} {\footnotesize Windows~path~to~libmysql.lib~file~~~~~~~~~~~:~c:\textbackslash{}mysql\textbackslash{}lib\textbackslash{}libmysql.lib}{\footnotesize \par} \end{lyxcode} While the session appears to show three prompts, the pathname of the MySQL DLL is determined by the script. It does this by looking for libmySQL.dll on your PATH. If your PATH is not correctly set, or the DLL not correctly installed, then this step will fail. Correct the PATH and try again, if necessary. The two important inputs are: \begin{enumerate} \item Directory pathname to MySQL include files \item Pathname of the MySQL DLL import file (libmysql.lib) \end{enumerate} Your pathnames may vary from the example, but these are the ones I am using for illustration purposes. \subsection{Choosing PostgreSQL Support} Like MySQL, you can choose whether or not you want to build support for it: \begin{lyxcode} Questions~for~PostgreSQL~: - Installing~PostgreSQL~database~support~?~(Yes/No)?~yes \end{lyxcode} Here, once again, we are assuming you want to get your money's worth. \subsection{Specifying PostgreSQL Pathnames} Currently, PostgreSQL only needs to know the location of the C header (include) files: \begin{lyxcode} {\footnotesize Questions~for~PostgreSQL~:}{\footnotesize \par} - {\footnotesize Installing~PostgreSQL~database~support~?~(Yes/No)?~yes}{\footnotesize \par} {\footnotesize Windows~pathname~to~PostgreSQL~include~directory~:~c:\textbackslash{}postgresql\textbackslash{}include}{\footnotesize \par} {\footnotesize Windows~path~of~PostgreSQL~DLL~file~is~~~~~~~~~~~:~c:\textbackslash{}OPT\textbackslash{}GNAT\textbackslash{}bin\textbackslash{}libpq.dll}{\footnotesize \par} \end{lyxcode} The script locates the PostgreSQL DLL file libpq.dll, by searching the PATH variable. If the script fails to locate the DLL file, then you may need to change the PATH (under CYGWIN) and/or make the DLL file in a directory that is searched by the PATH variable setting. Then try the configure step again. In this example, I will just hit return and accept the default. But you may specify a different directory from this. \subsection{Concluding the Configuration} The configuration session should look something like the following: \begin{lyxcode} {\footnotesize You~seem~to~have~the~Microsoft~Toolset~available..}{\footnotesize \par} - {\footnotesize Questions~for~MySQL~:}{\footnotesize \par} - {\footnotesize Installing~MySQL~database~support~?~(Yes/No)?~yes}{\footnotesize \par} {\footnotesize Windows~pathname~to~MySQL~include~directory~:~c:\textbackslash{}mysql\textbackslash{}include}{\footnotesize \par} {\footnotesize Windows~path~of~MySQL~DLL~file~is~~~~~~~~~~~:~c:\textbackslash{}MySQL\textbackslash{}BIN\textbackslash{}libmysql.dll}{\footnotesize \par} {\footnotesize Windows~path~to~libmysql.lib~file~~~~~~~~~~~:~c:\textbackslash{}mysql\textbackslash{}lib\textbackslash{}opt\textbackslash{}libmysql.lib}{\footnotesize \par} - {\footnotesize Questions~for~PostgreSQL~:}{\footnotesize \par} - {\footnotesize Installing~PostgreSQL~database~support~?~(Yes/No)?~yes}{\footnotesize \par} {\footnotesize Windows~pathname~to~PostgreSQL~include~directory~:~c:\textbackslash{}postgresql\textbackslash{}include}{\footnotesize \par} {\footnotesize Windows~path~of~PostgreSQL~DLL~file~is~~~~~~~~~~~:~c:\textbackslash{}OPT\textbackslash{}GNAT\textbackslash{}bin\textbackslash{}libpq.dll}{\footnotesize \par} - ~{\footnotesize ~~~You~are~now~ready~to~'make'}{\footnotesize \par} - To~proceed~with~the~build,~perform~the~following: - \$~make-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-{}-(do~'make~clean'~prior~to~rebuilds) \$~make~installer-{}-{}-{}-(optional) \$~make~install \end{lyxcode} You may of course, choose different directories and preferences. This document is just a guideline. At this point, you should receive a message indicating that you are ready to perform a {}``make''. If you are making changes and need to rebuild the sources, perform a {}``make clean'' first. If you are making changes to the installer programm, then you can repeat builds of it by simply doing a {}``make installer''. A {}``make install'' will make the installer program, and then execute it. \section{Building APQ} If you have all of the CYGWIN components required, then this should be the easiest part of the WIN32 build process. \subsection{Win32 Makefile} The APQ components are compiled using a Makefile that is tailored to the Windows environment. The actual make file used is named: \begin{itemize} \item Makefile.win32 \end{itemize} When the configure script ran% \footnote{The configure script invokes script win32\_config under Windows.% }, it also created a symlink to the Makefile.win32 file. The symlink is named: \begin{itemize} \item GNUmakefile \end{itemize} This symlink permits the make command to reference Makefile.win32 by default. If you must customize the make file, be sure to edit Makefile.win32. The configuration process also created another file: \begin{itemize} \item config.win32 \end{itemize} The configured values for the build are included in the config.win32 file. This is the file that is included from Makefile.win32. If you need edit configuration values, edit that file. Just be aware that those changes will be lost if the configure script is successfully rerun. To compile the APQ components, in a CYGWIN bash session, using the APQ source directory% \footnote{Using our example this would be /cygdrive/c/work/apq-2.1.% } as the current directory, you just type make: \begin{lyxcode} \$~make \end{lyxcode} This should successfully build everything that is required, depending upon the options you selected in the configuration process. The following products should come out of the build: \begin{description} \item [apq-mysql.ads]This is generated for MySQL support only \item [apq\_myadapter.dll]This is for MySQL support only \item [libapq.a]A static GNAT library for APQ \end{description} Additionally, all static APQ spec and body sources must also be installed. \section{Rebuilding/Configuring} Sometimes things don't go right on the first try. To allow for that possibility, the following tools are at your disposal: \begin{enumerate} \item make clean \item make clobber \end{enumerate} \subsection{Make Clean} Use this when you want to delete all compiled objects, binary components and generated sources (like apq-mysql.ads). This allows you to tweak as necessary, but rebuild again without redoing the configuration process. \subsection{Make Clobber} This goes one step further than {}``make clean'', in that it destroys the configuration information that was gathered. Use this procedure when you want to start over from scratch. \section{Installing APQ} Once you have successfully built APQ, you need to install its components. If it were only a few binary files, you could do this by hand. However, in addition to the library components, the Ada specification and body source files must be installed in the correct place.% \footnote{Some of the Ada bodies are mandatory because of the generics that must be compiled by GNAT. So APQ just installs them all.% } If you perform {}``make installer'', this will build the installer program for you. If you perform a {}``make install'', it will build the installer program and invoke it. \begin{lyxcode} \$~make~install \end{lyxcode} The installer used is a nice GUI installer, provided complements of the Nullsoft Scriptable Installer System folks. Visit their website at: \begin{lyxcode} nsis.sourceforge.net/site/index.php \end{lyxcode} When the installer is run, simply follow the GUI prompts. \section{Uninstalling APQ} If you are making changes, you'll frequently need to uninstall and re-install. This is easily provided for in the Control Panel. Choose {}``Add/Remove Programs'' and look for the entry named {}``APQ-2.1 (remove only)''. Click on the button {}``Change/Remove'' to proceed. The APQ\_Uninstall.exe program will then be launched to guide you through the process. \section{Conclusion} If you reached this point, you have successfully installed database support, which is now at your Ada95 finger tips! Congratulations! The next chapter will show you how to test your APQ library. \chapter{Testing APQ} Naturally, you want to test out your shiny new APQ library, now that you can connect to databases both on your win32 platform, and remotely over the network. The example programs in the ./eg and the ./eg2 are UNIX flavoured tests and are not suitable. Starting with APQ-2.1, there is now a template program named win32\_test.adb. This chapter will describe how you can use that source file to perform some simple tests. \section{Creating the Test Program} First you need to create a file named win\_test.adb from the win32\_test.adb source file provided. Do not modify the original win32\_test.adb file. You may need it for testing another database, later. Create the win\_test.adb by copying the win32\_test.adb file (bash): \begin{lyxcode} \$~cp~win32\_test.adb~win\_test.adb \end{lyxcode} But don't compile that file yet! You need to supply some changes. \begin{quote} Note: if you are testing a binary installed release, look for the win32\_test.adb program in the APQ bindings directory. If GNAT is installed as C:\textbackslash{}OPT\textbackslash{}GNAT, then look for the file named: C:\textbackslash{}OPT\textbackslash{}GNAT\textbackslash{}Bindings\textbackslash{}APQ\textbackslash{}win32\_test.adb Copy this file to your work area, and name it win\_test.adb to match the procedure name within it. \end{quote} \subsection{Editing the win\_test.adb Source} The test file win\_test.adb is nearly complete. But it still needs you to define: \begin{enumerate} \item Which database product to use \item What host name (if not local) to use \item What account name (userid) to use \item What password to use (if any) \end{enumerate} Once these are defined, the program is ready to compile and test. The unmodified start of the win\_test.adb program should look like this: \begin{lyxcode} ~{\footnotesize ~~~~1~~-{}-~Very~Simple~Connect~to~Database~Test}{\footnotesize \par} ~{\footnotesize ~~~~2}{\footnotesize \par} ~{\footnotesize ~~~~3~~-{}-~Uncomment~one~of~the~following:}{\footnotesize \par} ~{\footnotesize ~~~~4~~-{}-~with~APQ.PostgreSQL.Client;~use~APQ,~APQ.PostgreSQL,~...}{\footnotesize \par} ~{\footnotesize ~~~~5~~-{}-~with~APQ.MySQL.Client;~use~APQ,~APQ.MySQL,~APQ.MySQL.Client;}{\footnotesize \par} ~{\footnotesize ~~~~6}{\footnotesize \par} ~{\footnotesize ~~~~7~~with~Ada.Text\_IO;~use~Ada.Text\_IO;}{\footnotesize \par} ~{\footnotesize ~~~~8}{\footnotesize \par} ~{\footnotesize ~~~~9~~procedure~Win\_Test~is}{\footnotesize \par} ~{\footnotesize ~~~10~~~~~C~:~Connection\_Type;}{\footnotesize \par} ~{\footnotesize ~~~11~~~~~Q~:~Query\_Type;}{\footnotesize \par} ~{\footnotesize ~~~12~~begin}{\footnotesize \par} ~{\footnotesize ~~~13}{\footnotesize \par} ~{\footnotesize ~~~14~~~~~Put\_Line(\char`\"{}Win32\_Test~Started:\char`\"{});}{\footnotesize \par} ~{\footnotesize ~~~15}{\footnotesize \par} ~{\footnotesize ~~~16~~-{}-~Set\_Host\_Name(C,\char`\"{}\char`\"{});}{\footnotesize \par} ~{\footnotesize ~~~17~~~~~Set\_User\_Password(C,\char`\"{}\char`\"{},\char`\"{}\char`\"{});}{\footnotesize \par} ~{\footnotesize ~~~18~~~~~Set\_DB\_Name(C,\char`\"{}\char`\"{});}{\footnotesize \par} \end{lyxcode} The line numbers are not part of the source code however, since they are here only for our ease of reference. Now perform the following edits: \begin{enumerate} \item Uncomment line 4 if you are testing PostgreSQL. Else uncomment line 5 for MySQL. \item If your database is a remote database, uncomment line 16. Then replace with the host name or IP number of the database server. \item Edit your userid value in place of on line 17. \item Edit your password value in place of on line 17. If there is no password, supply a null string like {}``''. \item Edit the database name in place of on line 18. \end{enumerate} Save the file to win\_test.adb and compile it as follows: \begin{lyxcode} \$~gnatmake~win\_test \end{lyxcode} You will not need to specify any linking arguments, since the GNAT feature: \begin{lyxcode} pragma~Linker\_Options({}``...''); \end{lyxcode} was used in the APQ package specs to avoid this inconvenience. \section{Running the Test} Before the test run can be successful, there are some obvious prerequisites on the database side: \begin{itemize} \item The database server must accept connections from you \item The database server userid and password must be acceptable \item The database named must already exist (the test program does not create it) \end{itemize} The test program win\_test.exe, first attempts to drop a table TEST\_TBL, and then creates a new one. This is done so that you can run the test multiple times. This has the implication that: \begin{itemize} \item The userid must have table create privileges \item The userid must have table drop privileges \item The userid must have sequence drop privileges, for PostgreSQL only \end{itemize} Configuring the security and the privileges of the user accounts, is outside the scope of this document. Note however, that you can test the connectivity and rights with the mysql command for MySQL, and psql for PostgreSQL. Once those work, you should have success with win\_test.exe as well. The test results look something like the following for MySQL: \begin{lyxcode} \$~./win\_test {\footnotesize Win32\_Test~Started:}{\footnotesize \par} {\footnotesize My~Userid~is~'wwg'}{\footnotesize \par} {\footnotesize My~Password~is~''}{\footnotesize \par} {\footnotesize My~Database~is~'wwg'}{\footnotesize \par} {\footnotesize My~Host~Name~is~''}{\footnotesize \par} {\footnotesize My~Engine~is~ENGINE\_MYSQL}{\footnotesize \par} {\footnotesize Connecting..}{\footnotesize \par} {\footnotesize Connected!}{\footnotesize \par} - {\footnotesize DROP~TABLE~TEST\_TBL}{\footnotesize \par} - {\footnotesize Table~was~dropped.}{\footnotesize \par} - {\footnotesize CREATE~TABLE~TEST\_TBL~(}{\footnotesize \par} ~{\footnotesize ~NAME~~~VARCHAR(32)~NOT~NULL,}{\footnotesize \par} ~{\footnotesize ~ID~~~~~INTEGER~NOT~NULL~AUTO\_INCREMENT~PRIMARY~KEY}{\footnotesize \par} {\footnotesize )}{\footnotesize \par} - {\footnotesize Table~created.}{\footnotesize \par} - {\footnotesize INSERT~INTO~TEST\_TBL~(~NAME~)}{\footnotesize \par} ~{\footnotesize ~VALUES(~'ONE'~)}{\footnotesize \par} - {\footnotesize OID=~1}{\footnotesize \par} {\footnotesize INSERT~INTO~TEST\_TBL~(~NAME~)}{\footnotesize \par} ~{\footnotesize ~VALUES(~'TWO'~)}{\footnotesize \par} - {\footnotesize OID=~2}{\footnotesize \par} - {\footnotesize INSERT~INTO~TEST\_TBL~(~NAME~)}{\footnotesize \par} ~{\footnotesize ~VALUES(~'THREE'~)}{\footnotesize \par} - {\footnotesize OID=~3}{\footnotesize \par} - {\footnotesize SELECT~NAME,ID}{\footnotesize \par} {\footnotesize FROM~TEST\_TBL}{\footnotesize \par} - {\footnotesize Got~3~Tuples..}{\footnotesize \par} {\footnotesize NAME='ONE',~ID='1'}{\footnotesize \par} {\footnotesize NAME='TWO',~ID='2'}{\footnotesize \par} {\footnotesize NAME='THREE',~ID='3'}{\footnotesize \par} {\footnotesize }{\footnotesize \par} {\footnotesize Test~Completed.}{\footnotesize \par} \end{lyxcode} Note that this win\_test.exe can run independently of CYGWIN as well, in a cmd.exe session. APQ is not dependent upon the CYGWIN infrastructure. CYGWIN is only used as a tool to build APQ from sources. \section{Congratulations!} If you successfully built and installed APQ on your win32 environment, then you are ready to branch out into entire new horizons with APQ. This software has been developed and provided to you for free. One way you can help with the development is to provide support in the way of: \begin{itemize} \item bug reports \item user experiences with APQ (good and bad) \item suggestions for enhancements \item testimonials about the APQ library to encourage others to try it \item financial support \end{itemize} APQ is Open Sourced, and so financial support is not required. However, financial support is always welcome, and may help with future releases. An example of where financial support may be necessary is to fund the purchase of newer Microsoft development tools. The success of win32 ports of any package, depend upon access to these tools. So if you use APQ in a business setting, please consider providing some level of support to the APQ project. Testimonials and bug reports are another major area of support that don't cost anything. Testimonials help others realize that they need to take the time to test drive it. If you want to provide a testimonial, just let me know if you want it kept anonymous, or the email address removed. I understand the pain of spam. Bug reports help eliminate problems for everyone, including yourself in future revisions of APQ. User experiences and suggestions are always welcome. Just drop a line or three, and let me know how APQ can be improved, or how it has made your projects successful. \subsection*{Thanks for using APQ!} \begin{quote} Warren W. Gay VE3WWG ve3wwg@cogeco.ca \end{quote} \begin{lyxcode} \end{lyxcode} \end{document} apq-3.2.0/legacy/win32_config000066400000000000000000000413501171626402600157630ustar00rootroot00000000000000#!/usr/bin/bash # Configure for Makefil# # Warren W. Gay VE3WWG # for APQ # # NOTES ABOUT READLINE HISTORY : # # The way history -s works, it replaces the last command in the history # with what you provide. This leads to some difficult situations, where I # would like to simply _add_ entries to the history. So don't expect # everything you want to be found in the history. It is hit and miss. I # have given up all hope of ever getting it totally right here. Maybe # between bash and readline, this will be corrected someday. # # READLINE STUFF: # # completion-ignore-case (Off) # If set to On, readline performs filename matching and completion # in a case-insensitive fashion. # completion-query-items (100) # This determines when the user is queried about viewing the num- # ber of possible completions generated by the possible-comple- # tions command. It may be set to any integer value greater than # or equal to zero. If the number of possible completions is # greater than or equal to the value of this variable, the user is # asked whether or not he wishes to view them; otherwise they are # simply listed on the terminal. # disable-completion (Off) # If set to On, readline will inhibit word completion. Completion # characters will be inserted into the line as if they had been # mapped to self-insert. # editing-mode (emacs) # Controls whether readline begins with a set of key bindings sim- # ilar to emacs or vi. editing-mode can be set to either emacs or # vi. # # history [n] # history -c # history -d offset # history -anrw [filename] # history -p arg [arg ...] # history -s arg [arg ...] # # With no options, display the command history list with line num- # bers. Lines listed with a * have been modified. An argument of # n lists only the last n lines. If filename is supplied, it is # used as the name of the history file; if not, the value of HIST- # FILE is used. Options, if supplied, have the following mean- # ings: # # -c Clear the history list by deleting all the entries. # # -d offset # Delete the history entry at position offset. # # -a Append the ``new'' history lines (history lines entered # since the beginning of the current bash session) to the # history file. # # -n Read the history lines not already read from the history # file into the current history list. These are lines # appended to the history file since the beginning of the # current bash session. # # -r Read the contents of the history file and use them as the # current history. # # -w Write the current history to the history file, overwrit- # ing the history file's contents. # # -p Perform history substitution on the following args and # display the result on the standard output. Does not # store the results in the history list. Each arg must be # quoted to disable normal history expansion. # # -s Store the args in the history list as a single entry. # The last command in the history list is removed before # the args are added. # # The return value is 0 unless an invalid option is encountered, # an error occurs while reading or writing the history file, an # invalid offset is supplied as an argument to -d, or the history # expansion supplied as an argument to -p fails. # # STUFF WE DON'T WANT TO RECORD IN THE HISTORY : # HISTIGNORE="readit*:set *:if *:case *:while *:history*:*=*:get_info*:cat*:\ yesno*:unset *:upath(*:wpath(*:upath *:wpath *:find_path*:find_dll*:have_mstools*:\ eval *:echo *:#*:get_path*" set -o history history 500 set completion-ignore-case on set completion-query-items 30 set disable-completion off set -o vi # Default to vi, even though emacs is better set -eu VERSION=$(cat ./APQ_VERSION) # # TELL THE USER THAT WE HAVE STARTED : # cat >/dev/tty </dev/tty </dev/tty history -s "$reply" } # # ASK THE USER FOR THEIR EDIT PREFERENCES, SINCE THERE # DOESN'T SEEM TO BE A RELIABLE WAY TO DETERMINE THIS # IN ADVANCE: # while true; do cat >/dev/tty </dev/null return 0; } # # CONVERT A CYGWIN UNIX PATHNAME TO A WINDOWS PATHNAME # wpath() { set +e cygpath -w "$1" 2>/dev/null return 0; } # # PROMPT FOR A WINDOWS PATHNAME AND RETURN A CYGWIN UNIX PATHNAME # get_path() { readit "$1 : " win_path="$reply" cygpath "$win_path" 2>/dev/null } # # LOCATE A FILE ON THE PATH # find_path() { FILE="$1" not_cwd="${2:-0}" # When 1, do not consider current directory in search (for DLL searches) IFS=':' for dir in $PATH ; do if [ -r "$dir/$FILE" ] ; then if [ "$dir" != '.' -o $not_cwd -eq 0 ] ; then echo "$dir/$FILE" return 0 fi fi done return 1 } # # LOCATE A DLL FILE # find_dll() { set +e PATH=".:$PATH" find_path "$1" } # # LOCATE DLL ON PATH OTHER THAN CURRENT DIRECTORY # find_dll_not_cwd() { DLL="$1" set +e P=$(find_path "$DLL" 1) if [ $? -ne 0 ] ; then return 1; # Not found at all fi if [ $(cygpath -w "$P") = $(cygpath -w "$DLL") ] ; then return 1; # Current directory does not count fi echo $(dirname $P) return 0 # Found, and not in current directory } # # TEST TO SEE THAT WE HAVE THE MICROSOFT TOOLS NEEDED # have_mstools() { set +e type -p cl >/dev/null 2>&1 # Need MS CL compiler for compiling dll modules MSCL=$? type -p lib >/dev/null 2>&1 # Need MS LIB utility to generate export file (for dll) MSLIB=$? type -p link >/dev/null 2>&1 # Need MS LINK utility to create dll files MSLINK=$? if [ $MSCL -ne 0 -o $MSLIB -ne 0 -o $MSLINK -ne 0 ] ; then echo "You seem to be lacking Microsoft Visual Studio tools" >/dev/tty echo "or perhaps they are not on your PATH." >/dev/tty echo if [ $MSCL -ne 0 ] ; then echo "- Cannot locate Microsoft CL compiler."; fi if [ $MSLIB -ne 0 ] ; then echo "- Cannot locate Microsoft LIB utility for export files."; fi if [ $MSLINK -ne 0 ] ; then echo "- Cannot locate Microsoft LINK utility to create DLL files."; fi echo >/dev/tty MS=1 else MS=0 fi return $MS } # # PROMPT FOR DATABASE FILE INFO # get_info() { DB="$1" # PostgreSQL or MySQL echo >/dev/tty echo "Questions for $DB :" >/dev/tty echo >/dev/tty HAVE=$(yesno "Installing $DB database support ?") if [ $HAVE -gt 0 ] ; then while true ; do INCL_DIR=$(get_path "Windows pathname to $DB include directory") history -s $(cygpath -w "$INCL_DIR" 2>/dev/null) if [ -d "$INCL_DIR" ] ; then case "$DB" in PostgreSQL ) inclfile=libpq-fe.h;; MySQL ) inclfile=mysql.h;; esac if [ -r "$INCL_DIR/$inclfile" ] ; then break else echo "Include file $inclfile does not seem to be there." >/dev/tty fi else echo "Directory $(wpath "$INCL_DIR") does not exist." >/dev/tty fi done case "$DB" in PostgreSQL ) dllname=libpq.dll;; MySQL ) dllname=libmysql.dll;; esac if [ "X$dllname" != X ] ; then set +e DLLPATH=$(find_dll "$dllname") RC=$? history -s $(cygpath -w "$DLLPATH" 2>/dev/null) if [ $RC -ne 0 ] ; then echo "******************************************************" >/dev/tty echo "Sorry, but I was unable to find DLL $dllname." >/dev/tty echo "Check your PATH variable, or the location of the file." > /dev/tty echo "******************************************************" >/dev/tty exit 3 else echo "Windows path of $DB DLL file is : $(cygpath -w $DLLPATH 2>/dev/null)" >/dev/tty fi else DLLPATH= fi set -e if [ "$DB" = MySQL ] ; then while true ; do IMPLIBF=$(get_path "Windows path to libmysql.lib file ") history -s $(cygpath -w "$IMPLIBF" 2>/dev/null) if [ -f "$IMPLIBF" ] ; then break; else echo "The file $(wpath "$IMPLIBF") does not exist." >/dev/tty echo "To build a DLL, I need the libmysql.lib import library." >/dev/tty fi done fi else INCL_DIR= DLLPATH= IMPLIBF= fi echo "HAVE=$HAVE INCL='$INCL_DIR' DLL='$DLLPATH' IMPLIBF='$IMPLIBF'" } # # DETERMINE IF WE HAVE THE MICROSOFT VISUAL STUDIO UTILITIES : # (CL, LIB AND LINK) # set +e have_mstools MSTOOLS=$? set -e # # INFORM THE USER ABOUT THEIR OPTIONS WHEN NO MS TOOLS ARE AVAILABLE : # if [ $MSTOOLS -ne 0 ] ; then cat </dev/tty **************************************************************** APQ needs the Microsoft tools to build support for: - MySQL - Sybase If you are not including MySQL or Sybase support, then you do not need them, since GNAT can build what you need. **************************************************************** EOF else echo >/dev/tty echo "You seem to have the Microsoft Toolset available.." >/dev/tty echo >/dev/tty fi # # SEE IF THE APQ_MYADAPTER.DLL IS ALREADY INSTALLED. IF SO, # THEN WE CAN DETERMINE FROM THIS, THAT IS THE LIKELY PLACE # THAT WE WANT TO RE-INSTALL THE DLL. # set +e APQ_MYADAPTER=$(find_dll_not_cwd apq_myadapter.dll) # Locate our DLL but not current directory if [ $? -eq 0 ] ; then DLL_INSTPATH="$APQ_MYADAPTER" else DLL_INSTPATH= fi # # GET MySQL DATABASE INFORMATION : # eval $(get_info MySQL) if [ $? -ne 0 ] ; then exit 13 # Failure in interrogation fi HAVE_MY=$HAVE # Installing MySQL (or not) MY_UINCL="$INCL" # MySQL UNIX Include directory pathname MY_WINCL=$(wpath "$MY_UINCL") # Windows path of same MY_UDLL="$DLL" # Pathname to MySQL libmySQL.dll file MY_WDLL=$(wpath "$MY_UDLL") # Windows path of same MY_UIMP="$IMPLIBF" # UNIX pathname to MySQL import library (libmySQL.lib) MY_WIMP=$(wpath "$MY_UIMP") # Windows path of same if [ $HAVE_MY -gt 0 ] ; then MY_OBJS="apq-mysql.o apq-mysql-client.o" fi eval $(get_info PostgreSQL) if [ $? -ne 0 ] ; then exit 13 fi echo >/dev/tty HAVE_PG=$HAVE # Installing PostgreSQL (or not) if [ $HAVE_PG -ne 0 ] ; then PG_UINCL="$INCL" # UNIX pathname to include files PG_WINCL=$(wpath "$PG_UINCL") # Windows pathname to same PG_UDLL="$DLL" # UNIX pathname to libpq.dll PG_WDLL=$(wpath "$PG_UDLL") # Windows pathname to same PG_OBJS="apq-postgresql.o apq-postgresql-client.o numeric.o notices.o" else PG_UINCL= PG_WINCL= PG_UDLL= PG_WDLL= PG_OBJS= fi ###################################################################### # Test for SYBASE support ###################################################################### if [ "${SYBASE:-NOT}" = NOT ] ; then if [ -d /opt/sybase ] ; then if [ -r /opt/sybase/SYBASE.sh ] ; then set +u . /opt/sybase/SYBASE.sh set -u fi fi fi if [ "${SYBASE:-NOT}" != NOT ] ; then HAVE_SY=1 else HAVE_SY=0 fi if [ $HAVE_SY -gt 0 ] ; then echo " You have Sybase support." fi if [ $HAVE_SY -gt 0 ] ; then SY=$(cygpath "$SYBASE" 2>/dev/null) WP=$(cygpath -w "$SY/$SYBASE_OCS/include") SY_INCL="-I$WP" SY_OBJS="apq-sybase.o apq-sybase-client.o" UP="$SY/$SYBASE_OCS/lib" WP=$(cygpath -w "$UP") SY_LIBS="-L$WP -lcs -lct" SY_UIMP="$UP/libcs.lib $UP/libct.lib" SY_WIMP="$WP\\libcs.lib $WP\\libct.lib" else SY_INCL= SY_LIBS= SY_OBJS= SY_UIMP= SY_WIMP= fi # # TEST TO SEE IF WE HAVE ANY DATABASES TO WORK WITH # if [ $(expr $HAVE_PG + $HAVE_MY + $HAVE_SY) -eq 0 ] ; then cat </dev/tty ------------------------------------------------------------------------------ Based upon the configure script's findings, and your answers, there were no databases left to configure the APQ package to build for. Also check any exported environment variables like HAVE_PG/HAVE_MY. Consequently, the configuration of APQ will be abandoned. Please install your database software first, and then try building APQ again later. ------------------------------------------------------------------------------ EOF exit 13 fi # # CHECK MICROSOFT TOOL DEPENDENCIES # if [ $MSTOOLS -ne 0 ] ; then echo >/dev/tty echo "*********************************************************" >/dev/tty echo "You are building support for MySQL, yet lack the Microsoft" >/dev/tty echo "toolset. I feel your pain. However, you may still build" >/dev/tty echo "the remaining APQ components using GNAT, provided that you" >/dev/tty echo "have the binary file apq_myadapter.dll available. ">/dev/tty echo "*********************************************************" >/dev/tty echo >/dev/tty if [ ! -f apq_myadapter.dll ] ; then echo >/dev/tty echo "*********************************************************" >/dev/tty echo "It appears that you do not have it downloaded, or it" >/dev/tty echo "does not exist in the current directory. Please place" >/dev/tty echo "a copy of the APQ_MYADAPTER.DLL into the current" >/dev/tty echo "directory, and run configure again." >/dev/tty echo "*********************************************************" >/dev/tty echo >/dev/tty exit 2; else echo >/dev/tty echo "******************************************************" >/dev/tty echo "I see you have the DLL in the current directory. Good." >/dev/tty echo "******************************************************" >/dev/tty echo >/dev/tty fi echo >/dev/tty fi # # DETERMINE WHERE THE DLL(S) SHOULD BE INSTALLED : # if [ "$DLL_INSTPATH" = "" ] ; then if [ $HAVE_MY -ne 0 -a $HAVE_PG -ne 0 ] ; then DLL_INSTPATH=$(find_dll_not_cwd libmysql.dll) elif [ $HAVE_MY -ne 0 ] ; then DLL_INSTPATH=$(find_dll_not_cwd libmysql.dll) elif [ $HAVE_PG -ne 0 ] ; then DLL_INSTPATH=$(find_dll_not_cwd libpq.dll) elif [ $HAVE_SY -ne 0 ] ; then true; # Ignore this one for sybase (there are multiple dlls) else echo "Bug!" exit 13 fi fi history -s $(cygpath -w "$DLL_INSTPATH" 2>/dev/null) # # GENERATE MAKEINCL.WIN32 FILE # set +ue cat >config.win32 </dev/null) MY_OBJS=${MY_OBJS:-} # # PostgreSQL Config : # HAVE_PG=$HAVE_PG PG_UINCL="$PG_UINCL" PG_DLL="$PG_UDLL" PG_INCL=-I$(cygpath -w $PG_UINCL 2>/dev/null) PG_OBJS=${PG_OBJS:-} # # Sybase Config : # HAVE_SY=$HAVE_SY SY_INCL=$SY_INCL SY_LIBS=$SY_LIBS SY_OBJS=$SY_OBJS SY_UIMP=$SY_UIMP SY_WIMP=$SY_WIMP # # DLL INSTALL PARAMETERS # DLL_UINSTPATH=$DLL_INSTPATH DLL_WINSTPATH=$(cygpath -w "$DLL_INSTPATH" 2>/dev/null) # # GNAT INFO # GNAT_VERSION=$(./gnat_info -v) GNAT_ROOT=$(cygpath "$(./gnat_info -r)") GNAT_BIN=$(cygpath "$(./gnat_info -b)") GNAT_BINDINGS=$(cygpath "$(./gnat_info -B)") # End EOF ln -s Makefile.win32 GNUmakefile XC=0 cat </dev/tty You are now ready to 'make' EOF APQ_INSTALLED=$(./gnat_info -a) if [ "$APQ_INSTALLED" != "NOT INSTALLED" ] ; then cat >/dev/tty </dev/tty </dev/tty To proceed with the build, perform the following: $ make (do 'make clean' prior to rebuids) $ make installer (optional) $ make install EOF exit $XC # End apq-3.2.0/legacy/win32_copying.rtf000066400000000000000000000046601171626402600167630ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}} \viewkind4\uc1\pard\qc\b\f0\fs36 APQ-2.1 License\par \b0\fs18 Warren W. Gay VE3WWG\par \pard\fs24\par \ul\b\fs28 PostgreSQL Sources Used within APQ:\par \ulnone\b0\fs24\par The modified or unmodified copies of the PostgreSQL \par Database Management System (formerly known as\par Postgres, then as Postgres95) software sources are \par covered under a separate license (see the file \par \fs20\tab\par \tab APQ_PG_COPYRIGHT.txt\fs24 \par \par for the precise terms of that license).\par \par \ul\b\fs28 APQ Sources:\par \ulnone\b0\fs24\par As of Aug 4, 2002, the APQ source code is available \par under a \i dual-license\i0 agreement. You the user or \par distributor, can choose one of the following sets of \par terms, that best suits your needs:\par \pard\fi-360\li1080\tx1080\par \pard\fi-270\li720\tx1080 1. The ACL (Ada Community License) \par 2. The GPL2 license (GNU Public License 2)\par \par \pard One or the other license must cover all APQ source\par code that is not otherwise covered by the \par PostgreSQL license.\par \par \ul\b\fs28 License Documents:\par \ulnone\b0\fs24\par Review the following files that are installed with \par your distribution of APQ:\par \pard\fi-270\li720\par \fs20 1.\tab doc/APQ_ACL_LICENSE.txt\par 2. \tab doc/APQ_GPL_LICENSE.txt\par 3.\tab doc/APQ_PG_COPYRIGHT.txt\par \pard\fs24\par The distributor and the end user(s) can choose\par different licenses, if they wish. The intention of \par this dual license agreement is to protect your \par freedom, to access, to use and even modify \par the source code for your own use.\par \par Enjoy, and thank-you for using APQ.\par \par \pard\li720 Warren.\par \par \pard\ul\b\fs28 Your Support:\par \fs24\par \ulnone\b0 APQ is free software. No payment is required.\par Win32 ports however, require the use of 3rd \par party tools (Microsoft), which are not free. To\par support future win32 ports of APQ, please \par consider a donation, particularly if you are \par using APQ in a business setting.\par \ul\b\fs28\par Warranty:\par \ulnone\b0\fs24\par \pard\ri2070\tx9450\tx9540 This software is provided as is. There \par is no warranty expressed, nor implied. \par The user of this software accepts all \par risks and consequences of using this \par software. Neither the author nor \par contributors to this software can be \par held responsible for any damages.\par } apq-3.2.0/legacy/win32_gnat_info.adb000066400000000000000000000173341171626402600172140ustar00rootroot00000000000000-- $Id: win32_gnat_info.adb,v 1.2 2003/09/24 15:44:43 wwg Exp $ -- Copyright (c) 2002, Warren W. Gay VE3WWG -- -- Licensed under the ACL (Ada Community License) -- or -- GNU Public License 2 (GPL2) -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA with Ada.Strings.Fixed; with Interfaces.C; with GNAT.OS_Lib; with GNAT.Directory_Operations; with WIn32.WinReg; with Win32_Registry; package body Win32_GNAT_Info is Top_Level_Key : constant String := "SOFTWARE\Ada Core Technologies"; GNAT_Level_Key : constant String := Top_Level_Key & "\GNAT"; Std_Lib_Key : constant String := GNAT_Level_Key & "\Standard Libraries"; Root_Subkey : constant String := "ROOT"; -- Under GNAT_Level_Key Vers_Subkey : constant String := "VERSION"; -- Under Top_Level_Key Win32Ada_Subkey : constant String := "WIN32ADA"; -- Under Std_Lib_Key function Dir_Name(Path : String) return String is use Ada.Strings.Fixed; X : Natural; begin X := Index(Source => Path, Pattern => "\", Going => Ada.Strings.Backward); if X < Path'First then return Path; else return Path(1..X-1); end if; end Dir_Name; procedure Not_Dot_Dir_Entry(Dir : in out GNAT.Directory_Operations.Dir_Type; Name : in out String; Last : out Natural) is use GNAT.Directory_Operations; begin loop Read(Dir,Name,Last); exit when Last < Name'First; -- End of directory exit when Name(Name'First..Last) /= "." and then Name(Name'First..Last) /= ".."; end loop; end Not_Dot_Dir_Entry; function ADAINCLUDE_Parent return String is use GNAT.Directory_Operations; Start_Dir : String := Root & "\LIB\GCC-LIB"; Dir : Dir_Type; Name : String(1..1024); Last : Natural := 0; begin begin Open(Dir,Start_Dir); exception when others => raise Failed; end; begin loop Not_Dot_Dir_Entry(Dir,Name,Last); exit when Last < Name'First; exit when Ada.Strings.Fixed.Index(Name(Name'First..Last),"mingw32") >= Name'First; end loop; if Last < Name'First then Close(Dir); raise Failed; -- GNAT must be using a different directory structure end if; declare Dive_Dir : String := Start_Dir & "\" & Name(Name'First..Last); begin Close(Dir); Open(Dir,Dive_Dir); loop Not_Dot_Dir_Entry(Dir,Name,Last); exit when Last < Name'First; exit when Name(Name'First) in '0'..'9' and Name(Name'First+1) = '.' and Name(Name'First+2) in '0'..'9'; end loop; Close(Dir); if Last < Name'First then raise Failed; end if; return Dive_Dir & "\" & Name(Name'First..Last); end; exception when others => Close(Dir); raise Failed; end; end ADAINCLUDE_Parent; -------------------------------------------------------------------------------- ------------------------------ -- RETURN THE ROOT DIRECTORY FOR THE INSTALLED -- GNAT COMPILER AND TOOLS : ------------------------------ function Root return String is use Win32_Registry; H : HKEY_Type; begin H := Open(HKEY_LOCAL_MACHINE,GNAT_Level_Key); declare S : String := Win32_Registry.Query(H,Root_Subkey); begin Close(H); return S; exception when others => Close(H); raise; end; end Root; ------------------------------ -- RETURN THE GNAT COMPILER VERSION -- STRING (E.G. "3.14P") ------------------------------ function Version return String is use Win32_Registry; H : HKEY_Type; begin H := Open(HKEY_LOCAL_MACHINE,Top_Level_Key); declare S : String := Win32_Registry.Query(H,Vers_Subkey); begin Close(H); return S; exception when others => Close(H); raise; end; end Version; ------------------------------ -- RETURN THE APQ VERSION IF THE -- BINDING IS INSTALLED. ------------------------------ function APQ_Version return String is use Win32_Registry; H : HKEY_Type; begin H := Open(HKEY_LOCAL_MACHINE,"SOFTWARE\APQ"); declare S : String := Win32_Registry.Query(H,"Version"); begin Close(H); return S; exception when others => Close(H); raise; end; end APQ_Version; ------------------------------ -- RETURN THE DIRECTORY NAME FOR GNAT -- Win32Ada BINDINGS (E.G. "C:\OPT\GNAT\BINDINGS\Win32Ada") ------------------------------ function Win32Ada_Bindings_Directory return String is use Win32_Registry; H : HKEY_Type; begin H := Open(HKEY_LOCAL_MACHINE,Std_Lib_Key); declare S : String := Win32_Registry.Query(H,Win32Ada_Subkey); begin Close(H); return S; exception when others => Close(H); raise; end; end Win32Ada_Bindings_Directory; ------------------------------ -- RETURN THE DIRECTORY NAME FOR GNAT -- BINDINGS (E.G. "C:\OPT\GNAT\BINDINGS") ------------------------------ function Bindings_Directory return String is Win32Ada_Dir : String := Win32Ada_Bindings_Directory; begin return Dir_Name(Win32Ada_Dir); end Bindings_Directory; ------------------------------ -- RETURN THE PATH OF GNAT -- BIN DIRECTORY (e.g. -- "C:\OPT\GNAT\bin" ------------------------------ function Bin return String is begin return Root & "\BIN"; end Bin; ------------------------------ -- RETURN THE PATH TO THE ADAINLCUDE -- DIRECTORY : ------------------------------ function ADAINCLUDE return String is begin return ADAINCLUDE_Parent & "\adainclude"; end ADAINCLUDE; ------------------------------ -- RETURN THE PATH TO THE ADALIB -- DIRECTORY : ------------------------------ function ADALIB return String is begin return ADAINCLUDE_Parent & "\adalib"; end ADALIB; ------------------------------ -- RETURN THE ADA_INCLUDE_PATH -- ENVIRONMENT VARIABLE VALUE : ------------------------------ function ADA_INCLUDE_PATH return string is use GNAT.OS_Lib; Var_Ptr : String_Access := GetEnv("ADA_INCLUDE_PATH"); begin if Var_Ptr = null then return ""; end if; return Var_Ptr.all; end ADA_INCLUDE_PATH; ------------------------------ -- RETURN THE ADA_OBJECTS_PATH -- ENVIRONMENT VARIABLE VALUE : ------------------------------ function ADA_OBJECTS_PATH return string is use GNAT.OS_Lib; Var_Ptr : String_Access := GetEnv("ADA_OBJECTS_PATH"); begin if Var_Ptr = null then return ""; end if; return Var_Ptr.all; end ADA_OBJECTS_PATH; end Win32_GNAT_Info; apq-3.2.0/legacy/win32_gnat_info.ads000066400000000000000000000041131171626402600172240ustar00rootroot00000000000000-- $Id: win32_gnat_info.ads,v 1.2 2003/09/24 15:44:43 wwg Exp $ -- Copyright (c) 2002, Warren W. Gay VE3WWG -- -- Licensed under the ACL (Ada Community License) -- or -- GNU Public License 2 (GPL2) -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA package Win32_GNAT_Info is Failed : Exception; -- Operation failed function Root return String; -- Return Win32 path to root of installed GNAT compiler & tools function Version return String; -- Return installed GNAT version info (e.g. "3.13p") function Win32Ada_Bindings_Directory return String; -- Return directory name of GNAT's Win32Ada bindings function Bindings_Directory return String; -- Return directory name of bindings function Bin return String; -- Return the pathname to the GNAT bin directory function ADAINCLUDE return String; -- Return the path to the ADAINCLUDE directory function ADALIB return String; -- Return the path to the ADALIB directory function ADA_INCLUDE_PATH return String; -- Return the ADA_INCLUDE_PATH environment string function ADA_OBJECTS_PATH return String; -- Return the ADA_OBJECTS_PATH environment string function APQ_Version return String; -- APQ version if installed end Win32_GNAT_Info; apq-3.2.0/legacy/win32_registry.adb000066400000000000000000000101001171626402600171000ustar00rootroot00000000000000-- $Id: win32_registry.adb,v 1.1 2003/09/24 14:16:58 wwg Exp $ -- Copyright (c) 2002, Warren W. Gay VE3WWG -- -- Licensed under the ACL (Ada Community License) -- or -- GNU Public License 2 (GPL2) -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA with Ada.Unchecked_Conversion; with Ada.Characters.Latin_1; with Win32.WinReg; with Win32.Winnt; with Win32.WinError; with Interfaces.C; package body Win32_Registry is procedure Raise_Error(Result : Win32.LONG) is use Win32.WinError; begin case Result is when ERROR_SUCCESS => return; -- Not really an error! when ERROR_FILE_NOT_FOUND => raise Not_Found; when others => raise Failed; end case; end Raise_Error; function To_String(Buffer : Win32.Byte_Array) return String is function To_Char is new Ada.Unchecked_Conversion(Win32.BYTE,Character); S : String(Buffer'Range); begin declare begin for X in S'Range loop S(X) := To_Char(Buffer(X)); end loop; return S; end; end To_String; function To_String(Buffer : Win32.Byte_Array; Count : Win32.DWORD) return String is use Interfaces.C; begin if Count = 0 then return ""; end if; declare S_Count : Win32.DWORD := Count - 1; S_Last : Integer := Buffer'First + Integer(S_Count) - 1; begin return To_String(Buffer(Buffer'First..S_Last)); end; end To_String; function Open(hKey : HKEY_Type; Key : String) return HKEY_Type is use Win32.WinReg, Interfaces.C; NUL : constant Character := Ada.Characters.Latin_1.NUL; Root_Key : constant String := Key & NUL; H : aliased HKEY_Type; Result : Win32.LONG; begin Result := RegOpenKeyExA( hKey => hKey, lpSubKey => Win32.Addr(Root_Key), ulOptions => 0, samDesired => Win32.Winnt.KEY_READ, phkResult => H'Unrestricted_Access ); if Result /= Win32.WinError.ERROR_SUCCESS then Raise_Error(Result); end if; return H; end Open; procedure Close(hKey : HKEY_Type) is use Interfaces.C; Result : Win32.LONG; begin Result := Win32.WinReg.RegCloseKey(hKey); if Result /= 0 then raise Failed; end if; end Close; function Query(hKey : HKEY_Type; Key : String) return String is use Win32.WinReg, Interfaces.C; NUL : constant Character := Ada.Characters.Latin_1.NUL; Result : Win32.LONG; Value_Key : String := Key & NUL; Value_Buf : Win32.BYTE_Array(1..1024) := (others => 0); DType : aliased Win32.DWORD; Count : aliased Win32.DWORD := Value_Buf'Length; begin Result := RegQueryValueExA( hKey => hKey, lpValueName => Win32.Addr(Value_Key), lpReserved => null, lpType => DType'Unrestricted_Access, lpData => Value_Buf(1)'Unrestricted_Access, lpcbData => Count'Unrestricted_Access ); if Result /= Win32.WinError.ERROR_SUCCESS then Raise_Error(Result); end if; if DType /= Win32.Winnt.REG_SZ then raise Wrong_Type; -- Incorrect Data Type end if; return To_String(Value_Buf,Count); end Query; end Win32_Registry; apq-3.2.0/legacy/win32_registry.ads000066400000000000000000000031261171626402600171330ustar00rootroot00000000000000-- $Id: win32_registry.ads,v 1.1 2003/09/24 14:16:58 wwg Exp $ -- Copyright (c) 2002, Warren W. Gay VE3WWG -- -- Licensed under the ACL (Ada Community License) -- or -- GNU Public License 2 (GPL2) -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA with Win32.WinNT; with Win32.WinReg; package Win32_Registry is subtype HKEY_Type is Win32.WinReg.HKEY; Failed : Exception; -- General 'catch all' for errors Not_Found : Exception; -- Key not found Wrong_Type : Exception; -- Data type was different than was expected HKEY_CLASSES_ROOT : constant HKEY_Type := Win32.WinReg.HKEY_CLASSES_ROOT; HKEY_LOCAL_MACHINE : constant HKEY_Type := Win32.WinReg.HKEY_LOCAL_MACHINE; function Open(hKey : HKEY_Type; Key : String) return HKEY_Type; procedure Close(hKey : HKEY_Type); function Query(hKey : HKEY_Type; Key : String) return String; end Win32_Registry; apq-3.2.0/legacy/win32_test.adb000066400000000000000000000065431171626402600162270ustar00rootroot00000000000000-- A Very Simple Database Test ---------------------------------- -- UNCOMMENT ONE OF THE FOLLOWING: -- (Choose one Database product) ---------------------------------- -- with APQ.PostgreSQL.Client; use APQ, APQ.PostgreSQL, APQ.PostgreSQL.Client; -- with APQ.MySQL.Client; use APQ, APQ.MySQL, APQ.MySQL.Client; with Ada.Text_IO; use Ada.Text_IO; procedure Win_Test is C : Connection_Type; Q : Query_Type; begin Put_Line("Win32_Test Started:"); -- Set_Host_Name(C,""); -- Uncomment+edit if remote database Set_User_Password(C,"",""); -- Edit in userid and password Set_DB_Name(C,""); -- Edit in your database name -- NO CHANGES REQUIRED BEYOND THIS POINT Put_Line("My Userid is '" & User(C) & "'"); Put_Line("My Password is '" & Password(C) & "'"); Put_Line("My Database is '" & DB_Name(C) & "'"); Put_Line("My Host Name is '" & Host_Name(C) & "'"); Put_Line("My Engine is " & Database_Type'Image(Engine_Of(C))); begin Put_Line("Connecting.."); Connect(C); Put_Line("Connected!"); New_Line; exception when Not_Connected => Put_Line("Error: " & Error_Message(C)); return; end; if Engine_Of(C) = Engine_PostgreSQL then begin Prepare(Q,"DROP SEQUENCE TEST_TBL_ID_SEQ"); Execute(Q,C); Put_Line("Sequence was dropped."); New_Line; exception when SQL_Error => Put_Line("Sequence did not exist: "); Put_Line(Error_Message(Q)); Put_LIne("Error ignored."); end; end if; begin Prepare(Q,"DROP TABLE TEST_TBL"); Put_Line(To_String(Q)); Execute(Q,C); Put_Line("Table was dropped."); New_Line; exception when SQL_Error => Put("Table did not exist: "); Put_Line(Error_Message(Q)); Put_LIne("Error ignored."); end; Prepare(Q,"CREATE TABLE TEST_TBL ("); Append_Line(Q," NAME VARCHAR(32) NOT NULL,"); if Engine_Of(C) = Engine_MySQL then Append_Line(Q," ID INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY"); else Append_Line(Q," ID SERIAL"); end if; Append_Line(Q,")"); Put_Line(To_String(Q)); Execute_Checked(Q,C); Put_Line("Table created."); Prepare(Q,"INSERT INTO TEST_TBL ( NAME )"); Append_Line(Q," VALUES( 'ONE' )"); New_Line; Put_Line(To_String(Q)); Execute_Checked(Q,C); Put_Line("OID=" & Row_ID_Type'Image(Command_Oid(Q))); Prepare(Q,"INSERT INTO TEST_TBL ( NAME )"); Append_Line(Q," VALUES( 'TWO' )"); New_Line; Put_Line(To_String(Q)); Execute_Checked(Q,C); Put_Line("OID=" & Row_ID_Type'Image(Command_Oid(Q))); Prepare(Q,"INSERT INTO TEST_TBL ( NAME )"); Append_Line(Q," VALUES( 'THREE' )"); New_Line; Put_Line(To_String(Q)); Execute_Checked(Q,C); Put_Line("OID=" & Row_ID_Type'Image(Command_Oid(Q))); Prepare(Q,"SELECT NAME,ID"); Append_Line(Q,"FROM TEST_TBL"); New_Line; Put_Line(To_String(Q)); Execute_Checked(Q,C); Put_Line("Got" & Tuple_Count_Type'Image(Tuples(Q)) & " Tuples.."); begin loop Fetch(Q); Put("NAME='" & Value(Q,1) & "', "); Put_Line("ID='" & Value(Q,2) & "'"); end loop; exception When No_Tuple => Put_Line(""); end; Disconnect(C); Put_Line("Test Completed."); end Win_Test; apq-3.2.0/manual/000077500000000000000000000000001171626402600135575ustar00rootroot00000000000000apq-3.2.0/manual/Makefile000066400000000000000000000005011171626402600152130ustar00rootroot00000000000000 all: manual.pdf %.pdf: %.tex pdflatex -halt-on-error $< && pdflatex -halt-on-error $< || echo Error while building PDF file clean: manual.pdf-clean manual.pdf-clean: @rm -f manual.pdf \ manual.aux\ manual.idx\ manual.log\ manual.lot\ manual.pdf\ manual.toc #manual.pdf: # pdflatex manual.tex apq-3.2.0/manual/README000066400000000000000000000005701171626402600144410ustar00rootroot00000000000000this manual is rather outdated but has some highly quality information. someone has got to update it ASAP! And put it online somwehere... Dependencies: TexLive or compatible (teTeX should work also) floatflt.sty package (which is included) http://tug.ctan.org/tex-archive/macros/latex/contrib/floatflt/ Simply type "make" "make clean" will delete undesired files. apq-3.2.0/manual/floatflt.sty000066400000000000000000000254641171626402600161460ustar00rootroot00000000000000%% %% This is file `floatflt.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% floatflt.dtx (with options: `paketkod') %% %% Copyright (c) 1994-1998 by Mats Dahlgren . %% All rights reserved. See the file `floatflt.ins' for information %% on how you may (re-)distribute the `floatflt' package files. %% You are not allowed to make any changes to this file without %% explicit permission from the author. %% \NeedsTeXFormat{LaTeX2e}[1996/12/01] \ProvidesPackage{floatflt}[1997/07/16 v. 1.31] \newcounter{OptionTest} \setcounter{OptionTest}{0} \DeclareOption{rflt}{\setcounter{OptionTest}{1}} \DeclareOption{lflt}{\setcounter{OptionTest}{2}} \DeclareOption{vflt}{\setcounter{OptionTest}{0}} \DeclareOption*{\OptionNotUsed} \ProcessOptions \newbox\figbox \newbox\tabbox \newbox\pagebox \newcount\ffigcount \newcount\ftabcount \newcount\fftest \newcount\hangcount \newcount\nosuccesstryfig \newcount\nosuccesstrytab \newdimen\figgutter \figgutter=1truepc \newdimen\tabgutter \tabgutter=1truepc \newdimen\htdone \htdone=0pt \newdimen\pageht \newdimen\startpageht \newdimen\tabbredd \newdimen\floatfltwidth \newdimen\fltitemwidth \newif\iftryingfig \tryingfigfalse \newif\iftryingtab \tryingtabfalse \newif\ifdoingfig \doingfigfalse \newif\ifdoingtab \doingtabfalse \newif\iffigprocessing \figprocessingfalse \newif\iftabprocessing \tabprocessingfalse \newif\ifpageafterfig \pageafterfigfalse \newif\ifpageaftertab \pageaftertabfalse \newif\ifoddpages \newif\ifoutput \newtoks\outputpretest \newenvironment{floatingfigure}[2][v]% {\@tfor \@tempa :=#1\do {\if\@tempa r\global\oddpagestrue\fi \if\@tempa l\global\oddpagesfalse\fi \if\@tempa p% \ifodd\c@page\global\oddpagestrue \else\global\oddpagesfalse\fi \fi \if\@tempa v% \ifnum\theOptionTest=0 \ifodd\c@page\global\oddpagestrue \else\global\oddpagesfalse\fi \else \ifodd\theOptionTest\global\oddpagestrue \else\global\oddpagesfalse\fi \fi \fi } \expandafter\ifx\csname oldoutput\endcsname\relax% ref. TeXbook Ex.7.7 \PackageError{floatflt}{The `floatflt' package is not initialized} {Try to reinstall the `floatflt' package.\MessageBreak Type `x' to quit or to try to go on.}\@@end\fi \global\everypar={\tryfig\oldeverypar}% must be set globally! \global\advance\ffigcount by 1 \iffigprocessing {\count0=\ffigcount\advance\count0 by -1 \PackageWarningNoLine{floatflt}{Floating figures \the\count0\space% \space and \the\ffigcount\space colliding}% }% \fi \iftabprocessing \PackageWarningNoLine{floatflt}{Floating figure % \the\ffigcount\space and floating table \the\ftabcount\space colliding} \fi \def\@captype{figure} \global\setlength{\floatfltwidth}{#2} \global\figprocessingtrue \global\setbox\figbox=\vbox\bgroup% begin of figbox \hrule height 0pt width #2 depth 0pt% \hsize=#2% } { \egroup \figinsert\par% } \newenvironment{floatingtable}[2][v]% {\@tfor \@tempa :=#1\do {\if\@tempa r\global\oddpagestrue\fi \if\@tempa l\global\oddpagesfalse\fi \if\@tempa p% \ifodd\c@page\global\oddpagestrue \else\global\oddpagesfalse\fi \fi \if\@tempa v% \ifnum \theOptionTest=0 \ifodd\c@page\global\oddpagestrue \else\global\oddpagesfalse\fi \else \ifodd\theOptionTest\global\oddpagestrue \else\global\oddpagesfalse\fi \fi \fi } \expandafter\ifx\csname oldoutput\endcsname\relax% ref. TeXbook Ex.7.7 \PackageError{floatflt}{The `floatflt' package is not initialized} {Try to reinstall the `floatflt' package.\MessageBreak Type `x' to quit or to try to go on.}\@@end\fi \global\setbox\tabbox=\vbox\bgroup\hrule height 0pt width 0pt depth 0pt% \hsize=0pt\egroup \global\everypar={\trytab\oldeverypar} \global\advance\ftabcount by 1 \iftabprocessing {\count0=\ftabcount\advance\count0 by -1 \PackageWarningNoLine{floatflt}{Floating tables \the\count0\space% \space and \the\ftabcount \space colliding}% } \fi \iftabprocessing \PackageWarningNoLine{floatflt}{Floating table % \the\ffigcount\space and floating figure \the\ftabcount\space colliding} \fi \settowidth{\tabbredd}{#2} \global\setlength{\floatfltwidth}{\tabbredd} \def\@captype{table} \global\tabprocessingtrue \global\setbox\tabbox=\vbox\bgroup% begin of tabbox \hrule height 0pt width\tabbredd depth 0pt% \hsize=\tabbredd \noindent\ifnum\ftabcount >1\ifoddpages\else\hspace*{-12pt}\fi\fi% #2\vspace{0.2\baselineskip}% } { \egroup% end of \tabbox \tabinsert\par% } \AtBeginDocument{% \edef\oldoutput{\the\output}% \output={\the\outputpretest% \ifoutput\oldoutput\fi} \outputpretest={\outputtrue} \edef\oldeverypar{\the\everypar} } \def\dofigtest{% \ifnum\outputpenalty=-10005 \setbox\pagebox=\vbox{\unvbox255}% \global\pageht=\ht\pagebox \global\outputfalse \unvbox\pagebox \else \global\outputtrue \ifdoingfig \global\pageafterfigtrue \fi \fi}% \def\dotabtest{% \ifnum\outputpenalty=-10005 \setbox\pagebox=\vbox{\unvbox255}% \global\pageht=\ht\pagebox \global\outputfalse \unvbox\pagebox \else \global\outputtrue \ifdoingtab \global\pageaftertabtrue \fi \fi}% \def\tryfig{% \iftryingfig {\everypar={\relax}\setbox0=\lastbox% \parindent=\wd0 \parskip=0pt \par% \penalty-10005 \leavevmode}% \dimen0=\vsize% \advance\dimen0 by -\pageht% \advance\dimen0 by -2\baselineskip% \ifdim\dimen0>\ht\figbox% \dimen0=0.3\baselineskip \vrule depth \dimen0 width 0pt \vadjust{\kern -\dimen0% \vtop to \dimen0{% \baselineskip=\dimen0% \vss \vbox to 1ex{% \ifoddpages% \hbox to \hsize{\hss\copy\figbox}% \else% leftsetting \hbox to \hsize{\copy\figbox\hss}% \fi% \ifodd\count0 \vss}\null}}% \global\tryingfigfalse% \global\doingfigtrue \global\startpageht=\pageht \global\htdone=0pt \dohangf \ifnum\nosuccesstryfig>0% \typeout{floatflt Message: Flt. fig. \the\ffigcount\space set on page \the\count0, shifted \the\nosuccesstryfig\space par(s) forward.}% \else \typeout{Package floatflt Message: Floating figure \the\ffigcount \space set on page \the\count0}% \fi \else \global\advance\nosuccesstryfig by 1 \fi \else% \ifdoingfig {\everypar={\relax}\setbox0=\lastbox \parindent=\wd0 \parskip=0pt \par \penalty-10005 \leavevmode}% \global\htdone=\pageht \global\advance\htdone by -\startpageht \ifpageafterfig \global\doingfigfalse \else \dimen0=\ht\figbox% \advance\dimen0 by 0.5\baselineskip% \ifdim\htdone<\dimen0% \dohangf \else \global\doingfigfalse \fi \fi \ifdoingfig\relax\else\global\figprocessingfalse\fi \else \global\outputpretest={\outputtrue}% \fi \fi } \def\trytab{% \iftryingtab% {\everypar={\relax}\setbox0=\lastbox% \parindent=\wd0 \parskip=0pt \par% \penalty-10005 \leavevmode}% \dimen0=\vsize% \advance\dimen0 by -\pageht% \advance\dimen0 by -2\baselineskip% \ifdim\dimen0>\ht\tabbox% \dimen0=0.3\baselineskip \vrule depth \dimen0 width 0pt \vadjust{\kern -\dimen0% \vtop to \dimen0{% \baselineskip=\dimen0% \vss \vbox to 1ex{% \ifoddpages% \hbox to \hsize{\hss\copy\tabbox}% \else% leftsetting \hbox to \hsize{\copy\tabbox\hss}% \fi% \ifodd\count0 \vss}\null}}% \global\tryingtabfalse% \global\doingtabtrue \global\startpageht=\pageht \global\htdone=0pt \dohangt \ifnum\nosuccesstrytab>0% \typeout{floatflt Message: Flt. tab. \the\ftabcount\space set on page \the\count0, shifted \the\nosuccesstrytab\space par(s) forward.}% \else \typeout{Package floatflt Message: Floating table \the\ftabcount\space set on page \the\count0}% \fi \else \global\advance\nosuccesstrytab by 1 \fi \else \ifdoingtab {\everypar={\relax}\setbox0=\lastbox \parindent=\wd0 \parskip=0pt \par \penalty-10005 \leavevmode}% \global\htdone=\pageht \global\advance\htdone by -\startpageht \ifpageaftertab \global\doingtabfalse \else \dimen0=\ht\tabbox% \advance\dimen0 by 0.5\baselineskip% \ifdim\htdone<\dimen0% \dohangt \else \global\doingtabfalse \fi \fi \ifdoingtab\relax\else\global\tabprocessingfalse\fi \else \global\outputpretest={\outputtrue}% \fi \fi } \def\figinsert{% \global\nosuccesstryfig=0% \global\outputpretest={\dofigtest}% \global\tryingfigtrue \global\doingfigfalse% \global\pageafterfigfalse}% \def\tabinsert{% \global\nosuccesstrytab=0% \global\outputpretest={\dotabtest}% \global\tryingtabtrue \global\doingtabfalse% \global\pageaftertabfalse}% \def\dohangf{% \dimen0=\ht\figbox% \advance\dimen0 by -\htdone% \advance\dimen0 by 1.49\baselineskip% \hangcount=\dimen0% \divide\hangcount by \baselineskip% \dimen0=\wd\figbox% \advance\dimen0 by \figgutter% \ifoddpages% \global\hangafter=-\hangcount% placing right \global\hangindent=-\dimen0% \else% \ifleftsetting \global\hangafter=-\hangcount% placing left \global\hangindent=\dimen0% \fi } \def\dohangt{% \dimen0=\ht\tabbox% \advance\dimen0 by -\htdone% \advance\dimen0 by 1.49\baselineskip% \hangcount=\dimen0% \divide\hangcount by \baselineskip% \dimen0=\wd\tabbox% \advance\dimen0 by \tabgutter% \ifoddpages% \global\hangafter=-\hangcount% placing right \global\hangindent=-\dimen0% \else% \ifleftsetting \global\hangafter=-\hangcount% placing left \global\hangindent=\dimen0% \fi } \newcommand{\fltitem}[2][0pt]{\setlength{\fltitemwidth}{\linewidth}% \addtolength{\fltitemwidth}{-\floatfltwidth}% \addtolength{\fltitemwidth}{-0.5em}% \item \parbox[t]{\fltitemwidth}{#2}\\[#1]} \newcommand{\fltditem}[3][0pt]{\setlength{\fltitemwidth}{\linewidth}% \addtolength{\fltitemwidth}{-\floatfltwidth}% \addtolength{\fltitemwidth}{-0.5em}% \item[#2] \parbox[t]{\fltitemwidth}{#3}\\[#1]} \endinput %% %% End of file `floatflt.sty'. apq-3.2.0/manual/manual.tex000066400000000000000000013262501171626402600155670ustar00rootroot00000000000000% APQ-\apqversion Manual \documentclass[english,letterpaper]{book} \usepackage{times} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} \usepackage{longtable} \usepackage{amsmath} \usepackage{amssymb} \usepackage{floatflt} \usepackage{fancyhdr} \pagestyle{fancy} %\lhead{} %\chead{} \rhead{} \lfoot{} \cfoot{\thepage} \rfoot{APQ \apqversion} \newcommand\Ref[1]{\textsection\ref{#1} (page~\pageref{#1})} \usepackage{fancyvrb} \usepackage{makeidx} \makeindex \IfFileExists{url.sty}{\usepackage{url}} {\newcommand{\url}{\texttt}} \makeatletter \usepackage{babel} \makeatother %==========% % HYPERREF % %==========% \usepackage[bookmarks, colorlinks, breaklinks, pdftitle={APQ User Manual}, pdfauthor={KOW Framework Project}]{hyperref} \hypersetup{ linkcolor=DarkSkyBlue, citecolor= DarkSkyBlue, filecolor= DarkSkyBlue, urlcolor= DarkSkyBlue } %========================% % Listings Package Setup % %========================% \usepackage{xcolor} \usepackage{listings} \usepackage{caption} % COLORS (Tango) \definecolor{LightButter}{rgb}{0.98,0.91,0.31} \definecolor{LightOrange}{rgb}{0.98,0.68,0.24} \definecolor{LightChocolate}{rgb}{0.91,0.72,0.43} \definecolor{LightChameleon}{rgb}{0.54,0.88,0.20} \definecolor{LightSkyBlue}{rgb}{0.45,0.62,0.81} \definecolor{LightPlum}{rgb}{0.68,0.50,0.66} \definecolor{LightScarletRed}{rgb}{0.93,0.16,0.16} \definecolor{Butter}{rgb}{0.93,0.86,0.25} \definecolor{Orange}{rgb}{0.96,0.47,0.00} \definecolor{Chocolate}{rgb}{0.75,0.49,0.07} \definecolor{Chameleon}{rgb}{0.45,0.82,0.09} \definecolor{SkyBlue}{rgb}{0.20,0.39,0.64} \definecolor{Plum}{rgb}{0.46,0.31,0.48} \definecolor{ScarletRed}{rgb}{0.80,0.00,0.00} \definecolor{DarkButter}{rgb}{0.77,0.62,0.00} \definecolor{DarkOrange}{rgb}{0.80,0.36,0.00} \definecolor{DarkChocolate}{rgb}{0.56,0.35,0.01} \definecolor{DarkChameleon}{rgb}{0.30,0.60,0.02} \definecolor{DarkSkyBlue}{rgb}{0.12,0.29,0.53} \definecolor{DarkPlum}{rgb}{0.36,0.21,0.40} \definecolor{DarkScarletRed}{rgb}{0.64,0.00,0.00} \definecolor{Aluminium1}{rgb}{0.93,0.93,0.92} \definecolor{Aluminium2}{rgb}{0.82,0.84,0.81} \definecolor{Aluminium3}{rgb}{0.73,0.74,0.71} \definecolor{Aluminium4}{rgb}{0.53,0.54,0.52} \definecolor{Aluminium5}{rgb}{0.33,0.34,0.32} \definecolor{Aluminium6}{rgb}{0.18,0.20,0.21} \lstset{ keywordstyle=[1]{\color{DarkSkyBlue}}, keywordstyle=[2]{\color{DarkScarletRed}}, keywordstyle=[3]{\bfseries}, keywordstyle=[4]{\color{DarkPlum}}, keywordstyle=[5]{\color{SkyBlue}}, commentstyle={\color{Aluminium4}\tiny}, stringstyle={\color{Chocolate}}, tabsize=4, breaklines=true, basicstyle={\ttfamily\tiny}, xleftmargin=21pt, xrightmargin=11pt, frame=single, rulecolor=\color{black!30}, captionpos=b, framesep=10pt, framexleftmargin=18pt, numbers=none, numberstyle={\tiny}, stepnumber=1, numbersep=15pt } \lstdefinelanguage{Ada}{% morekeywords={alfa,and,array,begin,boolean,byte,case,char,const,div,% do,downto,else,end,false,file,for,function,get,goto,if,in,% integer,label,maxint,mod,new,not,of,or,pack,packed,page,program,% procedure,put,read,readln,real,record,repeat,reset,rewrite,set,% text,then,to,true,type,unpack,until,var,while,with,write,writeln},% sensitive=false,% morecomment=[s]{(*}{*)},% morecomment=[s]{\{}{\}},% morestring=[d]{'}% } \lstdefinelanguage{SQL}{% morekeywords={select,insert,table,from,into,create,delete,alfa,and,array,begin,boolean,byte,case,char,const,div,% do,downto,else,end,false,file,for,function,get,goto,if,in,% integer,label,maxint,mod,new,not,of,or,pack,packed,page,program,% procedure,put,read,readln,real,record,repeat,reset,rewrite,set,% text,then,to,true,type,unpack,until,var,while,with,write,writeln},% sensitive=false,% morecomment=[s]{(*}{*)},% morecomment=[s]{\{}{\}},% morestring=[d]{'},% caption=SQL% } \lstnewenvironment{SQL}[1][]{\lstset{language=SQL,title=SQL,title=Example,#1}}{} \lstnewenvironment{Code}[1][]{\lstset{language=Ada,framerule=0pt,#1}}{} \lstnewenvironment{Example}[1][]{\lstset{language=Ada,#1}}{} \lstnewenvironment{NumberedExample}[1][]{\lstset{language=Ada,numbers=left,escapeinside={(*@}{@*)},#1}}{} \lstnewenvironment{ShellNumberedExample}[1][]{\lstset{language=sh,numbers=left,escapeinside={(*@}{@*)},#1}}{} \renewcommand\lstlistingname{Example} \newcommand\apqversion{3.2} %\DeclareCaptionFont{white}{\color{white}} %\DeclareCaptionFormat{listing}{\colorbox[cmyk]{0.43, 0.35, 0.35,0.01}{\parbox{\textwidth}{\hspace{15pt}#1#2#3}}} %\captionsetup[lstlisting]{format=listing,labelfont=white,textfont=white, singlelinecheck=false, margin=0pt, font={bf,footnotesize}} %\DefineVerbatimEnvironment{SQL}{Verbatim}% % {frame=single,fontsize=\small,label={SQL},labelposition=topline} %\DefineVerbatimEnvironment{Code}{Verbatim}% % {frame=single,fontsize=\small} %\DefineVerbatimEnvironment{Example}{Verbatim}% % {frame=single,fontsize=\small,label={Example},labelposition=topline} %\DefineVerbatimEnvironment{NumberedExample}{Verbatim}% % {frame=single,numbers=left,fontsize=\small,label={Example},labelposition=topline,commandchars=\\\{\}} %==============% % The document % %==============% \begin{document} \title{APQ Ada2005 Database Binding} \author{% Copyright (c) 2002-2004, Warren W. Gay VE3WWG\\% Copyright (c) 2007-2011, KOW Framework Project } \date{\today} \maketitle \tableofcontents{} \listoftables %\listoffigures \chapter{Introduction} \section{APQ Version \apqversion} This manual documents APQ Version \apqversion, which is released under the GNAT Modified GPL\index{GPL} (GNU Public License)\index{GNU Public License} license. This license is designed to give both the \index{distributor} and user the necessary freedoms to enjoy the fair use and distribution of the sources \index{distribution of sources} contained in this project. See \Ref{license} for more details. \section{KOW Framework} APQ is now part of the KOW Framework\index{KOW Framework}\footnote{\url{http://framework.kow.com.br}}, which provides a range of libraries for developing web applications in Ada 2005.\\ Other library of interest in the KOW Framework is APQ Provider\footnote{\url{http://framework.kow.com.br/projects/apqprovider}}, which provides a task-safe database connection pool for server applications. A connection pool removes the connecting/disconnecting overhead and guaranties your code will be running with a valid connection.\\ APQ Provider depends on \begin{description} \item [KOW Lib] provides basic logging, file system utilities, locales and so on \item [KOW Config] provides an easy way for dealing with configuration files \end{description} while APQ doesn't depend on any KOW Framework library at all. \section{Supported Databases} The APQ binding\index{binding} was initially created to satisfy the simple need to allow Ada\index{Ada} programs to use a PostgreSQL\index{PostgreSQL} database. However, as open sourced database technologies continue to advance, the need to allow other databases to be used, becomes greater. Rather than write a unique Ada binding for each one, it was conceptualized that a common API\index{API} could emerge from the APQ framework\index{framework}. To this end, the APQ binding has been reworked rather extensively for version 2.1, to permit increasing levels of general support of other database technologies, including MySQL\index{MySQL}.\\ In the fall of 2003 the foundation was laid for Sybase\index{Sybase} support in the unreleased APQ \apqversion software using Sybase on a trial download\index{download} basis. Sybase highlighted some new APQ design \index{design, APQ} wrinkles, which required a few new adjustments and API additions. However, this development ground to a halt for a spell, until September 9, 2004 when it was announced on www.slashdot.org\index{www.slashdot.org} that ``Sybase Releases Free Enterprise Database on Linux''\index{Linux}.\\ \begin{quote} ``Sybase announced today that they are releasing a free (as in beer) version of their flagship database for Linux. The free version is limited to 1 CPU, 2 GB of RAM, and 5 GB of data, which is more than adequate for all but the most demanding applications. This release provides a very attractive alternative to Microsoft SQL Server\index{Microsoft SQL Server}, and gives developers and DBAs an extremely powerful argument to use against the adoption of Microsoft-based solutions.''% \footnote{Posted by ``Tassach'' (tassach@rapiertech.com)} \end{quote} Now there was greater reason to put enterprise class database support into an Ada thick binding\index{thick binding} for databases. Sybase support in APQ would allow developers to develop real applications in using Ada, without trial software expiring. Once developed, these same Ada applications could be deployed within the enterprise and on a large scale.\\ Thanks to the enterprise class database support, APQ entered the enterprise development world. This resulted in needing to support both Microsoft SQL Server\index{Microsoft SQL Server} and ODBC.\\ This resulted in major refactoring of the code and the package apq-sybase moved to apq-ct\_lib. Also, APQ became FreeTDS\index{FreeTDS} compatible. \begin{table}{ \begin{tabular}{lcccl} Database & As of APQ Version & SQL & Blob & Module \\ \hline PostgreSQL & 1.x & Yes & Yes & apq-postgresql \\ MySQL & 2.x & Yes & No & apq-mysql \\ Sybase 12.52 & 2.2 & Yes & No & apq-ct\_lib \\ SQL Server & 3.0 & Yes & No & apq-ct\_lib \\ ODBC & 3.2 & Yes & No & apq-odbc \end{tabular}} \caption{Database Product Support}\label{t:DBSupport} \end{table} Table \ref{t:DBSupport} is further described as follows: \begin{description} \item [As of APQ Version]is the version where the database was first supported. \item [SQL]indicates whether the common SQL functions are supported (sans blob). \item [Blob]indicates whether blob support is present. \item [Module]indicates the module where the specific binding is implemented \end{description} As the reader can observe in the table above, the only database with blob support\index{blob support} so far is PostgreSQL. This is so because MySQL's blob interface is not as complete as provided by PostgreSQL. Where PostgreSQL provides the facility for virtually limitless sized blobs, a MySQL blob must fit within a ``column'', very much like a text field. For this reason, the facility to perform stream oriented\index{stream oriented} I/O is lacking on a blob in APQ for MySQL.\\ Also, there han't been time or interest in developing Blob support in Sybase and SQL Server so far. This implementation should take quite a while to be done and for now the focus of the project is in providing a stable solution for database connectivity with up to date documentation.\\ The ODBC\index{ODBC} support is considered pre-alpha, only tested on Windows platforms. There is no build system for it yet and for now there is no interest and continuing this as MySQL and PostgreSQL have proven to be stable and robust enough for all of our needs. \subsection{The Future of Blob Support for MySQL} Much investigation and research\index{research, APQ} is required to adequately resolve the blob issue in APQ. Rather than hold back the binding from general use, where blob functionality may have limited use anyway, it was decided to release APQ 2.0 with the common API for the two databases, and leaving the resolution of the blob API for a future release.\\ If you are a developer, who hopes to write portable database\index{portable database code} code, then please be aware that the PostgreSQL\index{PostgreSQL} blob\index{blob} API is subject to future revision. Potentially, this could be fairly extensively revised, but every attempt will be made to leave a migration path open to the developer. \section{Generic Database Support} One of the main goals of the APQ version 2.0 release, was to develop a common API\index{API, common}, that does not discriminate based upon the database technology being selected. The ideal was to allow a developer to write a procedure that would accept a classwide\index{classwide} database objects, and perform database operations without needing to be concerned whether the database being used was PostgreSQL\index{PostgreSQL}, MySQL\index{MySQL} or Sybase\index{Sybase}. To a large extent, the author believes that this goal has been achieved. \subsection{Generic Limitations} It must be admited however, there are some areas where the database technologies were very different. Consequently, some exceptions and work-arounds will be required by the programmer. An example of this is that MySQL\index{MySQL} requires that all rows be fetched from a SELECT\index{SELECT} query. A failure to do this, corrupts the communication between the server\index{communication, server} and the client. Consequently, APQ works around this by defaulting to use the C library call mysql\_store\_result()\index{mysql\_store\_result()} instead of the alternative, which is mysql\_use\_result()\index{mysql\_use\_result()}. However, if the result set is large,\index{large result sets} then receiving all of the rows into the clients memory\index{memory, client} is not a suitable choice. Consequently, APQ does provide some MySQL specific ways to manage this setting.\\ The MySQL database software also provides the special ``LIMIT n''\index{LIMIT n} extension, if the client program is only interested in the first n rows of the result. If for example, you have a price file containing stock price history, you may want to query the most recent price for it. The simplest way to do this would be to perform a SELECT\index{SELECT} on the table with a descending price date sort sequence (or index). But if you only want the first (most recent) row \index{most recent row} returned, you do not want to retrieve the entire price history into the memory of your client! This is what mysql\_store\_result()\index{mysql\_store\_result()} implies (APQ default). So the application programmer will need to plan for this, when MySQL is used. He will need to do one of the following: \begin{itemize} \item Cause mysql\_use\_result() to be used instead (change the APQ default), and then fetch all of the rows, one by one. \item Use the MySQL ``LIMIT 1''\index{LIMIT n} SQL extension to limit the results to 1 row. \end{itemize} The problem of course, is that this type of handling must only be done for MySQL\index{MySQL} databases. Consequently, APQ also provides an API so that the application may query which database is being used. \section{The APQ Database Binding} This software represents a binding\index{binding to objects} to objects and procedures that enable the Ada2005\index{Ada2005}% \footnote{Hereafter, we'll just refer to the language as Ada, even though the version of the language implied is Ada2005.% } programmer to manipulate or query a relational database.\index{relational database} This document describes the design principles and goals\index{goals of APQ} of this APQ binding. It also supplies reference documentation\index{reference documentation} to the programmer, enabling the reader to write applications using the PostgreSQL\index{PostgreSQL}, MySQL\index{MySQL} or Sybase\index{Sybase} databases, in the Ada programming language.\\ We recomend you to use the newest GNAT distribution possible. Both FSF and Adacore's version are supported. APQ is currently developed under Sabayon Linux, but updated debian packages are currently available.\\ The source code avoids any use of GNAT\index{GNAT} specific language extensions\index{language extensions}. The possible exception to this rule is that the gnatprep\index{gnatprep} tool may be used to precompile\index{precompile} optional support of optional databases\index{optional databases}. There is some C\index{C language} language source\index{source code} code used, to facilitate Ada\index{Ada} and database C language library linkages. \begin{table} \begin{center} \begin{tabular}{ll} Library & Module \\ \hline libpq & apq-postgresql \\ libmysqlclient & apq-mysql \\ OCS-12\_5 or FreeTDS & apq-ct\_lib \\ \end{tabular} \end{center} \caption{Client Libraries}\label{t:ClientLib} \end{table} Table \ref{t:ClientLib} lists the C language libraries\index{libraries, C} that are used in addition to the APQ client\index{library, APQ client} library, while linking\index{linking} your application.\\ GNAT specific features are avoided where possible, but as it has become the \emph{de facto} standard compiler for Ada we tend to use some of it's facilities.\\ For now our code is built using gprbuild\index{gprbuild} tool (which actually should support non-ACT\index{non-ACT} vendors).\\ GNAT\index{GNAT} specific pragma\index{pragma} statements of the form:\\ \index{Linker\_Options} \begin{Code} pragma Linker_Options("-lapq"); \end{Code} were used in the past, but thanks to gprbuild they are being removed in favour of a more portable way for controlling the linker\index{linking}. Therefore those using non-ACT\index{non-ACT} vendor supplied Ada compilers\index{Ada compilers} might be able to compile and use this binding\index{binding} without a huge investment even if their compiler isn't supported by gprbuild.\\ APQ has been tested in the following platforms: \begin{description} \item [Windows] several versions, but for now 32bit windows only. APQ should work in 64 bit windows as well. \item [Linux] both 32 and 64 bit Linux distributions, including Debian, Ubuntu, Sabayon and Gentoo linux. \item [FreeBSD] even thought it hasn't been tested recently \item [Open Solaris] same as FreeBSD \end{description} \subsection{General Features} This binding\index{binding} supports all of the normal database functions that a programmer would want to use. Additionally blob\index{blob} support is included% \footnote{For PostgreSQL only, at release 2.0.% }, and implemented using the Ada streams\index{streams, Ada} interface\index{interface}. This provides the programmer with the Ada convenience and safety of the streams interface\index{streams interface} when working with blobs.\\ This binding includes the following general features: \begin{enumerate} \item Open and Close one or more concurrent database connections\index{connections} \item Create and Execute one or more concurrent SQL queries\index{queries, concurrent} on a selected database connection\index{connection, database} \item Begin work\index{begin work}, Commit work\index{commit work} or Rollback work\index{rollback work} \item Access error message\index{error messages} text \item Generic functions and procedures to support specialized application types \item The NULL indicator\index{NULL indicator} is supported \item Blob\index{blob} support using the Ada streams\index{streams, Ada} facility \item A wide range of native\index{native types} and builtin\index{builtin data types} data types are supported \item Database neutral API\index{neutral API, database} is now supported for most functions \end{enumerate} \subsection{Binding Type} This library represents a thick Ada binding\index{thick binding} to the PostgreSQL C\index{C programmer} programmer's libpq\index{libpq} library % \footnote{C++ programs can also make use of this library but there exists the library libpq++ for C++ native support.% }, and with version 2.0, MySQL's\index{MySQL} C programming library. As a thick binding, there are consequently Ada objects\index{objects, Ada} and data types that are tailored specifically to the Ada programmer. Some data types and objects exist to mirror those used in the C language, while others are provided to make the binding easier or safer to apply.\\ A thin binding\index{thin binding} would have required the Ada programmer to be continually dealing with C language\index{C language data types} data type issues. Conversions to and from various types and pointers\index{pointers} would be necessary making the use of the binding rather tedious. Furthermore, the resulting Ada\index{Ada} program would be much harder to read and understand.\\ A thick binding\index{thick binding} introduces new objects and types in order to provide an API to the programmer. This approach however, fully insulates the Ada\index{Ada} programmer from interfacing with C programs\index{C programs}, pointers\index{pointers} and strings\index{strings}. The design goal\index{design goal} has additionally been to keep the number of new objects and types to a minimum. This has been done without sacrificing convenience and safety\index{safety}. Readability\index{readability} of the resulting Ada\index{Ada} program was also considered to be important.\\ The objects and data types involved in the use of this binding can be classified into the following main groups: \begin{enumerate} \item Native\index{native data types} data types and objects \item Database \index{database objects} manipulation objects \item New database related objects and types for holding data \end{enumerate} Native data types need no explanation in this document. The database manipulation objects will be described in \Ref{Database_Objects:Section}. The following section will introduce the Ada types\index{Ada types} that are used to hold data. \section{Binding Data Types} The PostgreSQL\index{PostgreSQL} database supports many standard SQL\index{SQL data types} data types as well as a few exotic ones. This section documents the database base types\index{data types, database} that are supported by the Ada\index{Ada binding} binding to the database. This list is expected to grow with time as the Ada binding continues to mature in its own software development.\\ The ``Data Type Name'' column in the following table refers to a binding type\index{binding type} if the type name is prefixed with ``APQ\_''% \footnote{Formerly, the PostgreSQL specific types had used a PG\_ prefix.% }. These data types were designed to mimic common database data types in use. They can be used as they are provided, or you may subtype from them or even derive new types from them in typical Ada\index{Ada} fashion. All other data types are references to native Ada data types (for some of these, the package where they are defined are shown in the ``Notes'' column).\\ The column labelled ``Root Type''\index{root types} documents the data type that the APQ\_ data type was derived\index{derived} from. Where they represent an Ada\index{subtype, Ada} subtype, the column ``Subtype'' indicates a ``Y''. For type derivations a ``N'' is shown in this column, indicating that the APQ\_ type \index{APQ\_ types} listed is made ``unique''.\\ \subsection{PostgreSQL Data Types\label{PostgreSQL SQL Data Types}} The ``Notes'' column of Table \ref{t:pqtypes} provides PostgreSQL notes, package names\index{package names} and PostgreSQL\index{data types, PostgreSQL} data type names where the name is given in all capitals. \begin{longtable}{|l|c|c|l|} \hline Data Type Name & Root Type & Subtype & PostgreSQL Notes\\ \hline \hline Row\_ID\_Type & - & N & Used for blobs and rows\\ \hline String(<>) & - & - & Native Strings\\ \hline String(a..b) & - & - & Fixed length strings\\ \hline Unbounded\_String & - & - & Ada.Strings.Unbounded\\ \hline Bounded\_String & - & - & Ada.Strings.Bounded\\ \hline APQ\_Smallint & - & N & SMALLINT\\ \hline APQ\_Integer & - & N & INTEGER\\ \hline APQ\_Bigint & - & N & BIGINT\\ \hline APQ\_Real & - & N & REAL\\ \hline APQ\_Double & - & N & DOUBLE PRECISION\\ \hline APQ\_Serial & - & N & SERIAL\\ \hline APQ\_Bigserial & - & N & BIGSERIAL\\ \hline APQ\_Boolean & Boolean & Y & BOOLEAN\\ \hline APQ\_Date & Ada.Calendar.Time & Y & DATE\footnote{Local timezone assumed}\\ \hline APQ\_Time & Ada.Calendar.Day\_Duration & Y & TIME\footnote{Local timezone assumed}\\ \hline APQ\_Timestamp & Ada.Calendar.Time & N & TIMESTAMP\footnote{Converted into and loaded as UTC}\\ \hline APQ\_Bitstring & - & N & BIT or BIT VARYING\\ \hline Decimal\_Type & - & - & PostgreSQL.Decimal\\ \hline range <> & - & - & Native Integers\\ \hline delta <> & - & - & Native Fixed Point\\ \hline digits <> & - & - & Native Floating Point\\ \hline delta <> digits <> & - & - & Native Decimal\\ \hline \caption{PostgreSQL Data Types}\label{t:pqtypes} \end{longtable} The data type shown as ``Decimal\_Type''\index{Decimal\_Type} is special, in that it is supported from a child package APQ\-.PostgreSQL\-.Decimal\index{APQ.PostgreSQL.Decimal}. It represents a tagged\index{tagged type} type that provides an interface to the C routines\index{C routines} used by the PostgreSQL database server, for arbitrary precision decimal\index{precision, arbitrary} values. \subsection{MySQL Data Types\label{MySQL Data Types}} Table \ref{t:mytypes} summarizes the MySQL\index{data types, MySQL} specific data types and the corresponding APQ data types. \begin{longtable}{|l|c|c|l|} \hline APQ Data Type & Ada Spec & Subtype & Comments\\ \hline \hline Row\_ID\_Type & unsigned 64 bits & N & For all databases\\ \hline APQ\_Smallint & signed 16 bits & N & SMALLINT\\ \hline APQ\_Integer & signed 32 bits & N & INTEGER\\ \hline APQ\_Bigint & signed 64 bits & N & BIGINT\\ \hline APQ\_Real & digits 6 & N & REAL\\ \hline APQ\_Double & digits 15 & N & DOUBLE PRECISION\\ \hline APQ\_Serial & range 1..2147483647 & N & \emph{INTEGER}\\ \hline APQ\_Bigserial & range 1..2{*}{*}63 & N & \emph{BIGINT}\\ \hline APQ\_Boolean & Boolean & Y & BOOLEAN\\ \hline APQ\_Date & Ada.Calendar.Time & Y & DATE\\ \hline APQ\_Time & Ada.Calendar.Day\_Duration & Y & TIME\\ \hline APQ\_Timestamp & Ada.Calendar.Time & N & TIMESTAMP\\ \hline APQ\_Bitstring & array(Positive) of APQ\_Boolean & N & \emph{Not in MySQL}\\ \hline \caption{MySQL Data Types}\label{t:mytypes} \end{longtable} Notice the italicized SQL keywords\index{keywords, SQL} in the table. They identify the SQL keywords that differ from PostgreSQL\index{PostgreSQL}. However, the programmer only needs to be concerned with these SQL\index{keywords, SQL} keywords when creating new tables or temporary tables. For example a column of type SERIAL\index{SERIAL} in a PostgreSQL table, should be declared as a INTEGER\index{INTEGER} type in MySQL. \section{Sybase Data Types} The chart below outlines the mappings between APQ data types and Sybase server data types\index{data types, Sybase}. The italicized SQL keywords \index{keywords, SQL} in the table identify the keywords that differ from PostgreSQL\index{PostgreSQL}. The following notes are particular to Sybase\index{Sybase}: \begin{itemize} \item APQ\_Bigint is not completely range compatible with Sybase's \emph{NUMERIC} \index{APQ\_Bigint}\index{NUMERIC}\index{DECIMAL} (or \emph{DECIMAL}) server types. APQ\_Bigint will always accept Sybase server values, but the server will not be able to accept the full APQ\_Bigint range of values. To comply with the database server's range, the application designer should use: \end{itemize} \index{Sybase\_Bigint} \begin{Code} subtype Sybase_Bigint is APQ_Bigint range -10**38..10**38-1; \end{Code} \begin{itemize} \item APQ\_Bigserial\index{APQ\_Bigserial} is not supported. \item APQ\_Boolean\index{APQ\_Boolean} maps to Sybase's data type \emph{BIT.} \item APQ\_Bitstring\index{APQ\_Bitstring} is not supported. \end{itemize} Table \ref{t:sytypes} lists the APQ types supported for Sybase. \begin{longtable}{|l|c|c|l|} \hline APQ Data Type & Ada Spec & Subtype & Comments\\ \hline \hline Row\_ID\_Type & unsigned 64 bits & N & For all databases\\ \hline APQ\_Smallint & signed 16 bits & N & SMALLINT\\ \hline APQ\_Integer & signed 32 bits & N & INTEGER/INT\\ \hline APQ\_Bigint & signed 64 bits ($-10^{38}..$$10^{38}\textrm{-1}$) & N & \emph{NUMERIC/DECIMAL}\\ \hline APQ\_Real & digits 6 & N & REAL\\ \hline APQ\_Double & digits 15 & N & DOUBLE PRECISION\\ \hline APQ\_Serial & range 1..2147483647 & N & \emph{INTEGER}\\ \hline APQ\_Bigserial & range 1..$2^{63}$ & N & ???\\ \hline APQ\_Boolean & Boolean & Y & \emph{BIT}\\ \hline APQ\_Date & Ada.Calendar.Time & Y & DATE\\ \hline APQ\_Time & Ada.Calendar.Day\_Duration & Y & TIME\\ \hline APQ\_Timestamp & Ada.Calendar.Time & N & \emph{DATETIME}\\ \hline APQ\_Bitstring & array(Positive) of APQ\_Boolean & N & \emph{Not in Sybase}\\ \hline \caption{Sybase Data Types}\label{t:sytypes} \end{longtable} \section{Database Objects\label{Database_Objects:Section}} Much of the binding between Ada\index{Ada} and the database server is provided through the use of tagged\index{tagged record} record types. Presently the APQ binding operates through three object types\index{object types, APQ} listed in Table \ref{t:APQObj}. \begin{table} \begin{center} \begin{tabular}{lll} Derived From & Object Type & Purpose\\ \hline Root\_Connection\_Type & Connection\_Type & Database connection\\ Root\_Query\_Type & Query\_Type & SQL interface\\ N/A & Blob\_Type & Blob operations\\ \end{tabular} \end{center} \caption{APQ Object Types}\label{t:APQObj} \end{table} The APQ objects from Table \ref{t:APQObj} are described more fully as follows: \begin{description} \item[Connection\_Type] object is used with Query\_Type and Blob\_Type objects to perform SQL queries and blob operations respectively. This object maintains the connection to the database server. \item[Query\_Type] objects are used with one Connection\_Type object to perform SQL query operations. This object holds the text of the SQL query, some query state and result information. To execute a query, it must be used in conjunction with a Connection\_Type object. \item[Blob\_Type] objects are used with one Connection\_Type object to perform blob operations. This is currently only supported for PostgreSQL by APQ. All blob operations must occur within a transaction. \end{description} \begin{floatingtable}{ \begin{tabular}{lc} Object & Finalized \\ \hline Connection\_Type & Yes \\ Query\_Type & Yes \\ Blob\_Type & No \\ \end{tabular}} \caption{Object Finalization Behavior}\label{t:Finalization} \end{floatingtable} Table \ref{t:Finalization} lists the three APQ objects and their finalization behaviour. While the Connection\_Type\index{Connection\_Type} and Query\_Type\index{Query\_Type} objects are subject to finalization, the Blob\_Type\index{Blob\_Type} is not. This is because it represents an access type to a Blob\_Object. This is similar in concept to an open a file, using the File\_Type data type. This design approach was necessary to support Ada\index{Ada} Streams\index{streams, Ada} oriented access for blobs. \subsection{Object Hierarchy} Before multiple database products were supported, the APQ object hierarchy\index{hierarchy} was simple. To provide generic level support however, there are now root\index{root objects} objects and derived objects\index{derived objects}. In most programming contexts, the application writer does not need to be concerned with this fact. However, if you frequently inspect the spec files\index{spec files} instead of the documentation\index{documentation}, you must be aware that primitives\index{primitives} for a given object may be declared in multiple places. Examine Table \ref{t:pkghier} to review the APQ package hierarchy. \begin{table} \begin{center} \begin{tabular}{ll} Package Name & Description \\ \hline APQ & Root objects and primitives \\ APQ.PostgreSQL & Declarations and constants unique to PostgreSQL \\ APQ.PostgreSQL.Client & Derived objects and added primitives \\ APQ.MySQL & Declarations and constants unique to MySQL \\ APQ.MySQL.Client & Derived objects and added primitives \\ APQ.Sybase & Declarations and constants unique to Sybase \\ APQ.Sybase.Client & Derived objects and added primitves for Sybase \\ \end{tabular} \end{center} \caption{APQ Package Hierarchy}\label{t:pkghier} \end{table} Table \ref{t:pkghier} illustrates that support for a given database is derived\index{derived} from the APQ top level\index{top level package} package. Root objects\index{root level} are declared in APQ, with common functionality. Some primitives must be overridden\index{overridden} by the derived object in database specific packages. For example, APQ.Root\_Query\_Type declares a primitive named Value (\emph{APQ.Value)} to return a string column result. If this particular method is called, the exception \emph{Is\_Abstract}\index{Is\_Abstract} will be raised to indicate that it must be overriden with code to handle the specific database being used. Normally the user would invoke APQ\-.MySQL\-.Client\-.Value when using the MySQL\index{MySQL} database, for example. The programmer normally need not be aware of these details, since object dispatching\index{dispatching} takes care of these details. For this reason, the APQ\-.MySQL\-.Query\_Type object for example, is derived from the APQ\-.Root\_Query\_Type\index{Root\_Query\_Type} object. This Query\_Type\index{Query\_Type} object will provide its own implementation of the Value\index{Value} function to return a column result, and will work as required. Consequently, when looking for primitives\index{primitives} available to the Query\_Type object, don't forget that many common primitives\index{common primitives} will be inherited\index{inherited} from the APQ\-.Root\-\_Query\-\_Type object. The same is true for Connection\-\_Type\index{Connection\_Type} objects. A number of common primitives are inherited from the APQ\-.Root\_Connection\_Type object. \chapter{Connecting to the Database} Before any useful work can be accomplished by a database client program, a connection must be established between the Ada program and the database server. This chapter will demonstrate how to use the APQ binding\index{binding} to enable a program to connect\index{connect} and disconnect\index{disconnect} from the database server. \section{The Connection\_Type} The Connection\_Type\index{Connection\_Type} object holds everything that is needed to maintain a connection\index{connection} to the database server. There are seven groups of primitive\index{primitive} operations for this object: \begin{enumerate} \item Context\index{Context} setting operations \item Connection\index{Connection} operations \item Connection Information functions\index{information functions} \item General Information operations \item Implicit operations (Finalization\index{Finalization}) \item Trace Facilities\index{trace facilities} \item Generic Database Operations \end{enumerate} \section{Context Setting Operations}\label{Context_Setting_Operations} These primitives ``configure''\index{configure} the connection\index{connection} that is to be made later. When the object is initially created, it is in the disconnected\index{disconnected state} state. While disconnected, configuration changes can be made in to affect the next connection attempt. With the exception of the database name\index{database name}, the application should not make configuration\index{configuration} changes while the object is in the connected state\index{connected state}. \footnote{This is not yet enforced by APQ.} The configuration primitives\index{primitives} are listed in Table \ref{t:ctxops}. \footnote{The items marked ``Root'' are primitives from APQ.Root\_Query\_Type. The items marked {}``Derived'' are those overrides that are declared on the APQ.{*}.Query\_Type object.} \begin{table} \begin{center} \begin{tabular}{ccll} Type & Derivation & Name & Purpose \\ \hline proc & Root & Set\_Host\_Name & Set server host name \\ proc & Root & Set\_Host\_Address & Set server host IP address \\ proc & Root & Set\_Port & Set server port number \\ proc & Root & Set\_DB\_Name & Set database name \\ proc & Root & Set\_User\_Password & Set userid and password \\ proc & Root & Set\_Instance & Set instance name to use \\ proc & Root & Set\_Options & Set userid and password \\ \end{tabular} \end{center} \caption{Context Setting Primitives}\label{t:ctxops} \end{table} It would be nice if all database software products worked the same way but the reality is very different. Table \ref{t:ctxdiffs} indicates how the primitives apply by database product.\label{Set_Instance Support Chart} In the table you can see that PostgreSQL\index{PostgreSQL} and MySQL\index{MySQL} establish their connection by specifying the host, port and database name. Sybase on the other hand, specifies this information in their \emph{interface} file. To access the appropriate Sybase\index{Sybase interface entry} interface entry requires only the \emph{instance}\index{instance} information supplied by the Set\_Instance\index{Set\_Instance} call. \begin{table} \begin{center} \begin{tabular}{lccc} Primitive & PostgreSQL & MySQL & Sybase \\ \hline Set\_Host\_Name & Yes & Yes & Ignored \\ Set\_Host\_Address & Yes & Yes & Ignored \\ Set\_Port & Yes & Yes & Ignored \\ Set\_DB\_Name & Yes & Yes & See Note % \footnote{Set\_DB\_Name is useful after the connection is made.}\\ Set\_User\_Password & Yes & Yes & Yes \\ Set\_Instance & No & No & Yes \\ Set\_Options & Yes & Yes & Yes \\ \end{tabular} \end{center} \caption{Context Setting Differences}\label{t:ctxdiffs} \end{table} \subsection{PostgreSQL Defaults} The PostgreSQL database defines certain environment\index{environment, PostgreSQL} variables that can specify defaults. These and the fallback\index{fallback values} values are documented in Table \ref{t:pqdef}. \begin{table} \begin{center} \begin{tabular}{cclll} Type & Derivation & Name & Default & Fallback \\ \hline proc & Root & Set\_Host\_Name & PGHOST & localhost\\ proc & Root & Set\_Host\_Address & PGHOST & localhost\\ proc & Root & Set\_Port & PGPORT & 5432\\ proc & Root & Set\_DB\_Name & PGDATABASE & LOGNAME\\ proc & Root & Set\_User\_Password & \begin{tabular}{l} PGUSER\\ PGPASSWORD\\ \end{tabular} & LOGNAME\\ proc & Root & Set\_Options & PGOPTIONS & ""\\ \end{tabular} \end{center} \caption{PostgreSQL Context Defaults}\label{t:pqdef} \end{table} The capitalized names in the table for the ``Default'' and ``Fallback'' columns represent environment\index{environment} variable names. When any of the environment\index{environment variables} variables are undefined in the ``Default'' column, the value used is determined by the ``Fallback'' value listed. The fallback\index{fallback} variable name LOGNAME\index{LOGNAME} is simply used to represent the current user's userid\index{userid}.% \footnote{The PostgreSQL libpq library may in fact, completely ignore the LOGNAME environment variable, and simply look up the userid in the /etc/password file.% } When no password\index{password} value is provided and no PGPASSWORD\index{PGPASSWORD} environment variable exists, then no password is assumed. \subsection{Procedure Set\_Host\_Name} The Set\_Host\_Name\index{Set\_Host\_Name} procedure accepts the following arguments \begin{Code} procedure Set_Host_Name( C : in out Connection_Type; Host_Name : in String ); \end{Code} The following example configures the Connection\_Type object to connect to host\index{host name} ``witherspoon'': \begin{Example} declare C : Connection_Type; begin Set_Host_Name(C,"witherspoon"); \end{Example} \begin{description} \item [Note:]Sybase ignores this API call. \end{description} \subsection{Procedure Set\_Host\_Address} The procedure takes two arguments, in the same fashion as Set\_Host\_Name\index{Set\_Host\_Address}: \begin{Code} procedure Set_Host_Address( C : in out Connection_Type; Host_Address : in String ); \end{Code} The following example configures the Connection\_Type object to connect to IP address\index{IP address} 10.0.0.7: \begin{Example} declare C : Connection_Type; begin Set_Host_Address(C,"10.0.0.7"); \end{Example} \begin{description} \item [Note:]Sybase ignores this API call. \end{description} \subsection{Procedure Set\_Port (IP)} This procedure configures the port\index{port} where the database server\index{server} is listening\index{listening} (when using TCP/IP\index{TCP/IP} as the transport\index{transport}): \begin{Code} procedure Set_Port( C : in out Connection_Type; Port_Number : in Integer ); \end{Code} \begin{floatingtable}{ \begin{tabular}{ccc} Database & Default & Port\\ \hline PostgreSQL & IP & 5432\\ MySQL & UNIX & ?\\ Sybase & N/A & Ignored\\ \end{tabular}} \caption{Default Database Connections}\label{t:defdb} \end{floatingtable} Table \ref{t:defdb} shows the connection defaults by database product. Some of these are influenced by APQ. For example, APQ defaults to using a TCP/IP connection for the PostgreSQL standard port of 5432. The next example shows how the port\index{port} number is configured. The example configures APQ to use TCP/IP port number 5432\index{port 5432} to connect to a PostgreSQL database. \begin{Example} declare C : Connection_Type; begin Set_Port(C,5432); \end{Example} \begin{description} \item [Note:]Sybase ignores this API call. \end{description} \subsection{Procedure Set\_Port (UNIX)} To create a local UNIX socket connection to the database, there is an overloaded version of Set\_Port\index{Set\_Port} that accepts a string\index{string} parameter instead of an integer\index{port, integer} port number. \begin{Code} procedure Set_Port( C : in out Connection_Type; Port_Number : in String ); \end{Code} Specify a null string\index{null string} for the connection\index{connection} to use the local\index{local socket} UNIX\index{UNIX socket} socket default. This parameter has changed somewhat as PostgreSQL\index{PostgreSQL} evolves. If you are experiencing trouble getting a UNIX\index{UNIX socket} socket connection to work, check the database documentation for PostgreSQL carefully. The following example has been tested to work on PostgreSQL version 7.3.5. \begin{Example} declare C : Connection_Type; begin Set_Port(C,"5432"); \end{Example} See the troubleshooting chapter for tips. \subsection{Procedure Set\_DB\_Name} This procedure call configures the name of the database that the server is to use \emph{prior} to the connection being established. Once the connection has been established, calling Set\_DB\_Name\index{Set\_DB\_Name} switches the connection\index{connection} to use the named database. The calling signature for this primitive is as follows: \begin{Code} procedure Set_DB_Name( C : in out Connection_Type; DB_Name : in String ); \end{Code} The following code fragment shows how the database name\index{database name} is configured to be ``production'': \begin{Example} declare C : Connection_Type; begin Set_DB_Name(C,"production"); \end{Example} The Set\_DB\_Name \emph{always} acts as a configuration setting \emph{prior} to connecting to the database server. Calling Set\_DB\_Name on a Connection\_Type\index{Connection\_Type} object that has an open server connection to the database, can result in hidden SQL commands for some databases.% \footnote{For PostgreSQL and Sybase, a USE command must be executed.% } Table \ref{t:setdb} summarizes the behaviour according to database product. \begin{table} \begin{center} \begin{tabular}{llll} Database Vendor & Before Connecting & While Connecting & After Connected\\ \hline PostgreSQL & Configuration & uses config & ``USE'' Executed\\ MySQL & Configuration & uses config. & MySQL Client Call\\ Sybase & Pending SQL & ``USE'' executed & ``USE'' Executed\\ \end{tabular} \end{center} \caption{Set\_DB\_Name Behaviour}\label{t:setdb} \end{table} From the table you can see that PostgreSQL\index{PostgreSQL} and MySQL\index{MySQL} configure the database prior to connecting\index{connecting} (connecting also establishes the database to be used). When Set\_\-DB\_\-Name is called after a connection has been established, the database server will switch\index{switch database} to the requested database. For some databases, this happens through the native\index{native client API} client API library\index{library} (MySQL), but for others, a ``USE~''\index{USE database} SQL\index{SQL} command must be executed (internally within APQ). \begin{floatingtable}{ \begin{tabular}{ll} Exception Name & Reason\\ \hline Use\_Error & Unsuccessful doing a ``USE ''\\ \end{tabular}} \caption{Set\_DB\_Name Exceptions}\label{t:sdbx} \end{floatingtable} Sybase\index{Sybase} is different again, because does not establish the database at connect time\index{connect time} (Sybase will use the configured default database). So a call to Set\_DB\_Name will queue a ``USE ''\index{USE database} SQL\index{SQL} statement, to be executed by APQ, once the connection succeeds. If another Set\_DB\_Name is performed while connected, new ``USE '' SQL statements are executed on the Sybase server\index{Sybase server} connection provided. The exceptions listed in Table \ref{t:sdbx}\index{exception} are possible when using a new database name. The case of the database name used is affected according to the case policy\index{case policy} that is in effect for the connection\index{connection}. This is summarized in Table \ref{t:cpol} for each database vendor product. \begin{table} \begin{center} \begin{tabular}{llll} Database Product & Case Policy & Effect on DB\_Name & DB Name Sensitive\\ \hline PostgreSQL & Ignored & Case preserved & Yes\\ MySQL & Ignored & Case preserved & Yes\\ Sybase & Ignored & Case preserved & Yes\\ \end{tabular} \end{center} \caption{Case Policy by Product}\label{t:cpol} \end{table} \subsection{Procedure Set\_User\_Password} This procedure call configures both the userid\index{userid} and the password\index{password} together. If there is no password, then supply the null string\index{null string}: \begin{Code} procedure Set_User_Password( C : in out Connection_Type; User_Name : in String; User_Password : in String ); \end{Code} The following code fragment illustrates how the userid and password is configured: \begin{Example} declare C : Connection_Type; begin Set_User_Password(C,"myuserid","xyzzy"); \end{Example} \subsection{Procedure Set\_Case} One of the goals of APQ was to make writing of portable database\index{portable database code} code possible. While this isn't completely possible, the goal remains to reduce database differences. Until the introduction of Sybase\index{Sybase} within APQ, there was little concern for the case of SQL query\index{SQL query code} code used. This APQ manual has always used examples where SQL code is uppercased\index{uppercased SQL code}, with Ada\index{Ada} code using normal Ada2005\index{Ada2005} conventions. This helps to make the SQ\index{SQL}L code standout, and separate it from the other code. Sybase introduces a problem however, since the Sybase server is case sensitive\index{case sensitive} when referring to tables\index{tables} and column\index{column names} names. This feature cannot be disabled for a Sybase server% \footnote{MySQL databases can be configured to be caseless or case sensitive.% }. Since users of Sybase\index{Sybase} tend to use lowercase\index{lowercase names} names, this creates a bit of a problem for portable\index{portable SQL} SQL text within APQ. The approach that APQ \apqversion uses for Sybase\index{Sybase} (and future databases where this matters), all SQL\index{SQL} code is changed to lowercase\index{lowercase} before being sent to the server. Before the reader panics thinking that this won't work, it should be made clear that APQ does not change the case\index{case of SQL} of any string\index{string} that is quoted\index{quoted} (using the Append\_Quoted\index{Append\_Quoted} functions for example). A WHERE\index{WHERE clause} clause such as the following will preserve the text within quotes\index{quotes}: \begin{SQL} where part_no = "XZ98-307" \end{SQL} APQ keeps track of what parts of the SQL\index{SQL query} query were quoted\index{quoted} and which parts were not. This is \emph{not} done by parsing\index{parsing} the SQL text. That would be prone to error and would require intimate knowledge of every SQL dialect supported in APQ. Instead, the string\index{string} fragments are marked for ``preserve''\index{preserve case} case or ``not preserve''\index{preserved, not} as the Query\_Type\index{Query\_Type} object collects text. When the full SQL text\index{SQL text} is require by a routine like To\_String\index{To\_String}, then the standing case policy\index{case policy} is applied to each string\index{string fragment} fragment that has ``not preserve''\index{preserved, not}. You can change this APQ case policy\index{case policy} for Sybase (or any other database). The Set\_Case\index{Set\_Case} function gives you complete control over what the policy to use for SQL case\index{SQL case}. You can choose one of the SQL\_Case\_Type\label{SQL_Case_Type Choices} \index{SQL\_Case\_Type} options, which are listed in Table~\ref{t:cpolicies}. \begin{table} \begin{center} \begin{tabular}{ll} Case Policy & Description\\ \hline Preserve\_Case & Do not make any case changes to the SQL text\\ Lower\_Case & Force unquoted SQL text to lowercase\\ Upper\_Case & Force unquoted SQL text to uppercase\\ \end{tabular} \end{center} \caption{Case Policies for SQL Text}\label{t:cpolicies} \end{table} \begin{floatingtable}{ \begin{tabular}{ll} Database & Default SQL Case Policy\\ \hline PostgreSQL & Upper\_Case\\ MySQL & Lower\_Case\\ Sybase & Lower\_Case\\ \end{tabular}} \caption{Default Case Policies}\label{t:dfcpol} \end{floatingtable} Table~\ref{t:dfcpol} summarizes the default case policies\index{case policies} used in APQ \apqversion for the different database vendor products supported. MySQL\index{MySQL} joins Sybase\index{Sybase} in this case policy because by default, MySQL is case sensitive. If you have configured your MySQL server to be case insenstive, then any setting will do (Upper\_Case\index{Upper\_Case} is suggested for the benefit of the trace log displays). Most users of Sybase\index{Sybase} will likely prefer either the Lower\_Case\index{Lower\_Case} or Preserve\_Case\index{Preserve\_Case} policies instead. The Set\_Case\index{Set\_Case} API procedure for the Connection\_Type object is defined as follows: \begin{Code} procedure Set_Case( C : in out Connection_Type; SQL_Case : in SQL_Case_Type ); \end{Code} You may also use the Get\_Case\index{Get\_Case} function primitive to find out what the current policy in effect is. Please note that a change in policy only affects the outcome of the next call to the following pimitives of the Query\_Type\index{Query\_Type} object: \begin{itemize} \item To\_String \item Execute \item Execute\_Checked \end{itemize} The Set\_Case\index{Set\_Case} call will not actually change the SQL text\index{SQL text} stored within the Query\_Type object. It only sets the policy\index{case policy} mode. The following example shows how to undo the Sybase default of lowercasing the SQL text: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Set_Case(C,Preserve_Case); ... Append(Q,"from table Mixed_Case"); Execute(Q,C); -- SQL case is preserved here \end{Example} \subsubsection{The Viral Nature of Connection\_Type} Note that APQ does permit altering the case policy\index{case policy} for Query\_Type\index{Query\_Type} objects in addition to the Connection\_Type\index{Connection\_Type} object being described here. It should be noted however, that the setting held by the Connection\_Type is viral\index{viral nature} in nature. Whenever a Query\_Type object is used in conjunction with a Connection\_Type object, in a \emph{Execute}\index{Execute} or \emph{Execute\_Checked}\index{Execute\_Checked} call for example, the Query\_Type object will inherit the setting held by the corresponding Connection\_Type object. For this reason, the best application practice is to establish your application case policy\index{case policy} in all Connection\_Type objects used by your application. It is also best practice to use one Connection\_Type object wherever possible, since many queries can share one connection\index{shared connection}. The only reason you should consider applying a case policy\index{case policy} directly to a Query\_Object, is perhaps for application specific uses of the SQL text\index{SQL text}. For example, you could build a query\index{query, build a} in a Query\_Type object, set the case policy to Upper\_Case\index{Upper\_Case}, and then use the To\_String\index{To\_String} function primitive to extract out the SQL text for logging\index{logging} or user display\index{display} purposes. Once however the Query\_Type is used with a Connection\_Type however, (in \emph{Execute}) the Connection\_Type's setting will not only prevail for the primitive, but will also force the Query\_Type's policy to agree upon return from the call. \subsection{Procedure Set\_Options\label{Procedure Set_Options}} This procedure call permits the caller to specify any specialized database server options. The options are specified in string form with this API call. The specific options, and the format\index{format} of those options\index{options} will vary according to the database being used. See the following subsections for additional information about the database engine\index{engine, database} specifics. The procedure Set\_Options\index{Set\_Options} is documented as follows: \begin{Code} procedure Set_Options( C : in out Connection_Type; Options : in String ); \end{Code} Exceptions\index{exceptions} can be raised if the options are being set on a connection that is already connected. Table \ref{t:soopts} lists the exceptions that may be raised by Set\_Options. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Failed & The option is either unsupported or setting was rejected\\ \end{tabular} \end{center} \caption{Set\_Options Exceptions}\label{t:soopts} \end{table} If the options are configured for an unconnected\index{unconnected} Connection\_Type object, the exceptions if any, will be raised at the time of connection (See the Connect primitive). The following PostgreSQL\index{PostgreSQL} code fragment illustrates how two options\index{options} may be configured: \begin{Example} declare C : Connection_Type; begin Set_Options(C,"requiressl=1 dbname=test"); \end{Example} Note that in this example, the option string has been used to declare the database name to be used. Standard values should be set through the primitive functions provided (ie. use Set\_DB\_Name\index{Set\_DB\_Name} instead). Otherwise, when information primitives are added, you may not get correct results. Any non-standard options like the ``requiressl''\index{requiressl} option, should be configured as shown in this procedure call. MySQL\index{MySQL} and Sybase\index{Sybase}, use a comma delimited list\index{delimited list} of options\index{options}. The following example shows how to get Sybase I/O\index{statistics, Sybase I/O} and time statistics\index{statistics, time} recorded in your APQ trace\index{trace log} log: \begin{Example} declare C : Connection_Type; begin Set_Options(C,"STATS_IO=TRUE,STATS_TIME=TRUE"); \end{Example} Option parsing\index{parsing} is rather limited. Everything between the '=' sign and the next comma is the value for the parameter. Different database products will use different parameter types\index{paramater types}. For example, MySQL\index{MySQL} will use 0 to represent False\index{false}, and 1 to represent True\index{true}. For Sybase\index{Sybase}, use F or False, and T or True for Boolean\index{Boolean} values. \subsubsection{PostgreSQL Options} The documentation is not very clear about the format\index{format} of these options, but it appears that keyword=value\index{keyword value pairs} pairs\index{keyword=value pairs} separated by \emph{spaces} for multiple options\index{options} are accepted. If you must include spaces or other special characters within the value component, then you must follow PostgreSQL\index{PostgreSQL} escaping rules\index{escaping rules}. Refer to the database server documentation for these details. \subsubsection{MySQL Options} MySQL's\index{MySQL} C interface\index{C interface} is much different than PostgreSQL's C interface for options. MySQL uses an enumerated value\index{enumerated value} and argument pair\index{argument pair} when setting an option\index{option}.% \footnote{Although, some options do not use the argument.% } To keep the APQ interface friendly and consistent, APQ will accept all options and arguments in a string\index{string} form as documented in \Ref{Procedure Set_Options}. However, these string options\index{string options} must be processed by APQ and digested into arguments usable by the MySQL C client interface. Consequently, APQ must anticipate these options and the option format in advance. For these reasons, the MySQL options and their arguments will be partially documented here. The format\index{format of option string} of the option string should be one or more option names and arguments, separated by commas. Option names\index{option names} are treated as caseless\index{caseless} (internally upcased\index{upcased}). \begin{Example} Set\_Options(C,"CONNECT_TIMEOUT=3,COMPRESS,LOCAL_INFIL=1"); \end{Example} Each option should be separated by a comma. APQ processes each option in left to right fashion, making multiple MySQL C API calls for each one. Table~\ref{t:myopts} lists the APQ supported options for MySQL. \begin{table} \begin{center} \begin{tabular}{lll} Option Name & Argument Type & Comments\\ \hline CONNECT\_TIMEOUT & Unsigned & Seconds\\ COMPRESS & None & Compressed comm link\\ NAMED\_PIPE & None & Windows: use a named pipe\\ INIT\_COMMAND & String & Initialization command\\ READ\_DEFAULT\_FILE & String & See MySQL\\ READ\_DEFAULT\_GROUP & String & See MySQL\\ SET\_CHARSET\_DIR & String & See MySQL\\ SET\_CHARSET\_NAME & String & See MySQL\\ LOCAL\_INFIL & Boolean & See MySQL\\ \end{tabular} \end{center} \caption{MySQL Options}\label{t:myopts} \end{table} It is important to observe that any option that requires an argument\index{argument, option}, must have one. Any argument that requires an unsigned integer\index{unsigned}, must have an unsigned integer (otherwise an exception\index{exception} is raised). A MySQL\index{MySQL} Boolean\index{Boolean} argument should be the value 0 or 1. At the present time, APQ gathers string\index{string} data up until the next comma or the end of the string. Currently an option argument string cannot contain a comma character. \footnote{This needs to be corrected in a future release of APQ.} \subsubsection{Sybase Options} Sybase documents several options\index{options, Sybase} in their ``Open Client C Programmer's Reference'' manual. All documented options are made available to the APQ developer, although some options are not recommended. \begin{floatingtable}{ \begin{tabular}{ll} Option Value & Meaning\\ \hline TRUE & True\\ T & True\\ FALSE & False\\ F & False\\ \end{tabular}} \caption{Boolean Option Values}\label{t:boolarg} \end{floatingtable} Each Sybase option value must conform to certain data type format\index{format, option} and/or restrictions. Table~\ref{t:boolarg} lists acceptable argument values for Boolean\index{Boolean} options, within APQ. The case is not significant, but uppercase is recommended to make it stand out from the surrounding Ada code. The following is an example of a Boolean option setting for the Sybase option STATS\_IO: \begin{Example} "STATS_IO=TRUE" \end{Example} Some Sybase options require an integer\index{unsigned integer} (actually unsigned). Those options listed in the option table\index{option table} as requiring an Unsigned value, should be simply an unsigned value. The following is an example: \begin{Example} "ROWCOUNT=1" \end{Example} String value arguments\index{string value arguments} are simply textual values that are placed between the equal sign and the next comma (or end of string). The following example illustrates: \begin{Example} "AUTHOFF=sa" \end{Example} Some options are identified as taking ``String/NULL''. These options will take normal string values or simply the word NULL\index{NULL options}. The value NULL allows the system default to be used. The following is an example: \begin{Example} "CHARSET=NULL" \end{Example} \begin{table} \begin{center} \begin{tabular}{ll} Value & Sybase Option\\ \hline SUNDAY & CS\_OPT\_SUNDAY\\ MONDAY & CS\_OPT\_MONDAY\\ TUESDAY & CS\_OPT\_TUESDAY\\ WEDNESDAY & CS\_OPT\_WEDNESDAY\\ THURSDAY & CS\_OPT\_THURSDAY\\ FRIDAY & CS\_OPT\_FRIDAY\\ SATURDAY & CS\_OPT\_SATURDAY\\ \end{tabular} \end{center} \caption{Weekday Option Argument Values}\label{t:wkday} \end{table} The DATEFIRST option\index{DATEFIRST option} accepts an argument Weekday argument. The valid range of values are listed in Table~\ref{t:wkday}. The following example shows how the DATEFIRST option is used: \begin{Example} "DATEFIRST=SUNDAY" \end{Example} \begin{table} \begin{center} \begin{tabular}{ll} Value & Sybase Option\\ \hline MDY & CS\_OPT\_FMTMDY\\ DMY & CS\_OPT\_FMTDMY\\ YMD & CS\_OPT\_FMTYMD\\ YDM & CS\_OPT\_FMTYDM\\ MYD & CS\_OPT\_FMTMYD\\ DYM & CS\_OPT\_FMTDYM\\ \end{tabular} \end{center} \caption{Date Format Argument Values}\label{t:dtfmt} \end{table} One last category of Sybase option arguments is the DATEFORMAT argument\index{DATEFORMAT option} type. The valid list of values for this type of argument are given in Table~\ref{t:dtfmt}. The following is an example of such an option: \begin{Example} "DATEFORMAT=YMD" \end{Example} Table~\ref{t:syonames} lists all of the options that APQ is able to recognize for Sybase. Each of the option names\index{option names} listed is equivalent to the Sybase C macro\index{C macro, Sybase} constant if the prefix CS\_OPT\_\index{CS\_OPT\_{*}} is added to the option name. Consult the Sybase documentation for descriptions of the purpose of these options and when to apply them. \begin{longtable}{lll} Option Name & Data Type & Notes\\ \hline ANSINULL & Boolean &\\ ANSIPERM & Boolean &\\ ARITHABORT & Boolean &\\ ARITHIGNORE & Boolean &\\ AUTHOFF & String &\\ AUTHON & String &\\ CHAINXACTS & Boolean &\\ CHARSET & String/NULL & Use NULL for default\\ CURCLOSEONXACT & Boolean &\\ DATEFIRST & Weekday &\\ DATEFORMAT & YMD/MDY/etc. & May interfere with APQ\\ FIPSFLAG & Boolean &\\ FORCEPLAN & Boolean &\\ FORMATONLY & Boolean &\\ GETDATA & Boolean &\\ IDENTITYOFF & String &\\ IDENTITYON & String &\\ IDENTITYUPD\_OFF & String &\\ IDENTITYUPD\_ON & String &\\ ISOLATION & Unsigned & 0, 1 or 3\\ NATLANG & String/NULL & Use NULL for default\\ NOCOUNT & Boolean &\\ NOEXEC & Boolean &\\ PARSEONLY & Boolean &\\ QUOTED\_IDENT & Boolean &\\ RESTREES & Boolean &\\ ROWCOUNT & Unsigned &\\ SHOWPLAN & Boolean & Use at your own risk\\ STATS\_IO & Boolean &\\ STATS\_TIME & Boolean &\\ STR\_RTRUNC & Boolean &\\ TEXTSIZE & Unsigned &\\ TRUNCIGNORE & Boolean &\\ \caption{Sybase Option Names}\label{t:syonames} \end{longtable} Keep in mind that not all option settings will be compatible for use with APQ. Changing server date formats\index{date formats} to anything other than year-month-day format, is likely to cause problems within APQ, for example. \subsection{Procedure Set\_Notice\_Proc} The PostgreSQL\index{PostgreSQL} database \footnote{The Set\_Notice\_Proc procedure is not available with MySQL.} server sends notice\index{notice messages} messages back to the libpq\index{libpq} C library\index{library}, that the APQ binding uses. These are received by a callback\index{callback}, after certain database operations have been completed. While the messages are saved in the Connection\_Type object (see also \Ref{Function Notice_Message}), they overwrite each other as each new message comes in. For this reason, it may be desireable for some applications to also receive a callback, so that they can process the messages without losing them. The most common reason to do this is to simply display them on standard error\index{standard error}. The callback\index{callback}\index{Set\_Notice\_Proc} procedure must be defined as follows: \marginpar{The default setting for any new Connection\_Type object is No\_Notify.} \begin{Code} procedure Notice_Callback( C : in out Connection_Type; Message : in String ); \end{Code} The Set\_Notice\_Proc takes an argument named Notify\_Proc\index{Notify\_Proc} that is of the following type: \begin{Code} type Notify_Proc_Type is access procedure( C : in out Connection_Type; Message : in String ); \end{Code} Finally, the Set\_Notice\_Proc procedure has the following calling signature: \marginpar{Note that the Reset or Disconnect call will clear any registered Notify procedure.} \begin{Code} procedure Set_Notice_Proc( C : in out Connection_Type; Notify_Proc : in Notify_Proc_Type ); \end{Code} This call can be made at any time to change the Notify\index{notify procedure} procedure. The object may or may not be connected\index{connected}. The new procedure takes effect immediately upon return, and will be used when the object is connected. The present implementation only maintains one such procedure.% \footnote{Note that the replaced procedure is not returned. A future implementation of APQ may address this.% } \subsubsection{Disabling Notify} The APQ\-.PostgreSQL\-.Client\index{APQ\-.PostgreSQL\-.Client} package provides the special constant No\_Notify\index{No\_Notify} for the application programmer to use. An example of disabling notification\index{disabling notification} follows: \begin{Example} declare C : Connection_Type; begin ... -- Enable notify processing Set_Notify_Proc(C,My_Notify'Access); ... -- Disable notification Set_Notify_Proc(C,No_Notify); \end{Example} \subsubsection{Using Standard\_Error\_Notify} During the debugging\index{debugging} phase of a database application, it may be useful to simply have the notice messages\index{notice messages} printed on Standard\_Error\index{Standard\_Error}. To do this, simply provide the access constant Standard\_Error\_Notify\index{Standard\_Error\_Notify} as the second argument: \begin{Example} declare C : Connection_Type; begin ... -- Send notices to stderr Set_Notify_Proc(C,Standard_Error_Notify); ... \end{Example} \section{Connection Operations} The APQ binding provides three primitives for connecting\index{connecting} and disconnecting\index{disconnecting} from the database server. They are summarized in Table~\ref{t:conprims}. \begin{table} \begin{center} \begin{tabular}{lll} Type & Name & Purpose\\ \hline proc & Connect & Connect to the database server\\ proc & Disconnect & Disconnect from the database server\\ proc & Reset & Disconnect if connected\\ \end{tabular} \end{center} \caption{APQ Connection Primitives}\label{t:conprims} \end{table} \subsection{Procedure Connect} This primitive initiates a connection attempt with the database server as configured by the \Ref{Context_Setting_Operations} primitives. If the connection succeeds, the procedure call returns\index{Connect} successfully, leaving the Connection\_Type object in a connected state. \begin{Code} procedure Connect( C : in out Connection_Type ); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & The connection attempt failed\\ Already\_Connected & There is already a connection\\ Failed & One or more configured options failed\\ Use\_Error & Connection OK, but USE database failed\\ \end{tabular} \end{center} \caption{Connect Exceptions}\label{t:conx} \end{table} Table~\ref{t:conx} summarizes the exceptions that Connect may raise. The Already\_Connected\index{Already\_Connected} exception indicates that you need to disconnect first, or use another Connection\_Type object if you are maintaining multiple connections\index{connections, multiple}. Failed will be raised if a pending option setting is unsupported or its setting has been rejected. The exception Use\_Error\index{Use\_Error} indicates that the connection itself succeeded, but the selection of the database failed. The connection will be returned in an unconnected\index{unconnected} state when Use\_Error is raised. \begin{description} \item[PostgreSQL Note:] \index{PostgreSQL}The Connect primitive as of APQ 1.91 automatically executes a 'SET DATESTYLE TO ISO' \index{ISO}\index{DATESTYLE} command to guarantee that the APQ date routines will function correctly, even when the PGDATESTYLE\index{PGDATESTYLE} environment variable may choose something other than ISO. This implies however, that APQ applications should always format date information in the ISO format. \item[MySQL Note:]When MySQL\index{MySQL} returns dates in YYYYMMDD\index{YYYYMMDD} format, APQ will automatically make the necessary adjustment, based upon the length of the result. \end{description} The following is an example call: \begin{Example} declare C : Connection_Type; begin ... begin Connect(C); exception when No_Connection => -- Handle connection failure when Already_Connected => ...; -- Indicates program logic problem when others => raise; end; \end{Example} \subsection{Connection Cloning\label{Connection Cloning}} Application writers may want additional connections cloned\index{cloning connections} from a given connection. A web server may want to do this for example. This could be performed by obtaining all of the connection information from the given connection and then proceed to configure a new connection, but this is tedious and error prone. To clone a new connection from an existing connection, simply use the Connect\index{Connect} primitive with the following calling signature (argument Same\_As is added): \begin{Code} procedure Connect( C : in out Connection_Type; Same_As : in Connection_Type ); \end{Code} This primitive configures object C to use the same parameters as object Same\_As\index{Same\_As}. It then creates a connection to the database using these cloned\index{cloned} parameters. The exceptions that may be raised are listed in Table~\ref{t:cclonx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & The connection attempt failed\\ Already\_Connected & There is already a connection\\ \end{tabular} \end{center} \caption{Connection Cloning Exceptions}\label{t:cclonx} \end{table} The Not\_Connected\index{Not\_Connected} exception can be raised if the Same\_As connection is not connected (it must be connected). This same exception can be raised if the new connection fails (this should rarely happen unless your database is suddenly taken down or a network failure occurs). The Already\_Connected\index{Already\_Connected} exception is raised if \emph{C} is already connected. \begin{description} \item[Note:] Note that the trace settings of the Same\_As object are not carried to the new object C. You must manually configure any trace settings you require in the newly connected object C. \end{description} The following example shows how a procedure My\_Subr can clone a new connection: \begin{Example} procedure My_Subr(C : Connection_Type) is C2 : Connection_Type; begin Connect(C2,C); -- Clone a connection \end{Example} \subsection{Procedure Disconnect} The Disconnect\index{Disconnect} primitive closes the connection that was previously established in the Connection\_Type\index{Connection\_Type} object. The Disconnect primitive uses the following arguments: \begin{Code} procedure Disconnect( C : in out Connection_Type ); \end{Code} The list of possible exceptions for Disconnect are illustrated in Table~\ref{t:dconx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Connection & There is no connection to disconnect\index{No\_Connection}\\ \end{tabular} \end{center} \caption{Disconnect Exceptions}\label{t:dconx} \end{table} The following code fragment shows the procedure call in action: \begin{Example} declare C : Connection_Type; begin ... begin Disconnect(C); exception when No_Connection => ...; -- Indicates program logic problem when others => raise; end; \end{Example} \subsection{Procedure Reset} The Reset\index{Reset} primitive is provided so that the programmer can recycle the Connection\_Type object for use in a subsequent connection. Without this primitive, the user would need to destroy the original and create a new Connection\_Type. The Reset primitive accepts the following arguments: \begin{Code} procedure Reset( C : in out Connection_Type ); \end{Code} In addition to closing the current connection, if it is open, the notification procedure is also deregistered (if there was a Set\_Notify\_Proc\index{Set\_Notify\_Proc} performed). No exceptions should occur. If there is a connection pending\index{pending connection}, it is disconnected\index{disconnected}. If there is no connection pending, the call is ignored. The following shows an example of its use: \begin{Example} declare C : Connection_Type; begin ... Reset(C); -- C is now ready for re-use \end{Example} \section{Connection Information Operations} A modular\index{modular software} piece of software may get handed a Connection\_Type object as a parameter, and have a need to inquire about the details of the provided connection. The function primitives that return information about the connection are listed in Table~\ref{t:cinfp}. \begin{table} \begin{center} \begin{tabular}{ll} Function Name & Information Returned\\ \hline Host\_Name & Host name of the connection\\ Port & Port Number or Port Pathname\\ DB\_Name & Database name\\ User & User name for the database\\ Password & Password for the database\\ Instance & Instance name for the database\\ Options & Database option parameters\\ \end{tabular} \end{center} \caption{Connection Information Primitives}\label{t:cinfp} \end{table} These function primitive specifications are listed below: \begin{Code} function Host_Name( C : Connection_Type; ) return String; \end{Code} \begin{Code} function Port( C : Connection_Type; ) return String; -- UNIX path \end{Code} \begin{Code} function Port( C : Connection_Type; ) return Integer; -- TCP/IP port \end{Code} \begin{Code} function DB_Name( C : Connection_Type; ) return String; \end{Code} \begin{Code} function User( C : Connection_Type; ) return String; \end{Code} \begin{Code} function Password( C : Connection_Type; ) return String; \end{Code} \begin{Code} function Instance( C : Connection_Type; ) return String; \end{Code} \begin{Code} function Options( C : Connection_Type; ) return String; \end{Code} The Port\index{Port} primitive that returns a String is for use with database connections using a UNIX socket\index{UNIX socket}\index{local socket}. The socket pathname\index{pathname} is returned in this case. \footnote{or at least a fragment of the pathname.} When called on Connection\_Type objects without a current connection, an empty string\index{string, empty} is returned for any value that has not been configured (for example if Set\-\_Host\-\_Name\index{Set\_Host\_Name} has not been called, Host\-\_Name\index{Host\_Name} will return ""). If the value has been set, then that value is returned as expected. Once the Connection\-\_Type object is connected to the database however, the values will be values fetched from the library\index{library} libpq\index{libpq} instead. \footnote{Normally, these values should agree with what was configured.} The following code sample shows how to extract the host name\index{host name} and database name for the current connection. \begin{Example} procedure My_Code(C : in out Connection_Type) is Host_Name : String := Host_Name(C); Database_Name : String := DB_Name(C); begin ... \end{Example} \begin{description} \item [Sybase Note:]The Instance function primitive was added to APQ support Sybase. See the support level chart for Set\_Instance\index{Set\_Instance} on page \pageref{Set_Instance Support Chart} and other information primitives. Note also that setting and retrieving other parameters is possible in some cases, even though the information is ignored by Sybase. \end{description} \section{General Information Operations} Due to the modular construction of software, it is sometimes necessary to query an object for its present state. The primitives listed in Table~\ref{t:gifc} for the Connection\_Type object are available for querying the state\index{query the state} of the object. These are discussed in the next subsections. \begin{table} \begin{center} \begin{tabular}{lll} Type & Name & Purpose\\ \hline func & Is\_Connected & Indicates connected state\\ func & Error\_Message & Returns a error message text\\ \end{tabular} \end{center} \caption{General Information for Connections}\label{t:gifc} \end{table} \subsection{Function Is\_Connected} The Is\_Connected\index{Is\_Connected} function returns a Boolean result that indicates the present state of the Connection\_Type object. The arguments are as follows: \begin{Code} function Is_Connected( C : Connection_Type ) return Boolean; \end{Code} There are no exceptions raised by this primitive. The following example shows how to test if the object C is currently supporting a connection. The example disconnects from the server, if it determines that C is connected. \begin{Example} declare C : Connection_Type; begin ... if Is_Connected(C) then Disconnect(C); ... \end{Example} \subsection{Function Error\_Message} The Error\_Message\index{Error\_Message} function makes it possible for the application to report why the connection failed. This information is often crucial to the user of a failed application. The arguments accepted are as follows: \begin{Code} function Error_Message( C : Connection_Type ) return String; \end{Code} There are no exceptions raised by this function. If there is no present connection or no present error to report, the null string is returned. The following example shows how the connection failure is reported: \begin{Example} with Ada.Text_IO; ... declare use Ada.Text_IO; C : Connection_Type; begin ... begin Connect(C); exception when No_Connection => Put_Line(Standard_Error,"Connection Failed!"); Put_Line(Standard_Error,Error_Message(C)); ... when Already_Connected => ...; -- Program logic error here when others => raise; end; \end{Example} \subsection{Function Notice\_Message\label{Function Notice_Message}} The C libpq\index{libpq} interface library\index{library}\footnote{The Notice\_Message function is not available for MySQL.} provides the APQ binding with certain notification messages\index{notification messages} during some calls, by means of a callback\index{callback}. Each time one of these notifications is received from the database server, the notification message is saved in the Connection\_Type object (replacing any former notice message). The last notification message received can be retreived using the Notice\_Message\index{Notice\_Message} function: \begin{Code} function Notice_Message( C : Connection_Type ) return String; \end{Code} No exception is raised, and the null string\index{null string} is returned if no notice message has been registered. The following example illustrates one example of the Notice\_Message function: \begin{Example} with Ada.Text_IO; ... declare use Ada.Text_IO; C : Connection_Type; begin ... declare Msg : String := Notice_Message(C); begin if Msg'Length > 0 then Put_Line(Standard_Error,Msg); ... \end{Example} \subsection{In\_Abort\_State Function\label{In_Abort_State Function}} \Ref{Abort_State exception} documents the Abort\_State\index{Abort\_State} exception, which is unique to PostgreSQL\index{PostgreSQL}. This exception is raised in response to a status flag stored in the APQ\-.PostgreSQL\-.Client\-.Connection\_Type object. When a transaction is started, any SQL error\index{SQL error} will put the PostgreSQL database server into an ``\emph{abort state}'', where all current and future commands will be ignored, for the connection \footnote{MySQL does not support this concept, and so it does not go into an abort state.}. To permit the application programmer to query this status, the In\_Abort\_State\index{In\_Abort\_State} function can be used. It returns True, if an error has occurred within a transaction, which requires a Rollback\_Work (\Ref{Begin, Commit and Rollback Work functions}) call to clear this state. The calling requirements are summarized in the following table: \begin{Code} function In_Abort_State( C : Connection_Type ) return Boolean; \end{Code} Exceptions for In\_Abort\_State are summarized in Table~\ref{t:iasx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & There is no connection to query\\ \end{tabular} \end{center} \caption{In\_Abort\_State Exceptions}\label{t:iasx} \end{table} The following example shows how this function might be used: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Begin_Work(Q,C); ... Execute(Q,C); ... if In_Abort_State(C) then Rollback(Q,C); ... end if; \end{Example} \section{Implicit Operations} There are a few implicit operations\index{implicit operations} that are performed that the programmer should be aware of. They are: \begin{itemize} \item The Connection\_Type is subject to Finalization \item A default Commit/Rollback operation can occur at Finalization \end{itemize} The programmer is encouraged to call Commit\_Work\index{Commit\_Work} or Rollback\_Work\index{Rollback\_Work} explicitly, whenever possible. This way, the programmer is in complete control of the transaction outcome. If a transaction has not been committed or rolled back, and the connected Connection\_Type object is finalized\index{finalization}% \footnote{Usually because the Connection\_Type object has fallen out of scope.% }, then the default action for commit or rollback occurs. The default for the APQ binding is to rollback the transaction, when the connection is still active. If the programmer has disconnected\index{disconnected} from the database prior to finalization, then no further action occurs. To change or control the default action, use the Set\_Rollback\_On\_Finalize\index{Set\_Rollback\_On\_Finalize} procedure described in the next section. \subsection{Set\_Rollback\_On\_Finalize Procedure\label{Set_Rollback_On_Finalize Procedure}} The Set\_Rollback\_On\_Finalize primitive allows the programmer to change the default action for the Connection\_Type object. The calling requirements are summarized in the following table:% \begin{Code} procedure Set_Rollback_On_Finalize( C : in out Connection_Type; Rollback : in Boolean ); \end{Code} To change the default to COMMIT WORK\index{COMMIT WORK} when the Connection\_Type object finalizes, peform the following call: \begin{Example} declare C : Connection_Type; begin Set_Rollback_On_Finalize(C,False); -- Commit on Finalize \end{Example} \subsection{Will\_Rollback\_On\_Finalize Function\label{Will_Rollback_On_Finalize Function}} Programs sometimes need to inquire about the state of the Connection\_Type object that they may have been passed. To inquire about the commit or rollback default, the Will\_Rollback\_On\_Finalize\index{Will\_Rollback\_On\_Finalize} function can be called. The following table summarizes the calling requirements: \begin{Code} function Will_Rollback_On_Finalize( C : Connection_Type ) return Boolean; \end{Code} \section{Trace Facilities\label{Trace Facilities}} No matter how carefully a programmer writes a new program, problems develop that are often difficult to understand. Good tracing facilities\index{trace facilities} allow the problem to be quickly understood and corrected. To gain trace support using APQ, it is only necessary to perform the following steps: \begin{enumerate} \item Open a trace capture file with Open\_DB\_Trace \item Optionally enable/disable tracing at various points in the program with Set\_Trace% \footnote{Tracing is enabled by default after a Open\_DB\_Trace call.} \item Perform your SQL operations \item Close the trace capture file with Close\_DB\_Trace% \footnote{Or allow it to be closed when the Connection\_Type object is finalized.} \end{enumerate} The Open\_DB\_Trace\index{Open\_DB\_Trace} procedure takes a Trace\_Mode\_Type\index{Trace\_Mode\_Type} parameter that decides what trace content is being collected. The valid enumerated choices are listed in Table~\ref{t:tmchoic}. \begin{table} \begin{center} \begin{tabular}{ll} Value & Description\\ \hline APQ.Trace\_None & Collect no trace information (no file is written/created)\\ APQ.Trace\_DB & Collect only C library trace information% \footnote{Prior to APQ 2.0, this was Trace\_libpq.}\\ APQ.Trace\_APQ & Collect only APQ SQL trace information\\ APQ.Trace\_Full & Collect both database library and Trace\_APQ information\\ \end{tabular} \end{center} \caption{Trace\_Mode\_Type Choices}\label{t:tmchoic} \end{table} The Trace\_None\index{Trace\_None} value is provided so that the Open\_DB\_Trace procedure does not need to be coded around if a trace variable is supplied, which may or may not request tracing. Close\_DB\_Trace\index{Close\_DB\_Trace} can be called on a Connection\_Type\index{Connection\_Type} for which Trace\_None is in effect, without any exception being thrown (the call is ignored). Trace\_DB\index{Trace\_DB} provides only what the C library (libpq\index{libpq} for PostgreSQL\index{PostgreSQL}) provides. This may be useful to the database software maintainers, if they want a trace of the activity that you are reporting problems with. Trace\_APQ\index{Trace\_APQ} is what the author considers to be the most useful output format to an APQ developer. The trace output in this mode is such that the extra trace information is provided in SQL comment\index{SQL comment} form. The actual queries that are executed are in their natural SQL form. The captured Trace\_APQ trace then, is in a format that can be played back, reproducing exactly what the application performed.% \footnote{There are limitations however, since the blob functions are not traced at the present release.% } The full trace or portions of it then can be used to help debug SQL related problems. The following shows a sample of what the Trace\_APQ output looks like: \begin{SQL} -- Start of Trace, Mode=TRACE_APQ -- SQL QUERY: BEGIN~WORK} ; -- Result: 'BEGIN' -- SQL QUERY: INSERT INTO DOCUMENT (NAME,DOCDATE,BLOBID,CREATED,MODIFIED,ACCESSED) VALUES ('compile.adb','2002-08-12~21:09:25',3339004, '2002-08-12~21:59:48','2002-08-12~21:09:25', '2002-08-19~22:11:36') ; -- Result: 'INSERT 3339005 1' -- SQL QUERY: SELECT DOCID FROM DOCUMENT WHERE OID = 3339005 ; -- Result: 'SELECT' ... -- SQL QUERY: COMMIT WORK ; -- Result: 'COMMIT' -- End of Trace. \end{SQL} The following subsections describe the primitives that provide support for trace facilities. \subsection{Procedure Open\_DB\_Trace} To start any capture of trace\index{trace capture} information, you must specify the name of the text file to be written to. The file must be writable to the current process. The Connection\_Type object must be connected prior to calling Open\_DB\_Trace\index{Open\_DB\_Trace}: \begin{Code} procedure Open_DB_Trace( C : in out Connection_Type; Filename : in String; Mode : in Trace_Mode_Type := Trace_APQ ); \end{Code} Table \ref{t:odbtx} lists the possible exceptions for Open\_DB\_Trace. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & There is no connection\\ Tracing\_State & Trace is already enabled\\ \end{tabular} \end{center} \caption{Open\_DB\_Trace Exceptions}\label{t:odbtx} \end{table} Upon return from the Open\_DB\_Trace procedure, a text file will be created and ready to have trace entries written to it.% \footnote{Note that trace entries are buffered by C standard I/O routines, so trace information may be held in memory buffers before it is flushed out or closed.% } The following example shows how a call might be coded: \begin{Example} declare C : Connection_Type; begin ... Open_DB_Trace(C,"./bugs.sql",Trace_APQ); \end{Example} \subsection{Procedure Close\_DB\_Trace} Closing the tracing facility for a connection, suspends all further trace writes. Once this has been done, the effect of Set\_Trace\index{Set\_Trace} is superceeded, preventing any further trace information being written. The calling requirements are outlined in the following table: \begin{Code} procedure Close_DB_Trace( C : in out Connection_Type ); \end{Code} If the Open\_DB\_Trace call was made with the Mode parameter set to Trace\_None, then the call to Close\_DB\_Trace\index{Close\_DB\_Trace} has no effect and is ignored for programmer convenience. No exceptions are raised. An example call is shown below: \begin{Example} declare C : Connection_Type; begin ... Open_DB_Trace(C,"./bugs.sql",Trace_APQ); ... Close_DB_Trace(C); \end{Example} \subsection{Procedure Set\_Trace} In large applications where large numbers of SQL statements are executed, it may be desirable to trace only certain parts of its execution in a dynamic fashion. The Set\_Trace\index{Set\_Trace} primitive gives the programmer a way to disable and re-enable tracing at strategic\index{strategic tracing} points within the application. The calling requirements are summarized as follows: \begin{Code} procedure Set_Trace( C : in out Connection_Type; Trace_On : in Boolean := True ); \end{Code} Tracing is enabled by default, after a successful call to Open\_DB\_Trace is made (unless Mode was Trace\_None\index{Trace\_None}). There are no exceptions raised. Note that it is considered safe to invoke Set\_Trace, even if a former Open\_DB\_Trace call was not successfully performed, or the trace mode was Trace\_None. This allows the application to retain strategic Set\_Trace calls without having to remove them, when the Open\_DB\_Trace call is disabled% \footnote{Setting Mode to Trace\_None effectively disables the trace facility without requiring any code changes.% } or commented out. \subsection{Function Is\_Trace} It may be helpful to the developer that is tracking down a problem to know when tracing is enabled or not. The Is\_Trace\index{Is\_Trace} function returns true when the trace collection file is receiving trace information. The calling arguments are listed below:% Note that the returned value tracks the last value provided by Set\_Trace, whether or not an open trace file has been created/opened. \begin{Code} function Is_Trace( C : Connection_Type; ) return Boolean; \end{Code} Note that the initial state of the Connection\_Type object is to have Is\_Trace to return True. Also after a successful Open\_DB\_Trace, Is\_Trace will return True. An example showing its use is given below: \begin{Example} declare C : Connection_Type; begin ... Open_DB_Trace(C,"./bugs.sql",Trace_APQ); ... if Is_Trace(C) then -- We are collecting trace info.. \end{Example} \section{Generic Database Operations} APQ 2.0 and later is designed so that all but the most specialized database operations, can be performed, given only a Root\_Connection\_Type'Class\index{Root\_Connection\_Type'Class} object (declared in top level package APQ). The following sections describe some generic database related primitives that are necessary for successful generic database support. \subsection{Package APQ} Root object support\index{root object support} is provided in the package APQ\index{APQ, package}. Generic database code will normally only use this package: \begin{Code} with APQ; use APQ; -- Optional use clause \end{Code} The data types that will be used will be: \begin{itemize} \item APQ.Root\_Connection\_Type'Class \item APQ.Root\_Query\_Type'Class\index{Root\_Query\_Type'Class} \end{itemize} The generic primitives that will be covered in the next section are: \begin{itemize} \item APQ.Engine\_Of \item APQ.New\_Query \end{itemize} \subsection{Predicate Engine\_Of\label{Generic Database Engine_Of}} Given a Root\_Connection\_Type'Class object, generic database code sometimes needs to determine which specific database is being used. This allows the code to make special SQL syntax changes, depending upon the technology being used (for example, MySQL\index{MySQL} permits the use of a \emph{LIMIT}\index{LIMIT} keyword in queries). The Engine\_Of\index{Engine\_Of} primitive (dispatching) will identify the database technology that is being used: \begin{Code} type Database_Type is ( Engine_PostgreSQL, Engine_MySQL, Engine_Sybase ); function Engine_Of( C : Connection_Type ) return Database_Type; \end{Code} The following example code shows how to test if a PostgreSQL\index{PostgreSQL} database is being used: \begin{Example} with APQ; use APQ; ... procedure App(C : Root_Connection_Type'Class) is begin ... if Engine_Of(C) = Engine_PostgreSQL then ... \end{Example} \subsection{Primitive New\_Query\label{Query_Type Factories}} Normally, an application database procedure will receive a connection object as one of its input parameters. Generally, this connection is established in the main program and then used by the program components as required. However, to pass the parameter in a generic way (allowing for polymorphism), you would declare the procedure's argument as receiving data type Root\_Connection\_Type'Class. Within the called procedure however, you will need a Query\_Type object. This too could be passed in as an argument, but this is unnecessary. At other times, you may need additional Query\_Type objects for temporary use. What you need is a convenient way to create a Query\_Type object that matches the connection that you have received as a parameter. This is done by the New\_Query function\index{New\_Query}. If your connection object is a: \begin{Code} APQ.PostgreSQL.Client.Connection_Type \end{Code} object, then your application will want to create a: \begin{Code} APQ.PostgreSQL.Client.Query_Type \end{Code} object. You want to avoid tests like: \begin{Example} if Connection is in APQ.PostgreSQL.Client.Connection_Type then ... elsif Connection is in APQ.MySQL.Client.Connection_Type then ... elsif Connection is in APQ.Sybase.Client.Connection_Type then ... \end{Example} The above example code would force your portable code to also ``with''\index{with} the following packages: \begin{Example} with APQ.PostgreSQL.Client; with APQ.MySQL.Client; ... \end{Example} which would be very inconvenient and unnecessary. To make portable\index{portable} database programming easier, APQ provides a dispatching\index{dispatching} Query\_Type object factory primitive that can be used for this purpose. For example: \begin{NumberedExample} with APQ; use APQ; procedure My_Generic_App(C : Root_Connection_Type'Class) is Q : Root_Query_Type'Class := New_Query(C);(*@\label{Ex:New_Query_Assgn}@*) begin Prepare(Q,"SELECT NAME,INCOME"); Append_Line(Q,"FROM~SALARIES"); \end{NumberedExample} The assignment to Q in line~\ref{Ex:New_Query_Assgn}, shows the application of the primitive New\_Query. This dispatching primitive returns the correct Query\_Type object that matches the connection that was given. The primitive New\_Query is more formally presented as follows: \begin{Code} function New_Query( C : Root_Connection_Type ) return Root_Query_Type'Class; \end{Code} \subsection{Query\_Type Assignment\label{Query_Type Cloning}} Prior to APQ version 2.0, the Query\_Type object was a \emph{limited}\index{limited tagged type} tagged type. This meant that the Query\_Type object was never able to be assigned to another Query\_Type object. With the need for a factory\index{factory} primitive like \textbf{New\_Query} it was necessary to lift that restriction (otherwise the factory was unable to return the created object). So the Root\_Query\_Type and derived forms, permit assignment as of APQ version 2.0 and later. When a Query\_Type is assigned in APQ, nothing spectacular happens. In fact, the contents of the object on the right hand side are effectively ignored, leaving a new object on the left side. The following example shows how Q1 and Q2 are essentially the same: \begin{NumberedExample} declare Q0 : Query_Type; Q1 : Query_Type; Q2 : Query_Type; begin ... Q1 := Q0; -- Q1 becomes initialized (Q0 ignored)(*@\label{Ex:Q1}@*) Clear(Q2); -- Initialize Q2(*@\label{Ex:Q2}@*) \end{NumberedExample} In this example, both Q1~(line~\ref{Ex:Q1}) and Q2~(line~\ref{Ex:Q2}) end up in the same state, and no state information is taken from Q0. You might wonder why this would be implemented. The following example code fragment illustrates why this is convenient and useful: \begin{NumberedExample} with APQ; usse APQ; procedure My_Generic_App(C : Root_Connection_Type'Class) is Q : Root_Query_Type'Class := New_Query(C); begin Prepare(Q,"SELECT NAME, INCOME"); Append(Q, "FROM~SALARIES"); Execute(Q,C); ... declare Q2 : Root_Query_Type'Class := Q;(*@\label{Ex:Q_Clone}@*) begin ... end; \end{NumberedExample} The example illustrates that the assignment (line~\ref{Ex:Q_Clone}) is simply a convenient factory of its own kind. It is also likely to be slightly more efficient than the New\_Query primitive on the connection. Think of assignment of Query\_Type objects as cloning\index{cloning} operations. The assigned object becomes a fresh initialized clone of the Query\_Type object on the right hand side of the assignment. \chapter{SQL Query Support} Once a database connection has been established, the application is ready to invoke operations on the database server. To ease the programmer's burden in keeping track of the various components involved in these transactions, the Query\_Type object is provided. The Query\_Type\index{Query\_Type} object and the Connection\_Type object are used together when it comes time to execute the query. Some operations require the connection object, while others do not. There are a large number of primitives associated with the Query\_Type object. Most of them are related to the large number of data types that are supported. These Query\_Type primitives fall into the following basic categories: \begin{enumerate} \item Object initialization \item SQL Query building \item SQL Execution on the Database server \item Transaction operations \item Fetch operations \item Column information functions \item Value fetching functions \item Value and Indicator fetching procedures \item Information operations \end{enumerate} In addition to these, are a number of generic functions and procedures that permit the APQ user to custom tailor the API to his own specialized Ada data types. This allows applications to continue the follow the healthy tradition of using strong data types. There is no need for a database application to take a back seat to safety\index{safety}. \section{Initialization \label{SQL Initialization}} The Query\_Type object is initialized when the object is created. However, the Query\-\_Type object can be re-used as various SQL\index{SQL} operations are performed by the program. To re-use the Query\_Type object, one of the primitives in Table~\ref{t:qinit} may be used to recycle it for re-use. \begin{table} \begin{center} \begin{tabular}{lll} Type & Name & Purpose\\ \hline proc & Clear & Clear object and re-initialize\\ proc & Prepare & Reinitialize with start of new SQL query\\ \end{tabular} \end{center} \caption{Query Initialization}\label{t:qinit} \end{table} The Clear\index{Clear} procedure does the initialization of the Query\_Type object. The Prepare primitive implicitly invokes Clear \footnote{Consequently, your application need not invoke Clear() prior to calling Prepare().} and additionally starts the building of an SQL query. Very short SQL statements may comletely specified by the Prepare API call. Longer queries can be completed with some of the other primitives to be discussed in this section. \subsection{Procedure Clear} With one exception, the Clear\index{Clear} primitive completely resets the state of the Query\_Type object. This function primitive serves to basic purposes: \begin{enumerate} \item Resets the object to its initial state so that it can be reused for a new query. \item Releases any results of the current query (close cursors etc.) \end{enumerate} When performed after a query has been executed, this primitive releases all results from the query. For Sybase, this can include issuing a cancel back to the server and flushing all pending row results that have not been retrieved by the APQ client program. Clear accepts the Query\_Type object as its only argument: \begin{Code} procedure Clear( Q : in out Query_Type ); \end{Code} The one exception to clearing state however, is that the SQL case\index{case policy} policy remains unchanged. If prior to the clear, the SQL case policy is set to Preserve\_Case\index{Preserve\_Case}, it will remain so after the Clear call. There are no exceptions raised by this call. The use of the Clear primitive is recommended after all SQL processing related to the query has been completed. This permits any database server results to be released. Think of it as ``closing''\index{closing a query} the query. Note however, that object finalization\index{finalization} will take care of this, if the job is left unfinished by the programmer. The following example illustrates it's use: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Clear(Q); \end{Example} \subsubsection{Performance Issue} There is one particular case where calling Clear is vitally important for some database products. Let's use an example where you are fetching the most recent stock price from a price history file. Here is the table declaration: \begin{SQL} CREATE TABLE PRICE_HIST ( SECURITY CHAR(10) NOT NULL, PRICE_DATE DATE NOT NULL, PRICE REAL, PRIMARY KEY (SECURITY,PRICE_DATE) ); \end{SQL} With this table holding price history, keyed by the security name and date, we can lookup the most recent price with a subroutine something like the following: \begin{NumberedExample} procedure Last_Price( C : in out Root_Connection_Type'Class; Security : in String; Price : out APQ_Double ) is function Value is new Float_Value(APQ_Double); Q : Root_Query_Type'Class := New_Query(C);(*@\label{Ex:TheQ}@*) begin Begin_Work(Q,C); Prepare(Q, "SELECT SECURITY,PRICE_DATE,PRICE"); Append_Line(Q,"FROM PRICE_HIST"); Append(Q, "WHERE SECURITY = "); Append_Quoted(Q,C,Security,Line_Feed); Append_Line(Q,"ORDER BY SECURITY,PRICE_DATE DESC");(*@\label{Ex:OrderBy}@*) if Engine_Of(C) = Engine_MySQL then Append_Line(Q,"LIMIT 1");(*@\label{Ex:Limit1}@*) end if; Execute(Q,C); begin Fetch(Q); exception when No_Tuple => raise; -- No price found! end; Price := Value(Q,3); Clear(Q);\label{Ex:Clear} end Last_Price; \end{NumberedExample} In this example, you can see that MySQL\index{MySQL} is covered by adding the "LIMIT 1"\index{LIMIT} clause in line~\ref{Ex:Limit1}.\footnote{MySQL will limit the results to 1 row, if any.} PostgreSQL\index{PostgreSQL} does not have a problem with this type of query because each row is fetched on demand. Sybase\index{Sybase} however, will start returning all the rows that it has available, in the order specified by the "ORDER BY"\index{ORDER BY} clause (line~\ref{Ex:OrderBy}). Given that the routine Last\_Price only calls Fetch\index{Fetch} once, there is no point in the Sybase server producing and sending more row data down the connection to the APQ client program. For this reason, a call to Clear\index{Clear} (line~\ref{Ex:Clear}) will send a cancel notice to the Sybase server to stop producing additional rows. It will also clear out any row data on the connection that has not been fetched by the client program. In this particular example, the Query\_Type object Q (line~\ref{Ex:TheQ}) would have been finalized\index{finalized} anyway upon return from Last\_Price. Finalized Query\_Type objects always perform the equivalent of a call to Clear prior to releasing the object storage. However, it is important to explicitly call Clear\index{Clear} if you have many other operations that follow the query performed in order to allow a timely cancel if necessary and to release any pending query results. \subsection{Procedure Prepare\label{Procedure Prepare}} The Prepare\index{Prepare} primitive goes one step further than Clear in that it readies the object for the start of an SQL\index{SQL} statement build. If the query is short, this will be the only building step required. As in the case of Clear, the SQL case policy\index{case policy} is unchanged however. The Prepare procedure takes the following arguments: \begin{Code} procedure Prepare( Q : in out Query_Type; SQL : in String; After : in String := Line_Feed ); \end{Code} The SQL argument defines the start of your SQL\index{SQL} statement. The After argument may supply either the default (line feed)\index{line feed} or some other text to append to the SQL text\index{SQL text}. It is provided as a programmer convenience, since many times the programmer will need to append a comma for example. There are no exceptions raised by this call. The following code shows an example of building a query to drop a table: \begin{Example} declare Q : Query_Type; begin ... Prepare(Q,"DROP TABLE DEAD_WEIGHT"); \end{Example} \section{SQL Query Building \label{SQL Query Building}} The previous section primitives ``cleared'' the Query\_Type for a new query. The primitives provided in this section help to build a new SQL query or to continue (append to)\index{append} the one started by the Prepare call in \Ref{Procedure Prepare}. The programmer may start\index{start} with a Prepare call and follow it by a number of ``append'' calls, or call Clear and build upon an empty query\index{empty query} and skip the Prepare. ``PREPARE''\index{PREPARE} however, is a traditional first step in embedded SQL\index{embedded SQL} software, so this tradition comes recommended by the author. There are two broad categories of support for creating SQL queries\index{SQL queries}. They are: \begin{enumerate} \item Append\index{Append} a value to the SQL query \item Encode\index{Encode} a value or NULL\index{NULL}, to the SQL query. \end{enumerate} Both of these categories append to the current query. Primitives in category 2 , are prefixed with Encode and will be described later in the present chapter. The Append category of support is useful for values that are never \emph{NULL} (in SQL terms these columns that are declared as ``NOT NULL''\index{NOT NULL}). The Encode category of support is provided for values in your application that may be in the NULL\index{NULL} state. It is not absolutely required that the Encode support be used, since it is possible for the application to test for a NULL value. However, the programmer will find that the Encode support provides application coding convenience and economy of expression. With compact code, better readability\index{readability} and safety\index{safety} is normally obtained. Within category 1, there are five groups of primitives% \footnote{The generic procedures have been lumped in with the primitives.% } that build on the present query. They are: \begin{enumerate} \item Append a string \item Append a string and a \emph{{}``newline''} \item Append a quoted string% \footnote{Quoted values are always spared from any automatic case conversions, if any are applied.} \item Append non string types \item Append using generic procedures for custom types \end{enumerate} Encode\index{Encode} support on the other hand, only provides for the needs of variables that must be communicated to the database server. As a result, the encode procedures consist only of the following two groups: \begin{enumerate} \item Encode non-string\index{non-string types} types \item Encode using generic procedures for custom types\index{custom types} \end{enumerate} Presently only the second group is provided for by the APQ binding.% \footnote{The reasoning is that most of the time, the user will want to instantiate the generic procedures anyway. This permits both the data type and the null indicator\index{null indicator} type to be a custom application type.% } A future release may expand on category 1 support. The append procedures (category 1) will be described first and then followed by the encode procedures (category 2). \subsection{Append SQL String} The Append\index{Append} procedure permits the programmer to append text to the SQL query being saved in the Query\_Type object. Unlike Prepare\index{Prepare}, Append does not clear the object. Append continues to add SQL text\index{SQL text} to the query already gathered by the object Q (below): \begin{Code} procedure Append( Q : in out Query_Type; SQL : in String; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; SQL : in Ada.Strings.Unbounded.Unbounded_String; After : in String := "" ); \end{Code} There are no exceptions raised by this call. The following example shows how Append is used: \begin{Example} declare Q : Query_Type; begin ... Prepare(Q,"SELECT CUSTNO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); \end{Example} Note that the Prepare\index{Prepare} call uses a default argument After=New\_Line\index{After}\index{New\_Line}, while Append uses a null string\index{null string} default. You can put a line break in the SQL query by supplying the value New\_Line in the argument "After" if you like. The following example illustrates the use of Prepare and Append: \begin{Example} declare Q : Query_Type; Col_Name_1 : constant String := "CUSTNO"; Col_Name_2 : constant String := "CUST_NAME"; begin ... Prepare(Q,"SELECT "); Append(Q,Col_Name_1,","); Append(Q,Col_Name_2,Line_Feed); Append(Q,"FROM CUSTOMER"); \end{Example} This example builds up the same query that the previous example did, except that the column names were provided by string variables\index{string variables}. \subsection{Append SQL Line\label{Append SQL Line}} The Append\_Line\index{Append\_Line} procedure is provided for added convenience and program readability\index{readability}. The same effect can be had with a string Append call, using string APQ.Line\_Feed supplied as the After\index{After} argument. The Append\_Line procedure has the following specification: \begin{Code} procedure Append_Line( Q : in out Query_Type; SQL : in String; ); \end{Code} The Append\_Line procedure is one of the few that does not sport an \emph{After} argument. \subsection{Append Quoted SQL String} Don't quote\index{quoted strings} your own strings at home. There are several reasons why supplying your own quotes to a call to the normal Append call is a bad idea: \begin{enumerate} \item Some characters must be encoded\index{encoded} or escaped\index{escaped}, if they occur in the string. \item SQL portability\index{portability} is enhanced, since encoding and escaping\index{escaping} varies from database vendor to vendor. \item Internationalization\index{Internationalization} chosen by the user may require different processing. \item Quoted\index{quoted strings} strings should not be changed to upper or lowercase\index{lowercase} (by APQ). \end{enumerate} The Append\_Quoted\index{Append\_Quoted} procedure call is designed to make it easier for the programmer to supply a string value that may contain special characters within it. Since a string value is already supplied by APQ with outer\index{outer quotes} quotes, any quote\index{quote} appearing within the string must be quoted. The Append\_Quoted procedure provides the necessary outer quotes\index{quotes} for the sring value and escapes\index{escapes} any special characters\index{special characters} occuring within it as well. Another very important reason for using this API call for quoted strings is that this will prevent the APQ library from changing the case of\index{case of SQL} any SQL text that is created. This is true no matter what the current SQL case policy\index{case policy} is (see type APQ\-.SQL\-\_Case\-\_Type on page \pageref{SQL_Case_Type Choices}). Any string segment\index{string segment} that was added to the query with this API call will not have its case changed when the query is executed or the text of the SQL is returned in a call to the To\_String\index{To\_String} function. There are two Append\_Quoted procedures, which differ only in the data type of the \emph{SQL} argument: \begin{Code} procedure Append_Quoted( Q : in out Query_Type; Connection : in out Root_Connection_Type'Class; SQL : in String; After : in String := "" ); \end{Code} \begin{Code} procedure Append_Quoted( Q : in out Query_Type; Connection : in out Root_Connection_Type'Class; SQL : in Ada.Strings.Unbounded.Unbounded_String; After : in String := "" ); \end{Code} Notice that this particular API call requires a connection\index{connection}. The reason for this is that some databases require the server to make the appropriate choices dealing with internationalized\index{internationalized} character sets\index{character sets}. The quoting\index{quoting} conventions also vary from database to database, so APQ relies upon the database vendor software to perform the quoting for you. The following example illustrates the use of this call (using the String type): \begin{Example} declare C : Connection_Type; Q : Query_Type; Freds_Emporium : String := "Fred's Emporium"; begin ... Prepare(Q, "SELECT COMPNO,COMPANY_NAME"); Append_Line(Q,"FROM SUPPLIER"); Append(Q, "WHERE COMPANY_NAME = "); Append_Quoted(Q,C,Freds_Emporium,New_Line); \end{Example} The effect of these calls is to build an SQL query\index{SQL} that looks as follows (for PostgreSQL\index{PostgreSQL}): \begin{SQL} SELECT COMPNO,COMPANY_NAME FROM SUPPLIER WHERE COMPANY_NAME = 'Fred\'s Emporium' \end{SQL} Notice how the quote character was escaped for use by the PostgreSQL\index{PostgreSQL} database server. Note also that even though the SQL case policy\index{case policy} was to use Upper\_Case\index{Upper\_Case}, the case of the quoted text was preserved. APQ will automatically adjust the quoting conventions\index{quoting conventions} to match the database being used. The same example above when used for Sybase\index{Sybase}, would produce the following SQL text\index{SQL text} instead: \begin{SQL} SELECT COMPNO,COMPANY_NAME FROM SUPPLIER WHERE COMPANY_NAME = 'Fred''s Emporium' \end{SQL} Sybase uses a doubled-up quote\index{doubled-up quote} instead. Using APQ's Append\_Quoted frees the programmer from worrying about quoting conventions and guarantees that the case of the text will be preserved. \subsection{Append Non-String Types to SQL Query} A fairly large set of builtin non-string\index{non-string types} data types are supported by varied Append calls that differ in the second argument V. The following is a list of their specifications: \begin{Code} procedure Append( Q : in out Query_Type; V : in APQ_Boolean; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; V : in APQ_Date; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; V : in APQ_Time; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; V : in APQ_Timestamp; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; V : in APQ_Bitstring; After : in String := "" ); \end{Code} \begin{Code} procedure Append( Q : in out Query_Type; V : in Row_ID_Type; After : in String := "" ); \end{Code} These Append\index{Append} procedure calls automatically convert\index{convert} the supplied data type in argument V, internally into a string\index{string} using the To\_String\index{To\_String} function appropriate to the data type. Internally, the string Append procedure is then utilized to perform the remaining work. The following example illustrates their use: \begin{Example} declare Q : Query_Type; Ship_Date : APQ_Date; begin ... Prepare(Q, "SELECT COMPNO,COMPANY_NAME,SHIP_DATE"); Append_Line(Q,"FROM SUPPLIER"); Append(Q, "WHERE SHIP_DATE = "); Append(Q,Ship_Date,New_Line); \end{Example} The example presented builds an SQL query that looks like this: \begin{SQL} SELECT COMPNO,COMPANY_NAME,SHIP_DATE FROM SUPPLIER WHERE SHIP_DATE = '2002-07-21' \end{SQL} Notice that the Append call for APQ\_Date\index{APQ\_Date} automatically supplies the necessary quotes to the SQL query\index{SQL query} (if needed for the database being used). All of the data types supported are molded into a format that is acceptable in the native database SQL syntax\index{SQL syntax}. \\ APQ used to include the APQ\_Timezone data type. When it was updated to Ada 2005 this type was removed. Now APQ date and time types work as follows \begin{description} \item[APQ\_Date] date only, in local timezone \item[APQ\_Hour] \emph{Day\_Duration} type has no timestamp information; thus it's assumed local timezone as well \item[APQ\_Timestamp] it's converted to/from UTC when talking to the database; The \emph{Ada.Calendar.Formatting} package is used for the conversion tasks \end{description} \subsection{Generic Append SQL Procedures} Ada programmers often take advantage of the strong typing \index{strong typing}that is available in the language. To accomodate this programming aspect, generic procedures are available so that type conversions\index{type conversions} are unnecessary. The following table documents the generic procedures that accept one generic argument named Val\_Type and the data types that they support: \begin{Code} generic type Val_Type is new Boolean; procedure Append_Boolean( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is range <>; procedure Append_Integer( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is mod <>; procedure Append_Modular( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is digits <>; procedure Append_Float( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is delta <>; procedure Append_Fixed( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is delta <> digits <>; procedure Append_Decimal( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; procedure Append_Date( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Day_Duration; procedure Append_Time( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Timestamp; procedure Append_Timestamp( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Bitstring; procedure Append_Bitstring( Q : in out Root_Query_Type'Class; V : in Val_Type; After : in String := "" ); \end{Code} Each of the resulting instantiated procedures provide the following calling signature: \begin{Code} procedure Append( Q : in out Query_Type; V : in Val_Type; After : in String := "" ); \end{Code} The following code fragment illustrates how these are instantiated\index{instantiated} and used: \begin{NumberedExample} declare type Price_Type is delta 0.01 digits 12;(*@\label{Ex:TypeDef}@*) procedure Append is new Append_Decimal(Price_Type);(*@\label{Ex:Inst}@*) Q : Query_Type; Selling_Price : Price_Type; begin ... Prepare(Q,"UPDATE SUPPL_ORDER"); Append(Q."SET SELLING_PRICE = "); Append(Q,Selling_Price,New_Line);(*@\label{Ex:InstUse}@*) Append_Line(Q,"WHERE ..."); \end{NumberedExample} In this example, the application defines its own type Price\_Type in line~\ref{Ex:TypeDef}. After instantiating the Append\_Decimal generic procedure as Append\index{Append} (line~\ref{Ex:Inst}), the application is free to neatly append a price value from Selling\_Price in line~\ref{Ex:InstUse}, as if it were natively supported. \subsection{Generic Append of Bounded SQL Text} To accomodate the use of the package Ada\-.Strings\-.Bounded\index{Ada.Strings.Bounded}, the generic procedure Append\_Bounded\index{Append\_Bounded} was provided. Its instantiation requirements differ from the preceeding ones because the instantiation of the Bounded\_String\index{Bounded\_String} type must be provided to the Append\_Bounded generic procedure. The generic procedure is defined as follows: \begin{Code} generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Append_Bounded( Q : in out Query_Type; SQL : in P.Bounded_String; After : in String ); \end{Code} In other words, Append\_Bounded can be instantiated from any instantiation of the Ada.Strings.Bounded.Generic\_Bounded\_Length package. The following example makes this easier to understand: \begin{NumberedExample} with Ada.Strings.Bounded; ... declare package B80 is new Ada.Strings.Bounded.Generic_Bounded_Length(80); package B20 is new Ada.Strings.Bounded.Generic_Bounded_Length(20); procedure Append is new Append_Bounded(B80);(*@\label{Ex:B80}@*) procedure Append is new Append_Bounded(B20);(*@\label{Ex:B20}@*) Q : Query_Type; Item_Code : B20; Item_Name : B80; begin ... Prepare(Q, "SELECT COUNT(*)"); Append_Line(Q,"FROM ORDER"); Append(Q, "WHERE ITEM_CODE = ","'"); Append(Q,Item_Code,"' AND ITEM_NAME = '");(*@\label{Ex:UseB20}@*) Append(Q,Item_Name,"'" & New_Line);(*@\label{Ex:UseB80}@*) ... \end{NumberedExample} The example shows how two different generic procedures named Append are instantiated from the Bounded\_String instantiations B80 (line~\ref{Ex:B80}) and B20 (line~\ref{Ex:B20}). Note that the Append\_Bounded procedure does not escape special characters, nor provide the outer quotes (this is a poor example of its use actually). The Append\index{Append} call used in line~\ref{Ex:UseB20} is the one that was instantiated on line~\ref{Ex:B20}. The other Append used on line~\ref{Ex:UseB80} was instantiated on line~\ref{Ex:B80}. These are matched according to the normal Ada2005\index{Ada2005} argument type matching rules. \subsection{Generic Append\_Bounded\_Quoted Procedure} To accomodate the quoting needs of Bounded\_Strings, the Append\_Bounded\_Quoted\index{Append\_Bounded\_Quoted} generic procedure may be used: \begin{Code} generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Append_Bounded_Quoted( Q : in out Query_Type; C : in Connection_Type; SQL : in P.Bounded_String; After : in String ); \end{Code} It is otherwise very similar to the previous Append\_Unbounded\index{Append\_Unbounded} procedure. The following example illustrates a safer\index{safer} version of the prior example: \begin{Example} with Ada.Strings.Bounded; ... declare package B80 is new Ada.Strings.Bounded.Generic_Bounded_Length(80); package B20 is new Ada.Strings.Bounded.Generic_Bounded_Length(20); procedure Append_Quoted is new Append_Bounded_Quoted(B80); procedure Append_Quoted is new Append_Bounded_Quoted(B20); C : Connection_Type; Q : Query_Type; Item_Code : B20; Item_Name : B80; begin ... Prepare(Q, "SELECT COUNT(*)"); Append_Line(Q,"FROM ORDER"); Append(Q, "WHERE ITEM_CODE = "); Append_Quoted(Q,C,Item_Code," AND ITEM_NAME = "); Append_Quoted(Q,C,Item_Name,New_Line); ... \end{Example} The instantiations of Append\_Quoted\index{Append\_Quoted}% \footnote{It is not necessary to instantiate these procedures as Append\_Quoted, but it is recommended for readability.} here will properly escape\index{escape} any special\index{special characters} characters that may appear in the program's string variables Item\_Code and Item\_Name. Additionally, note that the outer quotes\index{quotes} are provided automatically, easing the programmer's burden in building up the SQL query. Like other Append\_Quoted API calls within APQ, the case\index{case within quoted strings} within quoted strings is always preserved. \subsection{Encoding Quoted Strings} While strings are well covered by the category 1 support, it is necessary to encode a NULL\index{NULL} in place of a quoted string\index{quoted string}, when the value is null. The generic specification for Encode\-\_String\-\_Quoted\index{Encode\_String\_Quoted} is as follows: \begin{Code} generic type Ind_Type is new Boolean; procedure Encode_String_Quoted( Q : in out Root_Query_Type'Class; Connection : in Root_Connection_Type'Class; SQL : in String; Indicator : in Ind_Type; After : in String := "" ); \end{Code} An example of its instantiation and use is shown below: \begin{Example} declare type Cust_Name_Ind_Type is new Boolean; procedure Encode_Quoted is new Encode_String_Quoted(Cust_Name_Ind_Type); Q : Query_Type; Cust_Name : String(1..30); Cust_Name_Ind : Cust_Name_Ind_Type; -- Indicator begin ... Prepare(Q,"UPDATE CUSTOMER"); Append_Line(Q,"SET CUST_NAME = "); Encode_Quoted(Q,Cust_Name,Cust_Name_Ind); \end{Example} In this example, the String Cust\_Name is given outer quotes and any special characters are escaped before the value is appended to the current SQL query being collected in object Q. If however, the indicator Cust\_Name\_Ind is True (indicating that the value Cust\_Name should be interpreted as NULL\index{NULL}), then the string ``NULL'' is appended instead. When NULL is supplied, no outer quotes are supplied. The following two SQL statements are possible, depending upon Cust\_Name\_Ind. When the indicator is false, a quoted\index{quoted value} value is supplied: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = 'Fred Willard' ... \end{SQL} When the indicator is true (the value is null), the resulting query becomes the following: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = NULL ... \end{SQL} \subsection{Encoding Quoted Unbounded\_String} To provide quoting\index{quoting support} support for Unbounded\-\_Strings\index{Ada.Strings.Unbounded}, the Encode\-\_Bounded\-\_Quoted gen\-eric procedure is provided by APQ. The specifications for this procedure is given below: \begin{Code} generic type Ind_Type is new Boolean; procedure Encode_Unbounded_Quoted( Q : in out Root_Query_Type'Class; Connection : in Root_Connection_Type'Class; SQL : in Ada.Strings.Unbounded.Unbounded_String; Indicator : in Ind_Type; After : in String := "" ); \end{Code} An example of its use is illustrated as follows: \begin{Example} declare use Ada.Strings.Bounded; type Cust_Name_Ind_Type is new Boolean; procedure Encode_Quoted is new Encode_Unbounded_Quoted(Cust_Name_Ind_Type); C : Connection_Type; Q : Query_Type; Cust_Name : Unbounded_String; Cust_Name_Ind : Cust_Name_Ind_Type; begin ... Prepare(Q,"UPDATE CUSTOMER"); Append_Line(Q,"SET CUST_NAME = "); Encode_Quoted(Q,C,Cust_Name,Cust_Name_Ind); \end{Example} In this example, the Unbounded\_String Cust\_Name is given outer quotes and any special characters are escaped before the value is appended to the current SQL query\index{SQL query} being collected in object Q. If however, the indicator\index{indicator, null} Cust\_Name\_Ind is True (indicating that the value \emph{Cust\_Name} should be interpreted as NULL), then the string ``NULL''\index{NULL} is appended\index{appended} instead. When NULL is supplied, no outer\index{outer quotes} quotes are supplied. The following two SQL statements are possible, depending upon \emph{Cust\_Name\_Ind}. When the indicator is false, a quoted value\index{quoted value} is supplied: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = 'Fred Willard' ... \end{SQL} When the indicator is true, the resulting query becomes the following: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = NULL ... \end{SQL} \subsection{Encoding Bounded Quoted Strings} Bounded strings\index{bounded strings} require instantiations of Ada\-.Strings\-.Bounded\-.Gen\-eric\-\_Bound\-ed\-\_Len\-gth \index{Ada.Strings.Bounded}with a specific length. The instantiated package\index{package} reference must be provided as an argment to the Encode\-\_Bounded\-\_Quoted\index{Encode\_Bounded\_Quoted} instantiation: \begin{Code} generic type Ind_Type is new Boolean; with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Encode_Bounded_Quoted( Q : in out Root_Query_Type'Class; Connection : in Root_Connection_Type'Class; SQL : in P.Bounded_String; Indicator : in Ind_Type; After : in String := "" ); \end{Code} An example showing its use is given below: \begin{Example} with Ada.Strings.Bounded; declare package B80 is new Ada.Strings.Bounded.Generic_Bounded_Length(80); type Cust_Name_Ind_Type is new Boolean; procedure Encode_Quoted is new Encode_Bounded_Quoted(Cust_Name_Ind_Type,B80); C : Connection_Type; Q : Query_Type; Cust_Name : B80.Bounded_String; Cust_Name_Ind : Cust_Name_Ind_Type; -- Indicator begin ... Prepare(Q,"UPDATE CUSTOMER"); Append_Line(Q,"SET CUST_NAME = "); Encode_Quoted(Q,C,Cust_Name,Cust_Name_Ind); ... \end{Example} In this example, the Bounded\_String Cust\_Name is given outer quotes and any special characters are escaped before the value is appended to the current SQL query being collected in object Q. If however, the indicator\index{indicator} Cust\_Name\_Ind is True (indicating that the value Cust\_Name should be interpreted as NULL), then the string ``NULL''\index{NULL} is appended instead. When NULL is supplied, no outer quotes are supplied. The following two SQL\index{SQL} statements are possible, depending upon Cust\_Name\_Ind. When the indicator is false, a quoted value\index{quoted value} is supplied: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = 'Fred Willard' ... \end{SQL} When the indicator is true, the resulting query becomes the following: \begin{SQL} UPDATE CUSTOMER SET CUST_NAME = NULL ... \end{SQL} \subsection{Encoding Non-String Values} There are a large number of generic\index{generic} encoding procedures that allow encoding of non-string\index{non-string values} values into SQL queries. They are listed below: \begin{Code} generic type Val_Type is new Boolean; type Ind_Type is new Boolean; procedure Encode_Boolean( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is range <>; type Ind_Type is new Boolean; procedure Encode_Integer( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is mod <>; type Ind_Type is new Boolean; procedure Encode_Modular( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is digits <>; type Ind_Type is new Boolean; procedure Encode_Float( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is delta <>; type Ind_Type is new Boolean; procedure Encode_Fixed( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is delta <> digits <>; type Ind_Type is new Boolean; procedure Encode_Decimal( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Date; type Ind_Type is new Boolean; procedure Encode_Date( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Time; type Ind_Type is new Boolean; procedure Encode_Time( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Timestamp; type Ind_Type is new Boolean; procedure Encode_Timestamp( Q : in out Root_Query_Type'Class; V : in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} \begin{Code} generic type Val_Type is new APQ_Bitstring; type Ind_Type is new Boolean; procedure Encode_Bitstring( Q : in out Root_Query_Type'Class; V: in Val_Type; Indicator : in Ind_Type; After : in String := "" ); \end{Code} The following example shows the application of one of these generic procedures: \begin{Example} declare type Cust_No_Type is new Integer range 1000..100_000; type Cust_Age_Type is new Integer range 0..200; procedure Append is new Append_Integer(Cust_No_Type); procedure Encode is new Encode_Integer(Cust_No_Type,Boolean); Q : Query_Type; Cust_No : Cust_No_Type; -- Customer # NOT NULL Cust_Age : Cust_Age_Type; -- Can be NULL Cust_Age_Ind : Boolean; -- Indicator Cust_Name : String(1..30); -- Customer Name NOT NULL begin ... Prepare(Q,"INSERT INTO CUSTOMER (CUST_NO,AGE,CUST_NAME)"); Append(Q, "VALUES ( "); Append(Q,Cust_No,","); Encode(Q,Cust_Age,Cust_Age_Ind,","); Append_Quoted(Q,Cust_Name," )" & New_Line); ... \end{Example} From the example, if variable Cust\_Name holds the value ``Martin Mull'', and Cust\_No holds 12345, two possible SQL queries are possible, depending upon the value of Cust\_Age\_Ind, the null indicator\index{indicator, null}. When Cust\_Age\_Ind is false (not null), then the SQL query would be formed as follows: \begin{SQL} INSERT INTO CUSTOMER (CUST_NO,AGE,CUST_NAME) VALUES (12345,52,'Martin Mull') \end{SQL} When the indicator\index{indicator} Cust\_Age\_Ind is true (representing null), then the query would be constructed as follows: \begin{SQL} INSERT INTO CUSTOMER (CUST_NO,AGE,CUST_NAME) VALUES (12345,NULL,'Martin Mull') \end{SQL} Notice how Append\index{Append} procedures are used for values that can never be null (no null indicator is involved). Encode routines are only necessary when a null indicator may need to be encoded into the result. \section{Query Execution} Once the SQL query has been constructed using all of the techniques described in \Ref{SQL Initialization} and \Ref{SQL Query Building}, you are ready to send\index{send the query} the query to the database engine\index{engine, database} to have it executed. This is done with the help of the Query\_Type's primitive Execute\index{Execute}. The Execute call requires the following calling arguments: \begin{Code} procedure Execute( Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class ); \end{Code} The Execute primitive can raise the exceptions that are listed in Table~\ref{t:exx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & There is no connection to use\\ Abort\_State & Transaction in {}``abort state{}``\\ SQL\_Error & The submitted SQL query failed\\ Failed & Hidden APQ query failure\\ \end{tabular} \end{center} \caption{Execute Exceptions}\label{t:exx} \end{table} The PostgreSQL\index{PostgreSQL} Abort\_State\index{Abort\_State} exception is described in \Ref{Abort_State exception}. This exception indicates that the current transaction has failed\index{failed transaction}. All other types of errors\index{errors} raise\index{raise} the SQL\_Error\index{SQL\_Error} exception, unless the connection is bad. The Failed\index{Failed exception} exception only occurs for some databases where a hidden\index{hidden SQL query} SQL query must be performed and it unexpectedly failed.% \footnote{For Sybase, APQ will do a SELECT @@identity after an INSERT query is performed.% } The use of the Execute\index{Execute} primitive is illustrated by the example \ref{Ex:Execute} \begin{NumberedExample}[label=Ex:Execute,caption=Executing Queries] declare type Cust_No_Type is new Integer range 1000..100_000; type Birthday_Type is new APQ_Timestamp; procedure Append is new Append_Integer(Cust_No_Type); procedure Encode is new Encode_Integer(Cust_No_Type,Boolean); procedure Encode is new Encode_Timestamp(Birthday_Type,Boolean); C : Connection_Type; Q : Query_Type; Cust_No : Cust_No_Type; -- NOT NULL Birthday : Birthday_Type; Birthday_Ind : Boolean; -- Indicator begin -- ... -- we set the Ada variable and so on... Prepare( Q, "INSERT INTO BIRTHDAY (CUST_NO,BIRTHDAY)" ); Append( Q, "VALUES (" ); Append( Q, Cust_No, ","); Encode( Q, Birthday, Birthday_TZ, Birthday_Ind, ")" ); Execute( Q, C ); (*@\label{Ex:Execute:Execute}@*) end; \end{NumberedExample} The example shows the Execute primitive pairing the query object Q with the database connection object C at line \ref{Ex:Execute:Execute}. \subsection{Error Message Reporting\label{Error Message Reporting}} It is useful to know that your SQL query failed, but more information is usually necessary. The Error\_Message\index{Error\_Message} primitive can be invoked on the Query\_Type object. This function has the following calling signature: \begin{Code} function Error_Message( Query : Query_Type; ) return String; \end{Code} The following example shows how this function might be used: \begin{Example} begin ... Execute(Q,C); exception when SQL_Error => Put(Standard_Error,"SQL Error: "); Put_Line(Standard_Error,Error_Message(Q)); raise; when others => raise; end \end{Example} \subsection{Is\_Duplicate\_Key Function} Duplicate\index{duplicate key} key errors\index{errors} often occur while performing SQL INSERT\index{INSERT} operations on a table. A duplicate key insertion\index{insertion error} error is a special case because the insert operation may not be considered a failure for some applications. For this reason, the Is\_Duplicate\_Key\index{Is\_Duplicate\_Key} predicate function is provided for use after a SQL\_Error exception has been raised% \footnote{At present, this test is implemented by calling Error\_Message and looking at the message text. Future versions of the APQ binding may use a more reliable indicator if the PostgreSQL libpq library provides such a status indication.% }. The specification is listed as follows: \begin{Code} function Is_Duplicate_Key( Query : Query_Type ) return Boolean; \end{Code} The following example reports an SQL error\index{SQL error} only if the error is not a duplicate key insert problem: \begin{Example} ... begin Execute(Q,C); -- Execute an INSERT SQL statement exception when SQL_Error => if not Is_Duplicate_Key(Q) then -- Report error if not a duplicate insert Put(Standard_Error,"SQL Error: "); Put_Line(Standard_Error,Error_Message(Q)); raise; else null; -- Ignore duplicate insert end; end; \end{Example} \subsection{Command\_Status Function (PostgreSQL)\label{Command_Status Function}} The Command\_Status\index{Command\_Status} function provides a string of status information after a PostgreSQL\index{PostgreSQL} query has been executed. The results returned depends upon the type of execution that was last performed. Table~\ref{t:csrv} summarizes the types of return status strings available:% \marginpar{This is a PostgreSQL specific function, only. Avoid its use for portability.} \begin{table} \begin{center} \begin{tabular}{|l|l|l|} \hline After Event & Result & Comments\\ \hline CREATE ... & "CREATE" & \\ BEGIN WORK & "BEGIN" & \\ COMMIT WORK & "COMMIT" & \\ ROLLBACK WORK & "ROLLBACK" & \\ SELECT ... & "SELECT" & \\ INSERT ... & "INSERT <\#>" & \# is normally 1\\ \hline \end{tabular} \end{center} \caption{Command\_Status Return Values}\label{t:csrv} \end{table} Notice that after an INSERT\index{INSERT} is performed, the returned status string includes the OID\index{OID} (row ID\index{row ID}) of the new row, and the number of rows inserted (normally 1). If you need to extract the OID value, see the Command\_Oid function in \Ref{Command_Oid Function}. The calling signature of Command\_Status is: \begin{Code} function Command_Status( Query : Query_Type ) return String; \end{Code} The Command\_Status function can raise the exceptions listed in Table~\ref{t:cstsx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There is no result status (no execution)\\ \end{tabular} \end{center} \caption{Command\_Status Exceptions}\label{t:cstsx} \end{table} \subsection{Command\_Oid Function \label{Command_Oid Function}} After an INSERT\index{INSERT} operation, it is often required to know the OID\index{OID} (row ID\index{row ID}) value for the newly created row. When using PostgreSQL, this can be extracted from the Command\_Status\index{Command\_Status} return string (see \Ref{Command_Status Function}), but this approach is not portable to other vendor databases. The APQ user is encouraged to call the Command\_Oid function when it is necessary to know the identity\index{identity} of the newly inserted row. This function primitive hides the differences\index{differences} between the different database products and makes your code more portable. The calling signature for Command\_Oid is as follows: \begin{Code} function Command_Oid( Query : Query_Type ) return Row_ID_Type; \end{Code} Table \ref{t:coidx} lists the exceptions that are possible for Command\_Oid. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There is no result status (no execution)\\ SQL\_Error & An SQL error occurred obtaining the OID\\ \end{tabular} \end{center} \caption{Command\_Oid Exceptions}\label{t:coidx} \end{table} Be aware that the exception No\_Result\index{No\_Result} can be raised for two different reasons: \begin{itemize} \item There was no prior ``execution'' (thus no result) \item The prior execution was not an INSERT operation (hence no OID value available) \end{itemize} APQ applications should \emph{not} be written to provoke these exceptions, since different database products behave differently in this respect (Sybase\index{Sybase} users will never see an exception from Command\_Oid for example). The raising of either of these exceptions does however indicate that there is a programming error\index{error, programming} that requires correction in the calling application. \subsubsection{Database OID (Row ID) Support} Some databases do not support the concept of OID\index{OID} (row ID\index{row ID}) values. This creates a huge portability\index{portability} problem for the application programmer. However, all databases provide some technique for identifying\index{identifying rows} rows uniquely in a table. Table~\ref{t:roids} summarizes the ways that APQ adapts the database server to concept of OID values:% \footnote{Applications should be written to avoid row ID concepts and use key values instead.} \begin{table} \begin{center} \begin{tabular}{|l|l|l|l|} \hline Database & OID & How & How APQ Supports OID\\ \hline PostgreSQL & Yes & OID = Row ID & PostgreSQL Object ID (OID)\\ MySQL & No & AUTO\_INCREMENT & Serial value from primary key\\ Sybase & No & Identity column & SELECT @@identity\\ \hline \end{tabular} \end{center} \caption{Row ID Database Support}\label{t:roids} \end{table} \subsubsection{MySQL OID (Row ID) Support} From the preceeding table, you can observe that MySQL\index{MySQL} does not support any concept of a row ID\index{row ID} value. APQ can fake OID-like\index{OID} support, if the table is defined using a primary key in the following form\index{AUTO\_INCREMENT}: \begin{SQL} INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY \end{SQL} When a MySQL table has a primary key like the one shown, APQ is able to return the created primary key value using Command\_OID\index{Command\_OID}. The following is an example table declaration: \begin{SQL} CREATE TABLE ITEM_DESC ( ITEM_ID INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR(80) ); \end{SQL} \subsubsection{Sybase OID (Row ID) Support} Sybase\index{Sybase} does not support the concept of row ID\index{row ID} values. APQ however, can provide row ID-like support if you declare your table with a primary key in the following form\index{IDENTITY}: \begin{SQL} NUMERIC IDENTITY NOT NULL PRIMARY KEY \end{SQL} For Sybase, when the APQ procedure Execute is performed, APQ will check to see if the SQL query peformed was an INSERT\index{INSERT} command. If it was, a hidden SQL query is performed immediately afterwards on the same connection to query the identity\index{identity of a row} of the row that was created\index{@@identity}: \begin{SQL} SELECT @@identity \end{SQL} The value returned by this hidden query will be saved as the row ID\index{row ID} in the Query\-\_Type object used to perform the INSERT\index{INSERT}. A later call to Command\_OID on this same Query\_Type object, will then return this row identity value as a Row\_ID\_Type\index{Row\_ID\_Type}. The following is an example Sybase table declaration: \begin{SQL} CREATE TABLE ITEM_DESC ( ITEM_ID NUMERIC IDENTITY NOT NULL PRIMARY KEY, DESCRIPTION VARCHAR(80) ); \end{SQL} \subsubsection{Example of Command\_OID Use} The following example will always work for PostgreSQL\index{PostgreSQL}. It will also work for MySQL\index{MySQL} and Sybase\index{Sybase}, if the primary key\index{primary key} guidelines in the prior subsections were followed. This example shows how the INSERTed\index{INSERT} row's OID value (or primary key\index{primary key}) is obtained: \begin{Example} declare C : Connection_Type; Q : Query_Type; Obj_Id : Row_ID_Type; begin ... Prepare(Q,"INSERT INTO CUST_ORDER (CATALOG_NO,QUANTITY,..."); ... Execute(Q,C); Obj_Id := Command_Oid(Q); -- row id/identity of inserted row \end{Example} The variable named Obj\_ID will contain the PostgreSQL\index{PostgreSQL} OID\index{OID} value of the inserted row, when PostgreSQL is used. For MySQL\index{MySQL} and Sybase\index{Sybase}, the variable Obj\_ID will contain the primary key value of the newly created row. \subsubsection{Generic\_Command\_Oid Function} To allow strong typing\index{strong typing} to be used in place of the supplied Row\_ID\_Type\index{Row\_ID\_Type} type, the Generic\_Command\_Oid\index{Generic\_Command\_Oid} function can be instantiated for use in the application. The instantiated function otherwise behaves identical with the Command\_Oid function described on page \pageref{Command_Oid Function}. The instantiation arguments for Generic\_Command\_Oid are as follows: \begin{Code} generic type Oid_Type is new Row_ID_Type; function Generic_Command_Oid( Query : Query_Type'Class ) return Oid_Type; \end{Code} An instantiation example follows: \begin{Example} declare type My_Oid_Type is new Row_ID_@Type; function Command_Oid is new Generic_Command_Oid(My_Oid_Type); \end{Example} \subsection{Error Status Reporting\label{Error Status Reporting}} The Result\index{Result} function primitive is documented here for completeness. Applications should avoid using this function, since the values that it returns are very database technology specific. \subsubsection{Result Codes} The Result function primitive should be avoided in portable code. However, there may be circumstances where a particular code is important to the application developer. \begin{Code} function Result( Query : Query_Type ) return Natural; -- Returns Result_Type'Pos() \end{Code} The Result function returns a Natural\index{Natural} value. To obtain the Result\_Type\index{Result\_Type} for the database being used, you should use; \begin{Example} declare Q : Query_Type; R : Result_Type; begin R := Result_Type'Val(Result(Q)); \end{Example} \subsubsection{Notes:} \begin{itemize} \item The Execute\index{Execute} primitive will throw an exception if the execution failed (the PostgreSQL Nonfatal\_Error\index{Nonfatal\_Error} case). \item For SELECT\index{SELECT} queries, the fact that no rows are returned will be identifiable upon the first FETCH\index{FETCH} operation (the PostgreSQL Empty\_Query\index{Empty\_Query} case), or upon calling End\_of\_Query\index{End\_of\_Query}. \item When rows are returned (the PostgreSQL Tuples\_OK\index{Tuples\_OK} case), the application will successfully fetch at least one row. \item For other SQL commands, successful execution is determined by Execute not throwing an exception (the PostgreSQL Command\_OK\index{Command\_OK} case). \end{itemize} \subsubsection{PostgreSQL Result Codes} The PostgreSQL\index{PostgreSQL} result\index{result types} types are declared in the APQ\-.PostgreSQL package. The Result\_Type values are highly PostgreSQL engine\index{engine} specific and are enumerated in Table~\ref{t:pqresc}. \begin{longtable}{|c|c|l|} \hline Name & Value & Description\\ \hline Empty\_Query & 0 & The query returned 0 rows of data\\ Command\_OK & 1 & The non-query statement executed successfully\\ Tuples\_OK & 2 & The SQL query returned at least 1 row of data\\ Copy\_Out & 3 & \\ Copy\_In & 4 & \\ Bad\_Response & 5 & Bad response from database server\\ Nonfatal\_Error & 6 & A non fatal error has occurred\\ Fata\_Error & 7 & A fatal error has occurred\\ \hline \caption{PostgreSQL Result Codes}\label{t:pqresc} \end{longtable} \begin{quote} Note that the numeric values in Table~\ref{t:pqresc} are subject to change if the PostgreSQL\index{PostgreSQL} database server software designers choose to do so. Use the enumerated names instead. \end{quote} \subsubsection{MySQL Result Codes} Result types for MySQL\index{MySQL} are declared in package APQ\-.MySQL. These are generated by the APQ install process from the MySQL database C macros provided. The following is the list from MySQL version 4.0.14 : \begin{Code} type Result_Type is ( CR_NO_ERROR, ER_HASHCHK, ER_NISAMCHK, ER_NO, ER_YES, ER_CANT_CREATE_FILE, ER_CANT_CREATE_TABLE, ER_CANT_CREATE_DB, ER_DB_CREATE_EXISTS, ER_DB_DROP_EXISTS, ER_DB_DROP_DELETE, ER_DB_DROP_RMDIR, ER_CANT_DELETE_FILE, ER_CANT_FIND_SYSTEM_REC, ER_CANT_GET_STAT, ER_CANT_GET_WD, ER_CANT_LOCK, ER_CANT_OPEN_FILE, ER_FILE_NOT_FOUND, ER_CANT_READ_DIR, ER_CANT_SET_WD, ER_CHECKREAD, ER_DISK_FULL, ER_DUP_KEY, ER_ERROR_ON_CLOSE, ER_ERROR_ON_READ, ER_ERROR_ON_RENAME, ER_ERROR_ON_WRITE, ER_FILE_USED, ER_FILSORT_ABORT, ER_FORM_NOT_FOUND, ER_GET_ERRNO, ER_ILLEGAL_HA, ER_KEY_NOT_FOUND, ER_NOT_FORM_FILE, ER_NOT_KEYFILE, ER_OLD_KEYFILE, ER_OPEN_AS_READONLY, ER_OUTOFMEMORY, ER_OUT_OF_SORTMEMORY, ER_UNEXPECTED_EOF, ER_CON_COUNT_ERROR, ER_OUT_OF_RESOURCES, ER_BAD_HOST_ERROR, ER_HANDSHAKE_ERROR, ER_DBACCESS_DENIED_ERROR, ER_ACCESS_DENIED_ERROR, ER_NO_DB_ERROR, ER_UNKNOWN_COM_ERROR, ER_BAD_NULL_ERROR, ER_BAD_DB_ERROR, ER_TABLE_EXISTS_ERROR, ER_BAD_TABLE_ERROR, ER_NON_UNIQ_ERROR, ER_SERVER_SHUTDOWN, ER_BAD_FIELD_ERROR, ER_WRONG_FIELD_WITH_GROUP, ER_WRONG_GROUP_FIELD, ER_WRONG_SUM_SELECT, ER_WRONG_VALUE_COUNT, ER_TOO_LONG_IDENT, ER_DUP_FIELDNAME, ER_DUP_KEYNAME, ER_DUP_ENTRY, ER_WRONG_FIELD_SPEC, ER_PARSE_ERROR, ER_EMPTY_QUERY, ER_NONUNIQ_TABLE, ER_INVALID_DEFAULT, ER_MULTIPLE_PRI_KEY, ER_TOO_MANY_KEYS, ER_TOO_MANY_KEY_PARTS, ER_TOO_LONG_KEY, ER_KEY_COLUMN_DOES_NOT_EXITS, ER_BLOB_USED_AS_KEY, ER_TOO_BIG_FIELDLENGTH, ER_WRONG_AUTO_KEY, ER_READY, ER_NORMAL_SHUTDOWN, ER_GOT_SIGNAL, ER_SHUTDOWN_COMPLETE, ER_FORCING_CLOSE, ER_IPSOCK_ERROR, ER_NO_SUCH_INDEX, ER_WRONG_FIELD_TERMINATORS, ER_BLOBS_AND_NO_TERMINATED, ER_TEXTFILE_NOT_READABLE, ER_FILE_EXISTS_ERROR, ER_LOAD_INFO, ER_ALTER_INFO, ER_WRONG_SUB_KEY, ER_CANT_REMOVE_ALL_FIELDS, ER_CANT_DROP_FIELD_OR_KEY, ER_INSERT_INFO, ER_INSERT_TABLE_USED, ER_NO_SUCH_THREAD, ER_KILL_DENIED_ERROR, ER_NO_TABLES_USED, ER_TOO_BIG_SET, ER_NO_UNIQUE_LOGFILE, ER_TABLE_NOT_LOCKED_FOR_WRITE, ER_TABLE_NOT_LOCKED, ER_BLOB_CANT_HAVE_DEFAULT, ER_WRONG_DB_NAME, ER_WRONG_TABLE_NAME, ER_TOO_BIG_SELECT, ER_UNKNOWN_ERROR, ER_UNKNOWN_PROCEDURE, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, ER_WRONG_PARAMETERS_TO_PROCEDURE, ER_UNKNOWN_TABLE, ER_FIELD_SPECIFIED_TWICE, ER_INVALID_GROUP_FUNC_USE, ER_UNSUPPORTED_EXTENSION, ER_TABLE_MUST_HAVE_COLUMNS, ER_RECORD_FILE_FULL, ER_UNKNOWN_CHARACTER_SET, ER_TOO_MANY_TABLES, ER_TOO_MANY_FIELDS, ER_TOO_BIG_ROWSIZE, ER_STACK_OVERRUN, ER_WRONG_OUTER_JOIN, ER_NULL_COLUMN_IN_INDEX, ER_CANT_FIND_UDF, ER_CANT_INITIALIZE_UDF, ER_UDF_NO_PATHS, ER_UDF_EXISTS, ER_CANT_OPEN_LIBRARY, ER_CANT_FIND_DL_ENTRY, ER_FUNCTION_NOT_DEFINED, ER_HOST_IS_BLOCKED, ER_HOST_NOT_PRIVILEGED, ER_PASSWORD_ANONYMOUS_USER, ER_PASSWORD_NOT_ALLOWED, ER_PASSWORD_NO_MATCH, ER_UPDATE_INFO, ER_CANT_CREATE_THREAD, ER_WRONG_VALUE_COUNT_ON_ROW, ER_CANT_REOPEN_TABLE, ER_INVALID_USE_OF_NULL, ER_REGEXP_ERROR, ER_MIX_OF_GROUP_FUNC_AND_FIELDS, ER_NONEXISTING_GRANT, ER_TABLEACCESS_DENIED_ERROR, ER_COLUMNACCESS_DENIED_ERROR, ER_ILLEGAL_GRANT_FOR_TABLE, ER_GRANT_WRONG_HOST_OR_USER, ER_NO_SUCH_TABLE, ER_NONEXISTING_TABLE_GRANT, ER_NOT_ALLOWED_COMMAND, ER_SYNTAX_ERROR, ER_DELAYED_CANT_CHANGE_LOCK, ER_TOO_MANY_DELAYED_THREADS, ER_ABORTING_CONNECTION, ER_NET_PACKET_TOO_LARGE, ER_NET_READ_ERROR_FROM_PIPE, ER_NET_FCNTL_ERROR, ER_NET_PACKETS_OUT_OF_ORDER, ER_NET_UNCOMPRESS_ERROR, ER_NET_READ_ERROR, ER_NET_READ_INTERRUPTED, ER_NET_ERROR_ON_WRITE, ER_NET_WRITE_INTERRUPTED, ER_TOO_LONG_STRING, ER_TABLE_CANT_HANDLE_BLOB, ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, ER_DELAYED_INSERT_TABLE_LOCKED, ER_WRONG_COLUMN_NAME, ER_WRONG_KEY_COLUMN, ER_WRONG_MRG_TABLE, ER_DUP_UNIQUE, ER_BLOB_KEY_WITHOUT_LENGTH, ER_PRIMARY_CANT_HAVE_NULL, ER_TOO_MANY_ROWS, ER_REQUIRES_PRIMARY_KEY, ER_NO_RAID_COMPILED, ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, ER_KEY_DOES_NOT_EXITS, ER_CHECK_NO_SUCH_TABLE, ER_CHECK_NOT_IMPLEMENTED, ER_CANT_DO_THIS_DURING_AN_TRANSACTION, ER_ERROR_DURING_COMMIT, ER_ERROR_DURING_ROLLBACK, ER_ERROR_DURING_FLUSH_LOGS, ER_ERROR_DURING_CHECKPOINT, ER_NEW_ABORTING_CONNECTION, ER_DUMP_NOT_IMPLEMENTED, ER_FLUSH_MASTER_BINLOG_CLOSED, ER_INDEX_REBUILD, ER_MASTER, ER_MASTER_NET_READ, ER_MASTER_NET_WRITE, ER_FT_MATCHING_KEY_NOT_FOUND, ER_LOCK_OR_ACTIVE_TRANSACTION, ER_UNKNOWN_SYSTEM_VARIABLE, ER_CRASHED_ON_USAGE, ER_CRASHED_ON_REPAIR, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER_TRANS_CACHE_FULL, ER_SLAVE_MUST_STOP, ER_SLAVE_NOT_RUNNING, ER_BAD_SLAVE, ER_MASTER_INFO, ER_SLAVE_THREAD, ER_TOO_MANY_USER_CONNECTIONS, ER_SET_CONSTANTS_ONLY, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_TABLE_FULL, ER_READ_ONLY_TRANSACTION, ER_DROP_DB_WITH_READ_LOCK, ER_CREATE_DB_WITH_READ_LOCK, ER_WRONG_ARGUMENTS, ER_NO_PERMISSION_TO_CREATE_USER, ER_UNION_TABLES_IN_DIFFERENT_DIR, ER_LOCK_DEADLOCK, ER_TABLE_CANT_HANDLE_FULLTEXT, ER_CANNOT_ADD_FOREIGN, ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_CONNECT_TO_MASTER, ER_QUERY_ON_MASTER, ER_ERROR_WHEN_EXECUTING_COMMAND, ER_WRONG_USAGE, ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, ER_CANT_UPDATE_WITH_READLOCK, ER_MIXING_NOT_ALLOWED, ER_DUP_ARGUMENT, ER_USER_LIMIT_REACHED, ER_SPECIFIC_ACCESS_DENIED_ERROR, ER_LOCAL_VARIABLE, ER_GLOBAL_VARIABLE, ER_NO_DEFAULT, ER_WRONG_VALUE_FOR_VAR, ER_WRONG_TYPE_FOR_VAR, ER_VAR_CANT_BE_READ, ER_CANT_USE_OPTION_HERE, ER_NOT_SUPPORTED_YET, ER_MASTER_FATAL_ERROR_READING_BINLOG, ER_SLAVE_IGNORED_TABLE, CR_UNKNOWN_ERROR, CR_SOCKET_CREATE_ERROR, CR_CONNECTION_ERROR, CR_CONN_HOST_ERROR, CR_IPSOCK_ERROR, CR_UNKNOWN_HOST, CR_SERVER_GONE_ERROR, CR_VERSION_ERROR, CR_OUT_OF_MEMORY, CR_WRONG_HOST_INFO, CR_LOCALHOST_CONNECTION, CR_TCP_CONNECTION, CR_SERVER_HANDSHAKE_ERR, CR_SERVER_LOST, CR_COMMANDS_OUT_OF_SYNC, CR_NAMEDPIPE_CONNECTION, CR_NAMEDPIPEWAIT_ERROR, CR_NAMEDPIPEOPEN_ERROR, CR_NAMEDPIPESETSTATE_ERROR, CR_CANT_READ_CHARSET, CR_NET_PACKET_TOO_LARGE, CR_EMBEDDED_CONNECTION, CR_PROBE_SLAVE_STATUS, CR_PROBE_SLAVE_HOSTS, CR_PROBE_SLAVE_CONNECT, CR_PROBE_MASTER_CONNECT, CR_SSL_CONNECTION_ERROR, CR_MALFORMED_PACKET ); \end{Code} \subsubsection{Sybase Result Codes} The Result\_Type values available from package APQ.Sybase are as follows; \begin{Code} type Result_Type is ( Execution_Failed, -- ct_results() call failed No_Results, -- Cmd processed, but no results Row_Results, -- Cmd processed, and row results Cursor_Results, -- Cmd processed, and cursor row result Info_Results, -- Cmd processed, no row data, but info Compute_Results, -- Computed results Param_Results, -- Parameter results Status_Results -- Status results ); \end{Code} \subsection{Generic APQ.Result\label{Generic APQ.Result}} To enable generic database processing, APQ version 2.0 adds a new API function which is declared at the APQ\-.Root\_Query\_Type\index{APQ.Root\_Query\_Type} object level. This function returns a Natural result: \begin{Code} function Result( Query : Root_Query_Type; ) return Natural; \end{Code} The value returned, represents the Result\_Type'Pos(arg)\index{Result\_Type'Pos}. In generic database code, you could use this generic function to retrieve the value. Later it can be turned into the appropriate Result\_Type when required by doing a conversion. The following example illustrates: \begin{Example} with APQ.MySQL.Client, APQ.PostgreSQL.Client; ... procedure App(Q : Root_Query_Type'Class) is R : Natural; PQ_R : APQ.PostgreSQL.Result_Type; My_R : APQ.MySQL.Result_Type; begin ... R := APQ.Result(Q); if APQ.Engine_Of(Q) = Engine_MySQL then My_R := APQ.MySQL.Result_Type'Val(R); ... elsif APQ.Engine_Of(Q) = Engine_PostgreSQL then PQ_R := APQ.PostgreSQL.Result_Type'Val(R); ... ... \end{Example} The code above demonstrates how generic database code is able to test for specific database error codes, when required. \subsection{Generic APQ.Engine\_Of\label{Generic APQ.Engine_Of}} As seen in the example of \Ref{Generic APQ.Result}, it is sometimes necessary to determine in portable code, what database technology is being used. Once this fact is known, the correct, more specific action can be taken. For example, the ``LIMIT n''\index{LIMIT} clause can be added to MySQL\index{MySQL} queries to limit the number of returned rows for greater efficiency. The function primitive Engine\_Of\index{Engine\_Of} can be used to determine the database technology being used: \begin{Code} type Database_Type is ( Engine_PostgreSQL, Engine_MySQL, Engine_Sybase ); function Engine_Of( Query : Root_Query_Type; ) return Database_Type; \end{Code} \subsection{Checked Execution} For many utility programs \index{utility programs}where error reporting and recovery have simple requirements, a more compact and convenient way to execute queries can be applied. With checked execution, the query is not only executed, but any SQL errors are intercepted and reported\index{reported} to Standard\_Error\index{Standard\_Error} automatically. This saves the programmer effort when writing simple utility programs. Once the SQL\_Error\index{SQL\_Error} exception is intercepted and reported, the exception is re-raised to leave control in the caller's hands. The important thing here is that the error\index{error} is caught and reported. The Execute\_Checked\index{Execute\_Checked} primitive has the following calling signature: \begin{Code} procedure Execute_Checked( Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class; Msg : in String := "" ); \end{Code} When the argument Msg is a non-empty\index{non-empty string} string like ``Dropping table temp\_tbl'', the error message reported will be of the following format: \begin{Example} *** SQL ERROR: Dropping table temp_tbl FATAL_ERROR: ERROR: Relation "temp_tbl" does not exist \end{Example} The first line just identifies the fact that an SQL error occurred, and reports the Msg text. The second line first reports Result\_Type'Image of the error, and then reports the error message text as returned by Error\_Message\index{Error\_Message}. In this case, the example shows that Result\_Type Fatal\_Error was returned, and the error message returned from the database server was ``ERROR: Relation ``temp\_tbl'' does not exist''. When the null string\index{null string} (or the default value for the parameter) is given to argument Msg, then the SQL query is dumped\index{dumped} out to Standard\_Error\index{Standard\_Error} instead. This is often useful for debugging\index{debugging} purposes. Changing the example \ref{Ex:Execute} on page \pageref{Ex:Execute} slightly, we can apply the Execute\_Checked primitive in the place of the Execute\index{Execute} call as shown in the example \ref{Ex:Execute_Checked}. \begin{NumberedExample}[label=Ex:Execute_Checked,caption=Executing Queries using Execute\_Checked] declare type Cust_No_Type is new Integer range 1000..100_000; type Birthday_Type is new APQ_Timestamp; procedure Append is new Append_Integer(Cust_No_Type); procedure Encode is new Encode_Integer(Cust_No_Type,Boolean); procedure Encode is new Encode_Timestamp(Birthday_Type,Boolean); C : Connection_Type; Q : Query_Type; Cust_No : Cust_No_Type; -- NOT NULL Birthday : Birthday_Type; Birthday_Ind : Boolean; -- Indicator begin -- ... -- we set the Ada variable and so on... Prepare( Q, "INSERT INTO BIRTHDAY (CUST_NO,BIRTHDAY)" ); Append( Q, "VALUES (" ); Append( Q, Cust_No, ","); Encode( Q, Birthday, Birthday_TZ, Birthday_Ind, ")" ); Execute_Checked( Q, C ); (*@\label{Ex:Execute_Checked:Execute_Checked}@*) end; \end{NumberedExample} \subsection{Suppressing Checked Exceptions} For utility work, it is sometimes convenient to have Execute\_Checked report errors, but not raise SQL\_Error\index{SQL\_Error}. This is useful when you don't care about the outcome but want the error to be reported when detected. The raising or not raising of SQL\_Error can be controlled for the Execute\_Checked\index{Execute\_Checked} primitive by calling Raise\_Exceptions\index{Raise\_Exceptions}. It has the following calling requirements: \begin{Code} procedure Raise_Exceptions( Query : in out Query_Type; Raise_On : in Boolean := True ); \end{Code} The following example shows how exceptions can be suppressed: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Raise_Exceptions(Q,False); -- Suppress SQL_Error exception Execute_Checked(Q,C); -- Report errors only Raise_Exceptions(Q,True); -- Re-enable SQL_Error exceptions \end{Example} \subsection{Suppressing Checked Reports} Occaisionally, it is useful to control whether or not reporting is performed in the event of an SQL\_Error\index{SQL\_Error}. The reporting of errors can be controlled by the Report\_Errors\index{Report\_Errors} primitive procedure: \begin{Code} procedure Report_Errors( Query : in out Query_Type; Report_On : in Boolean := True ); \end{Code} The default behaviour of a Query\_Type is to report errors and raise SQL\_Error when Execute\_Checked experiences an SQL\_Error exception. The reporting behaviour can be disabled\index{disable reporting} as follows: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Report_Errors(Q,False); -- Suppress error reporting Execute_Checked(Q,C); \end{Example} Normally application programmers would not use Execute\_Checked with error reporting disabled. However, it may be useful as a temporary measure to cause error reporting while debugging\index{debugging} a program. Once the debugging has been completed, a global Boolean\index{Boolean} value could be set to false to prevent these errors from being reported. \section{Transaction Operations} Database transaction\index{Transaction} operations consist of: \begin{itemize} \item BEGIN WORK\index{BEGIN WORK} \item COMMIT WORK\index{COMMIT WORK} \item ROLLBACK WORK\index{ROLLBACK WORK} \end{itemize} It is possible to build your own queries to accomplish these operations but the programmer is encourage to use the primitive operations below instead. One reason for using the APQ provided functions is to make your application portable to different databases. There are slight variations on the SQL syntax\index{syntax, SQL} required for these operations. It may also be possible in the future to query the state of the transaction.% \footnote{It is likely that a function like an In\_Transaction function will be added in the future.% } The three primitives are named according to function \label{Begin, Commit and Rollback Work functions} and are listed in Table~\ref{t:txp}. \begin{table} \begin{center} \begin{tabular}{ll} Primitive Name & SQL Function\\ \hline Begin\_Work & BEGIN WORK\\ Commit\_Work & COMMIT WORK\\ Rollback\_Work & ROLLBACK WORK\\ \end{tabular} \end{center} \caption{Transaction Primitives}\label{t:txp} \end{table} The specifications of these primitives are listed below: \begin{Code} procedure Begin_Work( Query : in out Query_Type; Connection : in out Connection_Type'Class ); \end{Code} \begin{Code} procedure Commit_Work( Query : in out Query_Type; Connection : in out Connection_Type'Class ); \end{Code} \begin{Code} procedure Rollback_Work( Query : in out Query_Type; Connection : in out Connection_Type'Class ); \end{Code} These primitives will raise the exceptions listed in Table~\ref{t:tranpx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Not\_Connected & There is no connection\\ Abort\_State & A ROLLBACK is required\\ SQL\_Error & This should not normally occur\\ \end{tabular} \end{center} \caption{Transaction Primitives Exceptions}\label{t:tranpx} \end{table} The following simple example demonstrates the use of these primitives: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin ... Begin_Work(Q,C); ... Commit_Work(Q,C); \end{Example} \begin{description} \item [Note:] There is an implicit\index{implicit Clear} Clear operation before and after the execution of these operations for the Query\_Type\index{Query\_Type} object. The original fetch mode of the object is preserved after the call. \end{description} \subsection{The PostgreSQL Abort\_State} The Abort\_State\index{Abort\_State} is unique to the PostgreSQL\index{PostgreSQL} database. Other databases will tolerate failed steps within a transaction, but PostgreSQL will not. The Abort\_State \label{Abort_State exception} exception indicates that the database was in a transaction% \footnote{A {}``BEGIN WORK'' statement was executed.% } when a processing error occurred (like a duplicate key on insert error). Once an error\index{error in transaction} is encountered within a PostgreSQL transaction, the only course to recovery is by executing a ROLLBACK\index{ROLLBACK} WORK statement (this is done by the Rollback\_Work\index{Rollback\_Work} call shown above). If duplicate\index{duplicate inserts} inserts\index{inserts} may occur, you must test for them in advance of the INSERT\index{INSERT}, to avoid placing the transaction into the ``abort state''\index{abort state}. Note that this PostgreSQL\index{PostgreSQL} behavior is different from other database vendor offerings. The ``abort state''\index{abort state} itself is maintained in the Connection\_Type\index{Connection\_Type} object, causing the state\index{state} to influence all Query\_Type objects using the same connection. To clear the status\index{status}, you must perform a Rollback\_Work\index{Rollback\_Work} call on any Query\_Type object, using the affected Connection\_Type object where the status is saved. The Query\_Type object is used to form the SQL\index{SQL} statement and to hold the result\index{result status} status. In application programming, you may want to dedicate one Query\_Type object for each transaction in progress.% \footnote{This will be important later, if you want to query whether or not you are in a transaction.% } \section{Fetch Operations} Some database operations, particularly SELECT\index{SELECT}, return results. There are two fetch\index{fetch} related primitives: \begin{enumerate} \item Sequential\index{Sequential access} row fetch\index{fetch, sequential} \item Random\index{Random access} access row fetch\index{fetch, random} \end{enumerate} The sequential fetch permits serial\index{serial access} access of the resulting rows (tuples\index{tuples}). Random access fetching permits rapid\index{rapid access} access to particular row results. \subsection{Fetch Limitations\label{Fetch Limitations}} Some databases like PostgreSQL\index{PostgreSQL} have \emph{no} limitations\index{limitations} on how row data is fetched. The fetch\index{fetch} may be sequential or random, as the application requires. Some other databases however, require some planning by the application programmer in this area. This distinction, and the API to control this problem is new to APQ 2.0 and later, for database engines\index{engines} that require it. For example, MySQL\index{MySQL} retrieves row data into the client program's address\index{address space} space in one of two ways: \begin{itemize} \item one row at a time, but all rows must be fetched \item all rows are loaded into client memory\index{client memory}, for random access by the application \end{itemize} For large result sets\index{large result sets}, fetching one row% \footnote{This is done using the mysql\_use\_result() function.% } at a time is very practical. However, MySQL\index{MySQL} requires that the program fetch \emph{all} row data. If the result set\index{result set} is large, and only an initial number of rows are required, this can be a serious performance issue. This is a greater problem if the application would like to cancel\index{cancel} the operation. When random access% \footnote{This is done using the mysql\_store\_result() function.% } of rows is required, MySQL\index{MySQL} requires that all row data be retrieved and stored into the client program (behind the scenes). Fetching all of this data into client memory\index{client memory} can be impractical for size\index{size} reasons for large numbers of rows (there is an SQL work-around\index{SQL work-around} for this). The default APQ query mode varies according to database as listed in Table~\ref{t:fchmd}. \begin{table} \begin{center} \begin{tabular}{lll} Database & Default Mode & Comments\\ \hline PostgreSQL & Random\_Fetch & Random or Sequential supported\\ MySQL & Random\_Fetch & Watch \# of rows returned\\ Sybase & Sequential\_Fetch & Random\_Fetch not supported\\ \end{tabular} \end{center} \caption{APQ Fetch Modes}\label{t:fchmd} \end{table} From the table, you can see that PostgreSQL\index{PostgreSQL} has no difficulty in either mode. MySQL\index{MySQL} supports both modes, but the programmer must be careful about the result set size returned if Random\_Fetch mode is in use. Finally, Sybase\index{Sybase} support does not support Random\_Fetch\index{Random\_Fetch} mode (Sybase \emph{can} fetch rows randomly with a cursor, but only sequential cursors\index{cursors} are currently supported by APQ). All database engines\index{engines} support sequential\index{sequential} access \- even in random\index{random} access mode. Even if you are using the default or configured Random\_Fetch\index{Random\_Fetch} mode, APQ will return rows sequentially unless a specific row is requested. If the application programmer is using a database that is limited in this way (MySQL), and has determined that fetching all results into client memory is not suitable, then the mode of the Query\_Type\index{Query\_Type} needs to be changed by the program to use sequential access instead. See the next few sections on how to control the fetch query mode. If you are only planning to use PostgreSQL\index{PostgreSQL}, you can effectively ignore the sections about Fetch Query modes. However, if you plan to write your application in a database generic sort of way, or support MySQL\index{MySQL} and/or Sybase\index{Sybase} code, then you need to plan for the fetch query modes in your code. \subsection{Fetch Query Modes\label{Fetch Query Modes}} Due to the performance limitations of different database engines, APQ provides the application programmer a way to control the fetch\index{fetch} mode used. Package APQ defines the Fetch\_Mode\_Type\index{Fetch\_Mode\_Type} for this purpose: \begin{Code} type Fetch_Mode_Type is ( Sequential_Fetch, -- All databases Random_Fetch, -- PostgreSQL, MySQL, not Sybase yet Cursor_For_Update, -- Sybase Cursor_For_Read_Only -- Sybase ); \end{Code} The last two modes related to cursors will be discussed separately. The application programmer can query the fetch mode that is in effect. The Fetch\-\_Mode\index{Fetch\_Mode} function primitive returns the current state of the Query\-\_Type object: \begin{Code} function Fetch_Mode( Q : Query_Type ) return Fetch_Mode_Type; \end{Code} To change the current mode in effect, use the function primitive Set\_Fetch\_Mode\index{Set\_Fetch\_Mode}: \begin{Code} procedure Set_Fetch_Mode( Q : in out Query_Type; Mode : in Fetch_Mode_Type ); \end{Code} The application should only change the query mode \emph{prior} to the \emph{execution} of the query. When Execute\index{Execute} or Execute\_Checked\index{Execute\_Checked} are called, APQ must commit to the fetch method being used. For this reason, set the query mode when the Query\_Type is initially declared, after a call to Reset\index{Reset} or Prepare\index{Prepare}. The mode must be established prior to executing the query. Table \ref{t:sfmdx} lists the exceptions that may be raised by Set\_Fetch\_Mode. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Failed & Query results exist - cannot change mode\\ \end{tabular} \end{center} \caption{Set\_Fetch\_Mode Exceptions}\label{t:sfmdx} \end{table} \subsection{Sequential Fetch} The \emph{Query\_Type} object is always positioned at the first row\index{first row} after the query has been executed. Sequential fetches\index{fetches} can then be performed to retrieve the first row, through to the last resulting row. The sequential \textbf{Fetch} primitive has the following calling arguments: \begin{Code} procedure Fetch( Q : in out Query_Type ); \end{Code} A sequential fetch can always be made, whether the query object is in sequential or random mode. However, be aware that some databases (MySQL\index{MySQL}) require that all results be fetched when in Sequential\_Fetch\index{Sequential\_Fetch} mode. The APQ default varies according to the database software being used. See \Ref{Fetch Query Modes} to establish a mode explicitly. Table \ref{t:fchx} lists the exceptions that can be raised by Fetch. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no command executed\\ No\_Tuple & There were no result rows returned\\ Not\_Supported & The fetch mode in effect is not supported\\ \end{tabular} \end{center} \caption{Fetch Exceptions}\label{t:fchx} \end{table} The No\_Result\index{No\_Result} exception is raised when the Query\_Type object is in the wrong\index{wrong state} state. For example, if the Query\_Type object is cleared, and/or an SQL query is built but not Executed, then a No\_Result exception will be raised. The No\_Tuple\index{No\_Tuple} exception is raised to indicate that no rows were available, or that there are no more rows remaining. In Sequential\_Fetch mode, this indicates that there are no more rows to be returned. In Random\_Fetch\index{Random\_Fetch} mode, this indicates that no rows were returned.% \footnote{Note that requesting a non existant row in random fetch mode will not raise an exception until a value is extracted.% } The Not\_Supported\index{Not\_Supported} exception is also possible with APQ \apqversion and later. This exception is raised to indicate that the database software being used does not support the current Fetch\_Mode\index{Fetch\_Mode} that is in effect. The following code shows a normal sequential fetch loop:\label{Sequential Fetch Example} \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when APQ.No_Tuple => exit; end; ... end loop; Clear(Q); -- Release any query results \end{Example} Clearing the query (or allowing it to fall out of scope) is recommended. This releases\index{releases} resources\index{resources} that are holding any prior query results. \subsection{Random Fetch} The random fetch\index{fetch} operation requires the use of the Tuple\_Index\_Type\index{Tuple\_Index\_Type} defined in the package APQ: \begin{Code} type Tuple_Index_Type is mod 2 ** 64; First_Tuple_Index : constant Tuple_Index_Type := 1; \end{Code} The random Fetch primitive has the following calling arguments: \begin{Code} procedure Fetch( Q : in out Query_Type; TX : in Tuple_Index_Type ); \end{Code} Table \ref{t:rfchx} lists the possible exceptions for a random Fetch call. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no command executed\\ No\_Tuple & There were no result rows returned\\ Not\_Supported & Random access is not supported\\ \end{tabular} \end{center} \caption{Random Fetch Exceptions}\label{t:rfchx} \end{table} A random fetch example is provided below:\label{Random Fetch Example} \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); for TX in 1..Tuple_Index_Type(Tuples(Q)) loop Fetch(Q,TX); ... end loop; Clear(Q); \end{Example} The function Tuples(Q)\index{Tuples} that was used in the \emph{for} loop, returns the number of result rows for the query.% \footnote{Which can be zero.% } A slight modification of this loop could permit processing the rows in reverse order. \subsubsection{Notes:} \begin{enumerate} \item If the tuple\index{tuple} index \emph{TX} provided to Fetch is out of range for the result set, no exception will be raised. An exception \emph{will} be raised however, when the application attempts to fetch any value from that out of range row. \item Any subsequent sequential fetch operation will fetch the row following the last randomly accessed row. \end{enumerate} \subsection{Function End\_of\_Query\label{End_of_Query}} To facilitate sequential fetch operations, the End\_of\_Query primitive function was provided in early versions of APQ. This API remains, but is considered \emph{obsolete} and should be avoided. MySQL\index{MySQL} users should not use it at all, due to the bug\index{bug} present in the MySQL client library. See the note that follows the tables. \begin{quote} Note: This function is depreciated. Catch the No\_Tuple exception instead for greater database portability. \end{quote} The calling requirements are summarized in the following specification: \begin{Code} function End_of_Query( Q : Query_Type ) return Boolean; \end{Code} Table \ref{t:eoqx} lists the exceptions for this function. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no command executed\\ \end{tabular} \end{center} \caption{End\_of\_Query Exceptions}\label{t:eoqx} \end{table} The End\_of\_Query\index{End\_of\_Query} function returns a Boolean\index{Boolean} result: \begin{description} \item [False] there is at least one more result row available (not at end) \item [True] there are no more rows\index{rows} available (at end) \end{description} \begin{quote} MySQL Note: The MySQL\index{MySQL} implementation of End\_Of\_Query is not a good one. End\_Of\_Query\index{End\_of\_Query} should \emph{not} be used. The problem is located in the MySQL C client library that comes with MySQL. The C mysql\_eof()\index{mysql\_eof()} function returns false after reading the last row. It is only by fetching one more row and discovering that there are no more rows, that mysql\_eof() then starts to return true. In other words, it returns true, when the end has already been reached. Since there is no way to work around this problem in MySQL, a developer should avoid using End\_Of\_Query completely. \end{quote} Catch the exception No\_Tuple\index{No\_Tuple} instead, when fetching rows. \subsection{Function Tuple} The Tuple\index{Tuple} function primitive is an information function that returns the current tuple number\index{tuple number} that was last fetched. If there has been no fetch yet, the No\_Tuple\index{No\_Tuple} exception is raised. The calling signature is as follows: \begin{Code} function Tuple( Q : Query_Type ) return Tuple_Index_Type; \end{Code} Tuple can raise the exceptions listed in Table~\ref{t:tupx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Tuple & There was no fetch performed yet\\ \end{tabular} \end{center} \caption{Tuple Exceptions}\label{t:tupx} \end{table} The following example shows the function being used: \begin{Example} declare C : Connection_Type; Q : Query_Type; X : Tuple_Index_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when APQ.No_Tuple => exit; end; TX := Tuple(Q); -- Get Row # ... end loop; Clear(Q); \end{Example} \subsection{Rewind Procedure} Sometimes it is desireable to reprocess results sequentially. This is easily accomplished with the Rewind\index{Rewind} primitive. This primitive merely alters the state of the Query\_Type object such that the next fetch\index{fetch} operation will start with the first row. This only works when the fetch mode is Random\_Fetch\index{Random\_Fetch}. The calling requirements are listed as follows: \begin{Code} procedure Rewind( Q : in out Query_Type ); \end{Code} Table \ref{t:rwx} lists the possible exceptions for Rewind. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline SQL\_Error & The Query\_Type is not in Random\_Fetch mode\\ \end{tabular} \end{center} \caption{Rewind Exceptions}\label{t:rwx} \end{table} The following example shows the Rewind procedure being used: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when APQ.No_Tuple => exit; end; ... end loop; -- REPROCESS THE QUERY RESULTS : Rewind(Q); loop begin Fetch(Q); exception when APQ.No_Tuple => exit; end; ... end loop; Clear(Q); \end{Example} \subsection{Tuples Function} You have already seen this function used in the example on page \pageref{Random Fetch Example}. This information function returns the number of result rows that are available. It should only be called after the \emph{Query\_Type} has been executed however. Otherwise the No\_Result exception will be raised by Tuples\index{Tuples}. The calling requirement for this function is summarized as follows: \begin{Code} function Tuples( Q : Query_Type ) return Tuple_Count_Type; \end{Code} Tuples can raise the exceptions listed in Table~\ref{t:tupsx}. For an example of use, see \Ref{Random Fetch Example}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed yet\\ \end{tabular} \end{center} \caption{Tuples Exceptions}\label{t:tupsx} \end{table} \subsection{Using Cursors} For databases supporting cursor\index{cursor} operations in their client\index{client libraries} libraries (Sybase), APQ will automatically generate cursor names for each Query\_Type object. The function Cursor\_Name\index{Cursor\_Name} will retrieve this for you (see \Ref{Cursor_Name}). To perform cursor operations, there are the following general steps to follow: \begin{enumerate} \item Set the cursor mode of the Query\_Type object. \item Prepare the SQL query to fetch rows. \item Execute the SQL query. \item Fetch a row. \item Prepare the inner SQL query using ``WHERE CURRENT OF''\index{WHERE CURRENT OF} \item Execute the inner query \item Repeat steps 4-6 as required \end{enumerate} Describing cursor operation in APQ is probably best done with a concrete example. Assume a simple SALARIES table like the one below: \begin{SQL} CREATE TABLE SALARIES ( EMPNO INT NOT NULL PRIMARY KEY, SALARY REAL NOT NULL ); \end{SQL} Our example, will assume the following values in the table: \begin{SQL} select * from salaries go empno salary ----------- -------------------- 2 56000.000000 3 82800.000000 4 82500.000000 5 43600.000000 4 rows affected 1> \end{SQL} Our application is tasked with the job of rewarding all employees with salaries greater than or equal to \$50,000 with an increase of 5\% (life is often unfair). It is possible to construct an SQL\index{SQL} statement to do this without using cursors but we're going to build the shell of a program that will be required to get approval from the user (using a GUI\index{GUI} etc.) Getting user approval is not possible in SQL, so we need to code a fetch loop and an inner query to do the update if the approval is granted. This is one example of how a cursor can be useful. The following is a Sybase\index{Sybase} APQ program listing for the update:\label{Cursor Example Program} \begin{Example} with Ada.Text _IO; with APQ.Sybase.Client; use APQ, APQ.Sybase.Client, Ada.Text_IO; procedure Salaries is function Value is new Integer_Value(Integer); function Value is new Float_Value(APQ_Double); procedure Append is new Append_Float(APQ_Double); C : Connection_Type; Q : Query_Type; Q2 : Query_Type; Empno : Integer; Salary : APQ_Double; begin Set_Instance(C,"SYBIL"); Set_DB_Name(C,"wwg"); Set_User_Password(C,"wwg","somepw"); Connect(C); Begin_Work(Q,C); Set_Fetch_Mode(Q,Cursor_For_Update); Prepare(Q, "SELECT EMPNO,SALARY"); Append_Line(Q,"FROM SALARIES"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; Empno := Value(Q,1); Salary := Value(Q,2); Put_Line("Empno=" & Empno'Img & " Salary=" & Salary'Img); if Salary >= 50_000.0 then Salary := Salary * 1.05; -- 5% raise Prepare(Q2, "UPDATE SALARIES"); Append(Q2, "SET SALARY = "); Append(Q2,Salary,Line_Feed); Append_Line(Q2,"WHERE CURRENT OF " & Cursor_Name(Q)); Execute(Q2,C); Clear(Q2); end if; end loop; Clear(Q); Commit_Work(Q,C); Disconnect(C); end Salaries; \end{Example} The fetch mode of query object Q is set to Cursor\_For\_Update\index{Cursor\_For\_Update}. This is critical for the cursor\index{cursor} operation to work (you can also use Cursor\_For\_Read\_Only for non-update operations). The outer query\index{outer query} is formed, which is then executed. When the program decides it wants to update a particular row (here we pretend the user has approved it from the terminal), we prepare and execute the inner query\index{inner query} Q2. The special WHERE clause ``WHERE CURRENT OF''\index{WHERE CURRENT OF} is used, naming the cursor being used from the outer query object Q. The function Cursor\_Name(Q)\index{Cursor\_Name} supplies the cursor name for it. Once the inner query is processed, more outer query rows can be fetched\index{fetched} and processed in like manner. Note that the inner query can also include DELETE\index{DELETE} ... WHERE CURRENT OF\index{WHERE CURRENT OF} operations. Using a cursor\index{cursor} guarantees that when you go to delete the row, that some other external process hasn't deleted it before you have (this avoids experiencing an error). Similarly for updates\index{updates}, if the correct isolation\index{isolation level} level is used, you can be sure that the values in the row have not changed by the time you perform the inner query. \section{Column Information Functions} After a query has been executed, which returns a set of rows, it is sometimes necessary to obtain information\index{information, column} about the columns. Many of the functions make use of the following data type: \begin{Code} type Column_Index_Type is new Postive; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Function Name & Purpose\\ \hline Columns & Return the \# of columns in each row\\ Column\_Name & Return the column name for an index value\\ Column\_Index & Return the index for a column name\\ Column\_Type & Return type information for the column\\ Is\_Null & Test if a column is null\\ \end{tabular} \end{center} \caption{Column Information Functions}\label{t:cif} \end{table} Table \ref{t:cif} lists four column information functions that are available to the application programmer. All of these functions will raise the exception No\_Result\index{No\_Result} if an execute has not been performed successfully on the Query\_Type object. Note that the case of the column name returned will match the SQL case policy for the connection. If the policy is Upper\_Case\index{Upper\_Case}, then column names are returned in uppercase. Other possibilities follow the established case policy\index{case policy}. \subsection{Function Columns} The Columns primitive function returns the number of columns\index{columns} available in each row of the result set. The calling arguments are summarized as follows: \begin{Code} function Columns( Q : Query_Type ) return Natural; \end{Code} The Columns\index{Columns} function may raise the exceptions found in Table~\ref{t:cex}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ \end{tabular} \end{center} \caption{Columns Exceptions}\label{t:cex} \end{table} The following example shows the function at work: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when APQ.No_Tuple => exit; end; for CX in 1..Column_Index_Type(Columns(Q)) loop ...process each column... end loop; end loop; Clear(Q); \end{Example} \subsection{Function Column\_Name} The primitive Column\_Name\index{Column\_Name} returns the name of the column for a particular column index\index{column index} value. The calling requirements are summarized in the following table: \begin{Code} function Column_Name( Query : in Query_Type; Index : in Column_Index_Type ) return String; \end{Code} The Column\_Name function may raise the exceptions listed in Table~\ref{t:cnx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & Bad Column\_Index\_Type value\\ \end{tabular} \end{center} \caption{Column\_Name Exceptions}\label{t:cnx} \end{table} Note that the case of the column name returned will match the SQL case policy for the connection. If the policy is Upper\_Case\index{Upper\_Case}, then column names are returned in uppercase. Other possibilities follow the established case policy\index{case policy}. The following example shows the function in use: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q, "SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; for CX in 1..Column_Index_Type(Columns(Q)) loop Put_Line("Column Name: " & Column_Name(Q,CX)); end loop; end loop; Clear(Q); \end{Example} \subsection{Function Column\_Index} If you have a column name, but want to know the column index value, then the Column\_Index\index{Column\_Index} primitive function can be used. It's calling requirements are as follows: \begin{Code} function Column_Index( Query : in Query_Type; Name : in String ) return Column_Index_Type; \end{Code} The function may raise any of the exceptions listed in Table~\ref{t:cidxx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & Unknown column name\\ \end{tabular} \end{center} \caption{Column\_Index Exceptions}\label{t:cidxx} \end{table} The following rather contrived example shows the Column\_Index function used in the pragma\index{pragma assert} assert statement: \begin{NumberedExample} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM~CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; for CX in 1..Column_Index_Type(Columns(Q)) loop declare Col_Name : String := Column_Name(Q,CX); begin Put_Line("Column Name: " & Col_Name); pragma assert(CX = Column_Index(Col_Name));(*@\label{Ex:pragma}@*) end; end loop; end loop; Clear(Q); \end{NumberedExample} The pragma statement in line~\ref{Ex:pragma} is not necessary, but was included in this example to show how the Column\_Index and the Column\_Name are related. \subsection{Function Column\_Type} \index{Column\_Type}The column type information varies according to the database product being used. The following subsections are specific to the APQ supported database products. \subsubsection{PostgreSQL Type Information} The Column\_Type\index{Column\_Type} primitive is the beginning of type information for the column. This function returns the Row\_ID\_Type\index{Row\_ID\_Type} value that describes the type in the pg\_type\index{pg\_type} PostgreSQL\index{PostgreSQL} table\index{table}. See the PostgreSQL database documentation for more details. The Column\_Type calling signature is as follows: \begin{Code} function Column_Type( Q : in Query_Type; CX : in Column_Index_Type ) return Row_ID_Type; \end{Code} Table \ref{t:ctypx} lists the exceptions that may be raised by Column\_Type. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & Unknown column name\\ \end{tabular} \end{center} \caption{Column\_Type Exceptions}\label{t:ctypx} \end{table} \subsubsection{MySQL Type Information} The field\index{field types} types supported by MySQL\index{MySQL} are defined by APQ\-.MySQL\-.Field\_Type. The programmer may use the Query\_Type primitive APQ\-.MySQL\-.Client\-.Column\_Type to determine the column's type: \begin{Code} function Column_Type( Q : in Query_Type; CX : in Column_Index_Type ) return Field_Type; \end{Code} At the writing of this manual, the values in Table~\ref{t:mysqlftyp} are supported MySQL field (column) type names. \begin{table} \begin{center} \begin{tabular}{ll} Field\_Type & MySQL Datatype\\ \hline FIELD\_TYPE\_DECIMAL & DECIMAL\\ FIELD\_TYPE\_TINY & TINYINT | BOOLEAN\\ FIELD\_TYPE\_SHORT & SMALLINT\\ FIELD\_TYPE\_LONG & INTEGER\\ FIELD\_TYPE\_FLOAT & FLOAT\\ FIELD\_TYPE\_DOUBLE & DOUBLE\\ FIELD\_TYPE\_NULL & BOOLEAN\\ FIELD\_TYPE\_TIMESTAMP & TIMESTAMP\\ FIELD\_TYPE\_LONGLONG & BIGINT\\ FIELD\_TYPE\_INT24 & MEDIUMINT\\ FIELD\_TYPE\_DATE & DATE\\ FIELD\_TYPE\_TIME & TIME\\ FIELD\_TYPE\_DATETIME & DATETIME\\ FIELD\_TYPE\_YEAR & YEAR\\ FIELD\_TYPE\_NEWDATE & ?\\ FIELD\_TYPE\_ENUM & ENUM\\ FIELD\_TYPE\_SET & SET\\ FIELD\_TYPE\_TINY\_BLOB & TINYTEXT | TINYBLOB\\ FIELD\_TYPE\_MEDIUM\_BLOB & MEDIUMTEXT | MEDIUMBLOB\\ FIELD\_TYPE\_LONG\_BLOB & LONGTEXT | LONGBLOB\\ FIELD\_TYPE\_BLOB & TEXT | BLOB\\ FIELD\_TYPE\_VAR\_STRING & VARCHAR(N)\\ FIELD\_TYPE\_STRING & CHAR(N)\\ \end{tabular} \end{center} \caption{MySQL Field Types}\label{t:mysqlftyp} \end{table} APQ does not yet fully support all of MySQL data types. \subsection*{Sybase Type Information} Sybase\index{Sybase} also provides type information: \begin{Code} function Column_Type( Q : in Query_Type; CX : in Column_Index_Type ) return Field_Type; \end{Code} Sybase is capable of returning types listed in the Column\_Type column of Table~\ref{t:sycoltyp}. \begin{table} \begin{center} \begin{tabular}{lll} Column\_Type & Sybase Database Type & APQ Support\\ \hline Type\_CHAR & CHAR/VARCHAR & Yes\\ Type\_BINARY & BINARY/VARBINARY & No\\ Type\_LONGCHAR & \emph{None} & No\\ Type\_LONGBINARY & \emph{None} & No\\ Type\_TEXT & TEXT & Yes\\ Type\_IMAGE & IMAGE & No\\ Type\_TINYINT & TINYINT & Yes\\ Type\_SMALLINT & SMALLINT & Yes\\ Type\_INT & INT/INTEGER & Yes\\ Type\_REAL & REAL & Yes\\ Type\_FLOAT & FLOAT & Yes\\ Type\_BIT & BIT & Yes\\ Type\_DATETIME & DATETIME & Yes\\ Type\_DATETIME4 & SMALLDATETIME & Yes\\ Type\_MONEY & MONEY & Yes\\ Type\_MONEY4 & SMALLMONEY & Yes\\ Type\_NUMERIC & NUMERIC & Yes\\ Type\_DECIMAL & DECIMAL & Yes\\ Type\_VARCHAR & VARCHAR & Yes\\ Type\_VARBINARY & VARBINARY & No\\ Type\_LONG & LONG & Yes\\ Type\_SENSITIVITY & \emph{None} & No\\ Type\_BOUNDARY & BOUNDARY & No\\ Type\_VOID & \emph{None} & No\\ Type\_USHORT & USHORT & Yes\\ Type\_UNICHAR & UNICHAR/UNIVARCHAR & No\\ Type\_BLOB & BLOB & No\\ Type\_DATE & DATE & Yes\\ \end{tabular} \end{center} \caption{Sybase Column Types}\label{t:sycoltyp} \end{table} \subsection{Is\_Null Function} If a column is capable of returning a NULL\index{NULL} value, it becomes necessary to test for this. The Is\_Null\index{Is\_Null} function calling specification is as follows: \begin{Code} function Is_Null( Q : in Query_Type; CX : in Column_Index_Type ) return Boolean; \end{Code} The Is\_Null function may raise the exceptions listed in Table~\ref{t:isnullx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & Unknown column name\\ \end{tabular} \end{center} \caption{Is\_Null Exceptions}\label{t:isnullx} \end{table} The following example shows how to test if the CUST\_NAME column is null\index{null} or not: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,BIRTH_DATE"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; ... if Is_Null(Q,2) then -- CUST_NAME value is null end if; ... end loop; Clear(Q); \end{Example} \subsection{Column\_Is\_Null Generic Function} If you need to test for null\index{null} using strongly typed indicators\index{indicators}, you may want to instantiate the Column\_Is\_Null\index{Column\_Is\_Null} generic function. The generic parameters are: \begin{Code} generic type Ind_Type is new Boolean; function Column_Is_Null( Q : in Query_Type'Class; CX : in Column_Index_Type ) return Ind_Type; \end{Code} Table~\ref{t:isnullx} lists exceptions that also apply to the Column\_Is\_Null function. %\begin{tabular}{ll} %Exception Name & Reason\\ %\hline %No\_Result & There was no execute performed\\ %No\_Column & No column at index\\ %\end{tabular} The following example illustrates its use: \begin{Example} declare type Cust_Name_Ind_Type is new Boolean; function Is_Null is new Column_Is_Null(Cust_Name_Ind_Type); C : Connection_Type; Q : Query_Type; Cust_Name_Ind : Cust_Name_Ind_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; Cust_Name_Ind := Is_Null(Q,2); if not Cust_Name_Ind then -- Get Cust_Name since it is not null end if; end loop; Clear(Q); \end{Example} \section{Value Fetching Functions\label{Value Fetching Functions}} Once a fetch\index{fetch} operation has been performed, the application needs to retrieve the values for each column from the row. The function primitive Value\index{Value} assumes that the column's value is \emph{not} going to be NULL\index{NULL}. If it should be null however, the exception Null\_Value\index{Null\_Value} is raised. A better set of primitives should be used for columns that may return NULL. See \Ref{Value and Indicator Fetch Procedures}. The following subsections will cover the function primitives for extracting the values for builtin types\index{builtin types}. \subsection{Function Value\label{Standard Value Functions}} The value for a Row\_ID\_Type\index{OID}, string, bit string or Unbounded\_String\index{Unbounded\_String} can be extracted for a column using the Value function primitive. This function should only used for columns that cannot return a NULL \index{NULL}value.% \footnote{If the value is NULL, the exception Null\_Value will be raised.% } The calling requirements for these primitives are the same with different return types: \begin{Code} function Value( Query : in Query_Type; CX : in Column_Index_Type ) return Row_ID_Type; \end{Code} \begin{Code} function Value( Query : in Query_Type; CX : in Column_Index_Type ) return String; \end{Code} \begin{Code} function Value( Query : in Query_Type; CX : in Column_Index_Type ) return Ada.Strings.Unbounded.Unbounded_String; \end{Code} \begin{Code} function Value( Query : in Query_Type; CX : in Column_Index_Type ) return APQ_Bitstring; \end{Code} Table \ref{t:valx} lists the possible exceptions for these functions. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ Null\_Value & The column's value is NULL\\ \end{tabular} \end{center} \caption{Value Exceptions}\label{t:valx} \end{table} The following example shows how all the column values are fetched: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; for CX in 1..Column_Index_Type(Columns(Q)) loop declare Col_Value : String := Value(Q,CX); begin Put("Column"); Put(Column_Index_Type'Image(CX)); Put(" = '"); Put(Value(Q,CX)); Put_Line("'"); end; end loop; end loop; Clear(Q); \end{Example} \subsection{Null\_Oid Function\label{Null_Oid Function}} Since different database engines have different approaches to row ID values% \footnote{MySQL for example, does not return row ID values.% }, it is necessary to know how to represent a null row ID\index{row ID} value in the current database context. Use the Null\_Oid\index{Null\_Oid} primitive to obtain that value: \begin{Code} function Null_Oid( Query : Query_Type ) return Row_ID_Type; \end{Code} \begin{floatingtable}{ \begin{tabular}{lc} Database & Value\\ \hline PostgreSQL & 0\\ MySQL & 0\\ Sybase & 0\\ \end{tabular}} \caption{Null Oid Values by Product}\label{t:nulloid} \end{floatingtable} Using the Null\_Oid function in generic database code allows helps to eliminate the need to identify the database engine being used. Table~\ref{t:nulloid} lists the numeric values that represent a null OID (row ID) value. The application programmer should rely of the function Null\_Oid to avoid hardcoding a numeric value that might change in the future. \subsection{Generic Value Functions} The Value functions documented in \Ref{Standard Value Functions} were suitable for the specific data types that they supported. However, Ada programmers often derive distinct new types to prevent accidental mixing of values in expressions. To accomodate all of these custom data types, you need to use generic functions for the purpose: \begin{Code} generic type Val_Type is new Boolean; function Boolean_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is range <>; function Integer_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is mod <>; function Modular_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is digits <>; function Float_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is delta <>; function Fixed_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is delta <> digits <>; function Decimal_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is new APQ_Date; function Date_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is new APQ_Time; function Time_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; function Timestamp_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return Val_Type; \end{Code} Table \ref{t:gvalx} lists the exceptions possible for these instantiated routines. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ Null\_Value & The column's value is NULL\\ \end{tabular} \end{center} \caption{Generic Value Exceptions}\label{t:gvalx} \end{table} The following example illustrates the use of the Integer\_Value and Date\_Value generic functions: \begin{Example} declare type Cust_No_Type is new APQ_Integer; type Cust_Birthday_Type is new APQ_Date; function Value is new Integer_Value(Cust_No_Type); function Value is new Date_Value(Cust_Birthday_Type); C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,BIRTH_DATE"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; declare Cust_Name : String := Value(Q,2); Cust_No : Cust_No_Type; Birthday : Cust_Birthday_Type; begin Cust_No := Value(Q,1); -- CUST_NO is col 1 Birthday := Value(Q,3); -- BIRTH_DATE is col 3 ... end; end loop; Clear(Q); \end{Example} In the example shown, \emph{Cust\_Name} is returned by the builtin function Value for String types. The variables \emph{Cust\_No} and \emph{Birthday} are assigned through the generic instantiations of the functions Integer\_Value\index{Integer\_Value} and Date\_Value\index{Date\_Value} respectively. \subsection{Fixed Length String Value Procedure} Sometimes in an application it is desireable to work with fixed\index{fixed length} length string\index{string} values. The following Value\index{Value} procedure does just this: \begin{Code} procedure Value( Query: in Query_Type; CX : in Column_Index_Type; V : out String ); \end{Code} This function raises the exceptions listed in Table~\ref{t:fxflsx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ Null\_Value & The column's value is null\\ \end{tabular} \end{center} \caption{Fixed Length String Value Exceptions}\label{t:fxflsx} \end{table} The following example extracts the CUST\_NAME column result into variable \emph{Cust\_Name} as a 30 byte string value: \begin{Example} declare C : Connection_Type; Q : Query_Type; Cust_Name : String(1..30); begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q,"FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; ... Value(Q,2,Cust_Name); ... end loop; Clear(Q); \end{Example} \subsection{Bounded\_Value Function} Bounded\index{bounded strings} strings require a separate instantiation of Ada\-.Strings\-.Bounded\index{Ada.Strings.Bounded} for each string length. For this reason, a function supporting bounded strings must be provided in generic form. The Bounded\_Value\index{Bounded\_Value} generic function accepts the following generic arguments: \begin{Code} generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); function Bounded_Value( Query : in Query_Type'Class; CX : in Column_Index_Type ) return P.Bounded_String; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ Null\_Value & The column's value is null\\ \end{tabular} \end{center} \caption{Bounded\_Value Exceptions}\label{t:bvx} \end{table} Table \ref{t:bvx} lists the exceptions possible for Bounded\_Value. The example below illustrates the use of Bounded\_Value: \begin{Example} with Ada.Strings.Bounded; declare package B30 is new Ada.Strings.Bounded.Generic_Bounded_Length(30); function Value is new Bounded_Value(B30); C : Connection_Type; Q : Query_Type; Cust_Name : B30; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,BIRTH_DATE"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => end; ... Cust_Name := Value(Q,2); ... end loop; end loop; Clear(Q); \end{Example} \section{Value and Indicator Fetch Procedures\label{Value and Indicator Fetch Procedures}} The Value\index{Value} functions\index{value functions} presented in \Ref{Value Fetching Functions} were useful when the returned value was always going to be present. However, their use becomes clumsy and less efficient if exception handlers must be used to handle the NULL\index{NULL} value case. This section documents Fetch procedures to return both a value and a null indicator together. With this convenience comes the added responsibility of checking the null indicator\index{indicator} values, that are returned. \subsection{Char and Unbounded Fetch} The Char\_Fetch and Unbounded\_Fetch generic procedures fetch both a string value and an indicator value. In the Char\_Fetch case, the returned value is blank filled to the full size of the receiving String buffer. Each of these has the following instantiation parameters: \begin{Code} generic type Ind_Type is new Boolean; procedure Char_Fetch( Query : in Query_Type'Class; CX : in Column_Index_Type; V : out String; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Ind_Type is new Boolean; procedure Unbounded_Fetch( Query : in Query_Type'Class; CX : in Column_Index_Type; V : out Ada.Strings.Unbounded.Unbounded_String; Indicator : out Ind_Type ); \end{Code} The Unbounded\_Fetch routine may raise any of the exceptions listed in Table~\ref{t:ufx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ \end{tabular} \end{center} \caption{Unbounded\_Fetch Exceptions}\label{t:ufx} \end{table} The following example illustrates two different column fetch applications: \begin{Example} with Ada.Strings.Unbounded; declare type Cust_Name_Ind_Type is new Boolean; type Cust_City_Ind_Type is new Boolean; subtype Cust_Name_Type is String(1..30); subtype Cust_City_Type is Ada.Strings.Unbounded.Unbounded_String; procedure Value is new Char_Fetch(Cust_Name_Ind_Type); procedure Value is new Unbounded_Fetch(Cust_City_Ind_Type); C : Connection_Type; Q : Query_Type; Cust_Name : Cust_Name_Type; Cust_Name_Ind : Cust_Name_Ind_Type; Cust_City : Cust_City_Type; Cust_City_Ind : Cust_City_Ind_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,CITY"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => end; ... Value(Q,2,Cust_Name,Cust_Name_Ind); Value(Q,3,Cust_City,Cust_City_Ind); ... end loop; Clear(Q); \end{Example} \subsection{Varchar\_Fetch and Bitstring\_Fetch Procedures} To return a varying length string\index{varying length string} requires the use of a function. However, to return two values, we must resort to a procedure call for the purpose. In order to return both a varying length string and a null indicator, an additional return value is returned that indicates the length of the string. To accomodate strongly typed indicators\index{indicators}, these two procedures are provided in generic form. The instantiation parameters are: \begin{Code} generic type Ind_Type is new Boolean; procedure Varchar_Fetch( Query : in Query_Type'Class; CX : in Column_Index_Type; V : out String; Last : out Natural; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Ind_Type is new Boolean; procedure Bitstring_Fetch( Query : in Query_Type'Class; CX : in Column_Index_Type; V : out APQ_Bitstring; Last : out Natural; Indicator : out Ind_Type ); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ \end{tabular} \end{center} \caption{Bitstring\_Fetch Exceptions}\label{t:bfx} \end{table} Table \ref{t:bfx} lists the exceptions for Bitstring\_Fetch. The next example illustrates two different column fetch applications: \begin{Example} declare type Cust_Name_Ind_Type is new Boolean; type Cust_City_Ind_Type is new Boolean; procedure Value is new Varchar_Fetch(Cust_Name_Ind_Type); procedure Value is new Varchar_Fetch(Cust_City_Ind_Type); C : Connection_Type; Q : Query_Type; Cust_Name : String(1..30); Cust_Name_Last : Natural; Cust_Name_Ind : Cust_Name_Ind_Type; Cust_City : String(1..40); Cust_City_Last : Natural; Cust_City_Ind : Cust_City_Ind_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,CITY"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; ... Value(Q,2,Cust_Name,Cust_Name_Last,Cust_Name_Ind); Value(Q,3,Cust_City,Cust_City_Last,Cust_City_Ind); ... end loop; Clear(Q); \end{Example} After the first Value call in the example, the customer name would be represented by the expression: \begin{Code} Cust_Name(1..Cust_Name_Last) \end{Code} provided that the value Cust\_Name\_Ind was false. \subsection{Bounded\_Fetch Procedure} To fetch both a Bounded\_String value and its associated null\index{null indicator} indicator, you instantiate and call the Bounded\_Fetch\index{Bounded\_Fetch}. The instantiation parameters are as follows: \begin{Code} generic type Ind is new Boolean; with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Bounded_Fetch( Query : in Query_Type'Class; CX : in Column_Index_Type; V : out P.Bounded_String; Indicator : out Ind); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ \end{tabular} \end{center} \caption{Bounded\_Fetch Exceptions}\label{t:bfx2} \end{table} The Bounded\_Fetch routine may raise any of the exceptions listed in Table~\ref{t:bfx2}. The example below illustrates a fetch instantiation and call: \begin{Example} with Ada.Strings.Bounded; declare package B32 is new Ada.Strings.Bounded.Generic_Bounded_Length(32); type Cust_Name_Ind_Type is new Boolean; procedure Value is new Bounded_Fetch(Cust_Name_Ind_Type,B32); C : Connection_Type; Q : Query_Type; Cust_Name : B32; Cust_Name_Ind : Cust_Name_Ind_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; ... Value(Q,2,Cust_Name,Cust_Name_Ind); ... end loop; Clear(Q); \end{Example} \subsection{Discrete Type Fetch Procedures} Several of the discrete\index{discrete types} types can be grouped and documented in this section. The following table indicates the generic procedure names and their associated class of data type for which they are designed: \begin{Code} generic type Val_Type is new Boolean; type Ind_Type is new Boolean; procedure Boolean_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is range <>; type Ind_Type is new Boolean; procedure Integer_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is mod <>; type Ind_Type is new Boolean; procedure Modular_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is digits <>; type Ind_Type is new Boolean; procedure Float_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is delta <>; type Ind_Type is new Boolean; procedure Fixed_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is delta <> digits <>; type Ind_Type is new Boolean; procedure Decimal_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; type Ind_Type is new Boolean; procedure Date_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Day_Duration; type Ind_Type is new Boolean; procedure Time_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; type Ind_Type is new Boolean; procedure Timestamp_Fetch( Query : in Root_Query_Type'Class; CX : in Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type ); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & There was no execute performed\\ No\_Column & No column at index\\ \end{tabular} \end{center} \caption{Timestamp\_Fetch Exceptions}\label{t:tfx2} \end{table} The Timestamp\_Fetch exceptions are listed in Table~\ref{t:tfx2}. The following example illustrates how to instantiate and call a Integer\_Fetch procedure. \begin{Example} declare type Cust_No_Type is new Integer; type Cust_No_Ind_Type is new Boolean; procedure Value is new Integer_Fetch (Cust_No_Type,Cust_No_Ind_Type); C : Connection_Type; Q : Query_Type; Cust_No : Cust_No_Type; Cust_No_Ind : Cust_No_Ind_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME"); Append(Q, "FROM CUSTOMER"); Execute(Q,C); loop begin Fetch(Q); exception when No_Tuple => exit; end; ... Value(Q,1,Cust_No,Cust_No_Ind); ... end loop; Clear(Q); \end{Example} \section{Information Functions} You have already seen two information functions Result\index{Result} and Error\_Message\index{Error\_Message} in \Ref{Error Message Reporting} and \Ref{Error Status Reporting}. Another useful Query\_Type primitive is the To\_String\index{To\_String} function. It is described in the next subsection. \subsection{The To\_String Function} The To\_String\index{To\_String} primitive allows the caller to retrieve the collected SQL text from the Query\_Type object. The function's calling signature is as follows: \begin{Code} function To_String( Query : Query_Type ) return String; \end{Code} The To\_String function returns the full text of the SQL query, including newline characters.% \footnote{One is included at the end of the string if it is missing.% } If there has not been any SQL text\index{SQL text} collected, the function returns an empty string.% \footnote{In this case, no newline is provided.% } The following example shows how a programmer can dump out the SQL\index{SQL} query, but only when it fails: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT CUST_NO,CUST_NAME,BIRTH_DATE"); Append(Q, "FROM CUSTOMER"); begin Execute(Q,C); exception when SQL_Error => Put_Line("The failed SQL Query was:"); Put_Line(To_String(Q)); raise; when others => raise; end; \end{Example} \subsection{Cursor Names\label{Cursor_Name}} While PostgreSQL\index{PostgreSQL} and MySQL\index{MySQL} do not yet support cursors\index{cursors} in their client libraries \footnote{PostgreSQL supports server cursors, but cursor support is absent in libpq.}, other database products like Sybase\index{Sybase} do. Cursors allow the programmer to work with the concept of a ``current row''\index{current row}. For those databases that do support the use of cursors, you can retrieve the cursor name\index{cursor name} with the use of the Cursor\_Name\index{Cursor\_Name} function primitive: \begin{Code} function Cursor_Name( Query : Query_Type ) return String; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline No\_Result & No cursor results pending\\ \end{tabular} \end{center} \caption{Cursor\_Name Exceptions}\label{t:cnamx} \end{table} The Cursor\_Name exceptions are documented in Table~\ref{t:cnamx}. To use cursors within APQ, you must set the fetch mode of the Query\_Type to one of the following: \begin{itemize} \item Cursor\_For\_Update\index{Cursor\_For\_Update} \item Cursor\_For\_Read\_Only\index{Cursor\_For\_Read\_Only} \end{itemize} Once you have set the fetch mode to one of the cursor fetch modes listed above, and you have executed the query to produce cursor results, \emph{then} the call to Cursor\_Name is valid. For a description of fetch query modes in \Ref{Fetch Query Modes}. \chapter{Blob Support} The MySQL\index{MySQL} database provides a very different type of blob support\index{blob support}. For the moment, blobs are unsupported in MySQL. Blob support is also absent for Sybase\index{Sybase}. These are two areas ripe for further work in APQ. Blobs are supported for PostgreSQL\index{PostgreSQL} in APQ however. This provides the application programmer with the ability to store large amounts of information in a ``blob''\index{blob}. In many ways this resembles a file\index{file}, with the exception that the contents are stored in the database and is accessed by number (OID\index{OID}). The APQ binding provides full PostgreSQL blob support for the Ada programmer. In addition, the Ada\index{Ada} stream\index{stream} concept is employed to provide reliable and Ada2005\index{Ada2005} convenient access to the blob. \subsubsection{Endian Note:} The application programmer must keep in mind that any binary data written to a blob, by means of the Ada stream, is not endian\index{endian} neutral. This becomes a concern when a client application accesses or writes to blobs stored on a database over the network, on another host. If the endianess of the server and client differ, endian problems will emerge. \section{Introduction} Blob functions are managed primarily through the Blob\_Type\index{Blob\_Type} access type.% \footnote{The object itself is of type Blob\_Object. Blob\_Type is an access to Blob\_Object type.% } Stream I/O to and from the blob is performed using an Ada streams access value.% \footnote{Internally named Root\_Stream\_Access type, which is the type ''access all Ada.Streams.Root\_Stream\_Type'Class''.% } The blob support can generally be grouped into the following categories: \begin{itemize} \item Create, Open and Close operations \item Index setting and querying operations \item Information operations for Size and OID \item Stream accessor\index{stream accessor} function \item Blob destruction\index{blob destruction} \item File and Blob operations \end{itemize} The following sections will document the blob support using these groupings. \section{Blob Memory Leak Prevention} \index{memory leak prevention}It is extremely important that the programmer realize that the Blob\_Type data type is an access type.% \footnote{This design choice was necessary to accomodate Ada stream oriented I/O.% } Additionally this access\index{access value} value is a pointer\index{pointer} to a dynamically\index{dynamic} allocated tagged\index{tagged} record (type Blob\_Object). For this reason, the programmer must take great care to ``close'' the Blob\_Type before discarding the Blob\_Type value, when it goes out of scope. Failure to close a Blob\_Type value, will result in a memory leak\index{memory leak} and cause subsequent database performance issues. Use the Blob\_Type value as if it were an open file that needs closing. The following example represents a ``Blob\_Type leak'': \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; begin ... B := Blob_Create(C'Access); ... end; \end{Example} The example above is bad because a ``blob leak''\index{blob leak} occurs when the ``end'' statement is reached.% \footnote{It should also be noted that after creating a blob in the database, the application must save the OID value for the blob somewhere. Otherwise, you will have a blob in the database that will never be accessed!% } The variable \emph{C} finalizes itself OK because it is a controled object.% \footnote{Both Connection\_Type and Query\_Type objects are controlled records with finalization.% } However, B is an access type, pointing to a Blob\_Object record. When variable B falls out of scope, only the pointer value in B is lost. The object it pointed to has not been released! The following example code is better: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; begin ... B := Blob_Create(C'Access); ... Blob_Close(B); end; \end{Example} The call to Blob\_Close\index{Blob\_Close} insures that the memory associated with the opened blob is released, before the value \emph{B} falls out of scope.% \footnote{Note that Close does not destroy the blob in the database.% } However, if there is a chance that an exception may be raised, you may still be vulnerable to leaks. The following example covers all of the bases: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; begin ... B := Blob_Create(C'Access); ... Blob_Close(B); exception when others => if B /= null then Blob_Close(B); end if; ...recovery steps... end; \end{Example} While the recovery steps have been left to the reader's imagination in the example above, the exception is caught and the value for variable \emph{B} is tested. Only if \emph{B} is not null, should the Blob\_Close procedure call made. Only you can prevent blob memory leaks! \section{Create, Open and Close of Blobs} The most basic operations possible in an Ada program using blobs are: \begin{itemize} \item Creating a new blob in the database (Blob\_Create) \item Opening an existing blob in the database (Blob\_Open) \item Flushing buffered writes to the database (Blob\_Flush) \item Closing a blob (Blob\_Close) \end{itemize} The following subsections will explain how to perform these operations in detail. \subsection{Blob\_Create Procedure} Before the application can open an existing blob\index{opening a blob}, there must be some way to create a blob\index{creating a blob}. The Blob\_Create\index{Blob\_Create} function does just this with the following calling signature:% \marginpar{Note: Blob operations must be performed within the context of a transaction.% } \begin{Code} function Blob_Create( DB : access Connection_Type; Buf_Size : in Natural := Buf_Size_Default ) return Blob_Type; \end{Code} The returned value is a Blob\_Type that is capable of being used to read and/or write a blob. The blob is positioned at index position 1 (the beginning). See \Ref{Blob OID Function} for information about how to determine the created blob's OID\index{OID}. Starting with APQ version 1.2, all blob I/O is buffered if the Buf\_Size argument is supplied with a value greater than zero, or is not supplied such that the default value applies. Table~\ref{t:bcbsgx} summarizes the Buf\_Size\index{Buf\_Size} argument behaviour. The exceptions are listed in Table~\ref{t:blbcx}. \begin{table} \begin{center} \begin{tabular}{lll} Buf\_Size Value & Description & Performance\\ \hline 0 & Unbuffered blob I/O & Very poor\\ 0 < Buf\_Size < 1024 & Buffered & Poor\\ 1024 <= Buf\_Size < Buf\_Size\_Default & Buffered blob I/O & Better\\ Buf\_Size\_Default & Buffered: 5120 bytes & Very good\\ \end{tabular} \end{center} \caption{Blob\_Create Buf\_Size Guidelines}\label{t:bcbsgx} \end{table} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & There was no blob created\\ \end{tabular} \end{center} \caption{Blob\_Create Exceptions}\label{t:blbcx} \end{table} Possible reasons for a Blob\_Error\index{Blob\_Error} exception to be raised would include: \begin{itemize} \item bad database connection object% \footnote{Or the database connection object went out of scope.} \item a database error occurred (no more blob space?) \end{itemize} The following example shows how a new blob can be created: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; begin ... B := Blob_Create(C'Access); ... Blob_Close(B); end; \end{Example} \subsubsection{Note:} The argument DB in the call to the Blob\_Create\index{Blob\_Create}, is an access to Connection\_Type argument. You must guarantee that the Connection\_Type object does not finalize before the created blob has been closed. \subsection{Blob\_Open Function\label{Blob_Open Function}} To open an existing blob\index{existing blob}, you must know the OID\index{OID} of the blob in the database. This is normally a value that is stored in a database column somewhere. See \Ref{Blob OID Function} for information on how to determine the OID of a created blob.% \marginpar{Note: Blob operations must be performed within the context of a transaction.% } Blobs can be opened for various types of access: \begin{description} \item [Read\index{Read}] for readonly access to the blob contents \item [Write\index{Write}] for writing to the blob \item [Read\_Write\index{Write}] for both reading and writing of the blob \end{description} The Blob\_Open\index{Blob\_Open} function has the following specification: \begin{Code} type Mode_Type is ( Write, Read, Read_Write ); function Blob_Open( DB : access Connection_Type; Oid : in Row_ID_Type; Mode : in Mode_Type; Buf_Size : in Natural := Buf_Size_Default ) return Blob_Type; \end{Code} The returned value is a Blob\_Type that is accessable according to the Mode selected. The blob is positioned\index{blob position} at index value 1 (the beginning). Starting with APQ version 1.2, all blob I/O is buffered\index{buffered blob I/O} if the Buf\_Size argument is supplied with a value greater than zero, or is not supplied such that the default value applies. Refer to Table~\ref{t:bcbsgx} for guidance on the value to use for Buf\_Size. The exceptions are documented in Table~\ref{t:bopnx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & There was no blob opened\\ \end{tabular} \end{center} \caption{Blob\_Open Exceptions}\label{t:bopnx} \end{table} Possible reasons for a Blob\_Error exception to be raised would include: \begin{itemize} \item bad database connection object \item the Oid value supplied is not known by the database \item a database error occurred \end{itemize} The following example shows how blob 73763 can be opened for reading: \label{Example-code-with-OID-73763} \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; OID : Row_ID_Type := 73763; begin ... B := Blob_Open(C'Access,OID,Read); ... Blob_Close(B); exception when others => if B /= null then Blob_Close(B); end if; raise; end; \end{Example} \subsubsection{Note:} The argument DB in the call to the Blob\_Open, is an access to Connection\_Type argument. You must guarantee that the Connection\_Type object does not finalize\index{finalize} before the opened blob has been closed. \subsubsection{Generic\_Blob\_Open Function} To allow the application programmer to use strong types in place of the supplied Row\_ID\_Type\index{Row\_ID\_Type} type, a generic procedure for opening blobs is also provided. The instantiated function behaves exactly as described for Blob\_Open\index{Open\_Blob} on page \pageref{Blob_Open Function}. The instantiation arguments for Generic\_Blob\_Open\index{Generic\_Blob\_Open} are: \begin{Code} type Mode_Type is ( Write, Read, Read_Write ); generic type Oid_Type is new Row_ID_Type; function Generic_Blob_Open( DB : access Connection_Type; Oid : in Oid_Type; Mode : in Mode_Type; Buf_Size : in Natural := Buf_Size_Default ) return Blob_Type; \end{Code} The following example shows how to instantiate the function: \begin{Example} declare type My_Oid_Type is new Row_ID_Type; function Blob_Open is new Generic_Blob_Open(My_Oid_Type); \end{Example} \subsection{Blob\_Flush Procedure} \index{Blob\_Flush}When you are using buffered\index{buffered blob I/O} blob I/O% \footnote{Buffered blob I/O is the default for performance reasons.% } and your application has performed one or more writes to the blob, you may need to be certain that all of the buffered data is physically written out to the database. For example, you may have a timing\index{timing} opportunity to perform this expensive operation while the user is waiting for something else to occur. Buffer flushes\index{flush} are automatically performed when the blob is closed or due to changes made by the Blob\_Set\_Index\index{Blob\_Set\_Index} operation. To give the application programmer control over the timing of the physical write to the database, the Blob\_Flush\index{Blob\_Flush} procedure can be used.% \marginpar{Blob\_Flush calls are ignored when unbuffered blob I/O is being used. This makes it easy for the application to choose buffered or unbuffered operation without source code changes.} The Blob\_Flush procedure has the specification below. Table~\ref{tblbflx} lists the exceptions. \begin{Code} procedure Blob_Flush(Blob : Blob_Type); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & The blob is not open\\ \end{tabular} \end{center} \caption{Blob\_Flush Exceptions}\label{t:blbflx} \end{table} \subsection{Blob\_Close Procedure} When the programmer no longer requires access to a open/created blob, the procedure Blob\_Close\index{Blob\_Close} should be called. Since an open blob depends upon a hidden access value that points back to the Connection\_Type object, the programmer should call Blob\_Close as soon as is practical. This reduces the possibility of error that will occur if the Connection\_Type object is finalized too soon. The Blob\_Close procedure has the following specification. Exceptions are listed in Table~\ref{t:bclsx}. \begin{Code} procedure Blob_Close(Blob : in out Blob_Type); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & The blob is not open\\ \end{tabular} \end{center} \caption{Blob\_Close Exceptions}\label{t:bclsx} \end{table} Normally the Blob\_Error\index{Blob\_Error} exception will indicate an attempt to close a blob that is not open. However, it is possible that the database engine may experience a problem that will raise the same exception. The procedure Blob\_Close will also null out the the Blob\_Type value that was passed in. This is done to eliminate any accidental access to a Blob\_Object that no longer exists. \section{Index Setting Operations} Like a file, a blob's ``position''\index{position of a blob} can be changed and queried. The index\index{index} operations require the use of two types defined for the purpose. They are: \begin{Code} type Blob_Count is new Ada.Streams.Stream_Element_Offset range 0..Ada.Streams.Stream_Element_Offset'Last; \end{Code} \begin{Code} subtype Blob_Offset is Blob_Count range 1..Blob_Count'Last; \end{Code} The type Blob\_Count\index{Blob\_Count} is used where there is a count involved (which may require the value zero). The type Blob\_Offset\index{Blob\_Offset} is used whenever a blob offset is used, since it starts at the value 1. The next subsections describe facilities for performing blob indexing operations. \subsection{Blob\_Set\_Index Procedure} The Blob\_Set\_Index\index{Blob\_Set\_Index} procedure is used when the caller needs to seek to a new position within the opened blob. See \Ref{Blob Size Function} if you need to know the size of the blob. The calling requirements for Blob\_Set\_Index are summarized below (exceptions in Table~\ref{t:blbsxx}). \begin{Code} procedure Blob_Set_Index ( Blob : in Blob_Type; To : in Blob_Offset ); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open or seek failed\\ \end{tabular} \end{center} \caption{Blob\_Set\_Index Exceptions}\label{t:blbsxx} \end{table} The following example shows how to seek to the end of the blob: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; B_Size : Blob_Count; End_Blob : Blob_Index; begin ... B_Size := Blob_Size(B); if B_Size > 0 then End_Blob := B_Size; Blob_Set_Index(B,End_Blob); ... \end{Example} \section{Blob\_Index Function} Applications sometimes need to query where they are positioned in the blob. The Blob\_Index\index{Blob\_Index} function returns the current Blob\_Offset\index{Blob\_Offset} position\index{position} information. The specification is shown below, while the exceptions are listed in Table~\ref{t:blbxx}. \begin{Code} function Blob_Index( Blob : in Blob_Type ) return Blob_Offset; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open\\ \end{tabular} \end{center} \caption{Blob\_Index Exceptions}\label{t:blbxx} \end{table} The following example code determines where in the presently opened blob the blob position index is: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; Pos_Blob : Blob_Index; begin ... Pos_Blob := Blob_Index(B); \end{Example} \section{Information Functions} The following subsections describe information gathering functions. They provide the programmer a way to obtain size\index{size} and identification\index{identification} information. \subsection{Blob Size Function\label{Blob Size Function}} To determine the present size\index{blob size} of a blob, the Blob\_Size\index{Blob\_Size} function can be used. Table~\ref{t:blbszx} documents the exceptions while the specification is listed as follows: \begin{Code} function Blob_Size( Blob : in Blob_Type ) return Blob_Count; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open\\ \end{tabular} \end{center} \caption{Blob\_Size Exceptions}\label{t:blbszx} \end{table} Notice that the return type Blob\_Count\index{Blob\_Count} does permit the value zero to be returned (blob is empty). The following example code determines the size of the presently opened blob: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; Blob_Size : Blob_Count; begin ... Blob_Size := Blob_Size(B); \end{Example} \subsection{Blob\_OID Function\label{Blob OID Function}} After a blob is created, it is very necessary to determine the OID\index{OID} for the blob. The Blob\_Oid function may be called after Blob\_Create\index{Blob\_Create} or Blob\_Open\index{Blob\_Open} to obtain OID information. Table~\ref{t:blboidx} lists the exceptions and the specification is shown below: \begin{Code} function Blob_Oid( Blob : in Blob_Type ) return Row_ID_Type; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open\\ \end{tabular} \end{center} \caption{Blob\_OID Exceptions}\label{t:blboidx} \end{table} The following example code determines the OID\index{OID} value for the newly created blob\index{blob}: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; Blob_OID : Row_ID_Type; begin ... B := Blob_Create(C'Access); Blob_OID := Blob_Oid(B); \end{Example} \subsubsection{Generic\_Blob\_Oid Function} To use a strongly typed version of the Blob\_Oid\index{Blob\_Oid} function, the application programmer can instantiate from Generic\_Blob\_Oid. The instantiated function otherwise behaves exactly as the Blob\_Oid function on page \pageref{Blob OID Function}. The instantiation parameters for Generic\_Blob\_Oid\index{Generic\_Blob\_Oid} are: \begin{Code} generic type Oid_Type is new Row_ID_Type; function Generic_Blob_Oid( Blob : in Blob_Type ) return Oid_Type; \end{Code} The following example shows how to instantiate the function: \begin{Example} declare type My_Oid_Type is new Row_ID_Type; function Blob_Oid is new Generic_Blob_Oid(My_Oid_Type); \end{Example} \subsection{End\_Of\_Blob Function} The End\_Of\_Blob\index{End\_Of\_Blob} function can be used by programs that sequentially read through a blob. The calling signature for this function is given below:% \marginpar{Note that this function results in poor performance if the buffer size is set to zero (unbuffered) in the opening Blob\_Open/Blob\_Create calls.% } \begin{Code} function End_of_Blob( Blob : in Blob_Type ) return Boolean; \end{Code} The return value is True if the current position in the blob is at the end of the blob. Otherwise the value False is returned. Table~\ref{teoblbx} lists the possible exceptions. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open\\ \end{tabular} \end{center} \caption{End\_of\_Blob Exceptions}\label{t:eoblbx} \end{table} The following example code reads a series of strings from the blob, using the End\_Of\_Blob function: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; begin ... B := Blob_Open(...); declare S : Root_Stream_Access := Blob_Stream(B); begin while not End_Of_Blob(B) loop declare Line : String := String'Input(S); begin Put_Line(Line); end; end loop; end; Blob_Close(B); \end{Example} \section{Stream Access} In order for an Ada program to perform stream I/O\index{stream I/O} on a blob, you must obtain a useable stream pointer\index{stream pointer}. The APQ binding defines a type named Root\_Stream\_Access\index{Root\_Stream\_Access} for this purpose. It is defined as follows: \begin{Code} type Root_Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; \end{Code} The function Blob\_Stream\index{Blob\_Stream} returns this stream pointer to the caller. Use of this returned pointer makes it possible to use the native Ada\index{Ada} stream\index{stream I/O} I/O facilities. The function Blob\_Stream is specified below while Table~\ref{t:blbstrx} documents the exceptions possible. \begin{Code} function Blob_Stream( Blob : in Blob_Type ) return Root_Stream_Access; \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Not open\\ \end{tabular} \end{center} \caption{Blob\_Stream Exceptions}\label{t:blbstrx} \end{table} The following example shows how a blob is created, a stream access value is obtained, and a APQ\_Timestamp\index{APQ\_Timestamp} value is written to the new blob: \begin{Example} declare C : aliased Connection_Type; B : Blob_Type; Str : Root_Stream_Access; Some_Date : APQ_Timestamp; begin ... B := Blob_Create(C'Access); declare Str : Root_Stream_Access := Blob_Stream(B); begin APQ_Timestamp'Write(Str,Some_Date); ... end; Blob_Close(B); end; \end{Example} Notice in this example, that the declaration and the existance of the stream pointer Str was restricted as much as possible. While not strictly necessary, there are good reasons for following this practice. See the special following note for the details. \subsubsection{Note:} The programmer does not have to worry about ``closing'' or freeing\index{freeing} the returned stream pointer (Str in the example). It can be nulled or left to fall out of scope. Only the type Blob\_Type must be ``closed'' by calling Blob\_Close\index{Blob\_Close}. The programmer must however be careful to never use the stream\index{stream pointer} pointer after the blob has been closed, or after the connection object has been closed or finalized\index{finalized}. The stream pointer should be nulled\index{nulled} when it has outlived its usefulness, or allowed to fall out of scope. \section{Blob Destruction} To release a blob\index{releasing a blob}, you must use the Blob\_Unlink\index{Blob\_Unlink} procedure call. Table~\ref{t:blbunlkx} lists the exceptions while the specification is shown below: \begin{Code} procedure Blob_Unlink( DB : in Connection_Type; Oid : in Row_ID_Type ); \end{Code} \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & No such Oid\\ \end{tabular} \end{center} \caption{Blob\_Unlink Exceptions}\label{t:blbunlkx} \end{table} The following code releases the blob referenced in the example on page \pageref{Example-code-with-OID-73763}. \begin{Example} declare C : aliased Connection_Type; Oid : Row_ID_Type := 73763; begin ... Blob_Unlink(C,Oid); \end{Example} \subsubsection{Generic\_Blob\_Unlink Procedure} To use a strongly typed version of the Blob\_Unlink procedure, the application programmer can instantiate from Generic\_Blob\_Unlink\index{Generic\_Blob\_Unlink}. The instantiated function otherwise behaves exactly as the Blob\_Unlink function. The instantiation parameters for Generic\_Blob\_Unlink are: \begin{Code} generic type Oid_Type is new Row_ID_Type; procedure Generic_Blob_Unlink( DB : in Connection_Type; Oid : in Oid_Type ); \end{Code} The following example shows how to instantiate the function: \begin{Example} declare type My_Oid_Type is new Row_ID_Type; procedure Blob_Unlink is new Generic_Blob_Unlink(My_Oid_Type); \end{Example} \section{File and Blob Operations} Blobs are very similar to files\index{files}. It should be no surprise then that sometimes a file is imported\index{imported} into a blob, or exported\index{exported} from a blob. A file is imported into a blob with the Blob\_Import\index{Blob\_Import} call: \begin{Code} procedure Blob_Import( DB : in Connection_Type; Pathname : in String; Oid : out Row_ID_Type ); \end{Code} Blob\_Import returns the Oid of the newly created blob, that now contains a copy of the file specified by the Pathname argument. A blob's contents can be written out (exported) to a file with a call to Blob\_Export\index{Blob\_Export}: \begin{Code} procedure Blob_Export( DB : in Connection_Type; Oid : in Row_ID_Type; Pathname : in String ); \end{Code} After a successful return from Blob\_Export, the file named by the Pathname argument, contains a copy of the specified blob. If any error in these import/export operations occur, the exceptions listed in Table~\ref{t:blbxpx} occur. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Blob\_Error & Import/export failed\\ \end{tabular} \end{center} \caption{Blob\_Export Exceptions}\label{t:blbxpx} \end{table} Note that Blob\_Import creates a new blob if necessary. Blob\_Export creates a new file if necessary. \subsubsection{Generic\_Blob\_Import and Generic\_Blob\_Export Procedures} To use strongly typed versions of the Blob\_Import and Blob\_Export, the application programmer can instantiate from Generic\_Blob\_Import\index{Generic\_Blob\_Import} and Generic\_Blob\_Export\index{Generic\_Blob\_Export} respectively. The instantiated procedure otherwise behaves exactly as the Blob\_Import or Blob\_Export function. The instantiation parameters for Generic\_Blob\_Import or Generic\_Blob\_Export are: \begin{Code} generic type Oid_Type is new Row_ID_Type; procedure Generic_Blob_Import( DB : in Connection_Type; Pathname : in String; Oid : out Oid_Type ); \end{Code} \begin{Code} generic type Oid_Type is new Row_ID_Type; procedure Generic_Blob_Export( DB : in Connection_Type; Oid : in Oid_Type; Pathname : in String ); \end{Code} The following example shows how to instantiate the function: \begin{Example} declare type My_Oid_Type is new Row_ID_Type; procedure Blob_Import is new Generic_Blob_Import(My_Oid_Type); \end{Example} \chapter{Utility Functions} % Chapter 5 \section{To\_String Support} To ease the job for programming, a number of builtin To\_String\index{To\_String} functions are provided to allow conversion from the data type to its string representation. The following To\_String functions are available with the following builtin types (only one function requires a second argument): \begin{Code} function To_String( V : APQ_Boolean ) return String; \end{Code} \begin{Code} function To_String( V : APQ_Date ) return String; \end{Code} \begin{Code} function To_String( V : APQ_Time ) return String; \end{Code} \begin{Code} function To_String( V : APQ_Timestamp ) return String; \end{Code} \begin{Code} function To_String( V : APQ_Bitstring ) return String; \end{Code} The following illustrates one example: \begin{Example} declare Ship_Date : APQ_Date; begin Put({ Put_Line(To_String(Ship_Date)); \end{Example} \section{Generic To\_String Support} Programs that make use of distinct types will require the use of generic functions to perform To\_String\index{generic To\_String} conversions. The following generic functions are available for instantiation: \begin{Code} generic type Val_Type is new Boolean; function Boolean_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is range <>; function Integer_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is mod <>; function Modular_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is delta <>; function Fixed_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is digits <>; function Float_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is delta <> digits <>; function Decimal_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; function Date_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Day_Duration; function Time_String( V : Val_Type ) return String; \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; function Timestamp_String( V : Val_Type ) return String; \end{Code} The following example illustrates their use: \begin{Example} declare type My_Date_Type is new APQ_Timestamp; function To_String is new Timestamp_String(My_Date_Type); Execution_Date : My_Date_Type; begin ... Put("Program Execution Date: "); Put_Line(To_String(Execution_Date)); \end{Example} \section{Conversion Generic Functions} Sometimes a programmer must convert from a text format string into another data type for manipulation. Several generic conversion \index{conversion functions} functions are provided for the purpose (exceptions listed in Table~\ref{t:cvtx}): \begin{Code} generic type Val_Type is new Boolean; function Convert_To_Boolean( S : String ) return Val_Type; \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; function Convert_To_Date( S : String ) return Val_Type; -- YYYY-MM-DD format \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Day_Duration; function Convert_To_Time( S : String ) return Val_Type; -- HH:MM:SS format \end{Code} \begin{Code} generic type Val_Type is new Ada.Calendar.Time; function Convert_To_Timestamp( S : String; TZ: Ada.Calendar.Time_Zones.Time_Offset := 0 ) return Val_Type; -- HH:MM:SS format \end{Code} As for time and timestamp conversions, these are generic implementations that in fact uses the ones provided by the \emph{Ada.Calendar.Formatting} package. They are provided to enforce strong typing whenever desired and also for backwards compatibility.\\ \textbf{Convert\_to\_Date} was removed to enforce the use of Timestamps. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Invalid\_Format & The input value was not a proper value for the type\\ \end{tabular} \end{center} \caption{Conversion Exceptions}\label{t:cvtx} \end{table} The following example illustrates some converions: \begin{Example} declare type Bool is new APQ_Boolean; type Birth_Date_Type is new APQ_Date; function To_Boolean is new Convert_To_Boolean(Bool); function To_Date is new Convert_To_Date(Birth_Date_Type); My_Bool : Bool; Elvis : Birth_Date_Type; begin ... My_Bool := To_Boolean("T"); -- valid values are 1/t/true and 0/f/false Elvis := To_Timestamp("1957-01-08 00:00:00"); -- UTC \end{Example} \section{The Convert\_Date\_and\_Time Generic Function} Sometimes the programmer needs the convenience of putting separate date and time values together into a returned timestamp\index{timestamp} value. For example the date of birth may be stored in one database column\index{column}, while the time of birth is stored in another. It may be necessary to work with a timestamp value instead, that contains both of these components. To permit the use of strongly typed values\index{strongly typed values}, a generic function is provided for this purpose. The generic specification for Convert\_Date\_and\_Time\index{Convert\_Date\_and\_Time} is: \begin{Code} generic type Date_Type is new Ada.Calendar.Time; type Time_Type is new Ada.Calendar.Day_Duration; type Result_Type is new Ada.Calendar.Time; function Convert_Date_and_Time( DT : Date_Type; TM : Time_Type ) return Result_Type; \end{Code} The following example shows how to apply this function: \begin{Example} declare type My_Date_Type is new APQ_Date; type My_Time_Type is new APQ_Time; type My_Timestamp_Type is new APQ_Timestamp; function To_Timestamp is new Convert_Date_and_Time( Date_Type => My_Date_Type, Time_Time => My_Time_Type, Result_Type => My_Timestamp_Type); Some_Date : My_Date_Type; Some_Time : My_Time_Type; Some_Timestamp : My_Timestamp_Type; begin ... Some_Timestamp := To_Timestamp(Some_Date,Some_Time); \end{Example} \chapter{Calendar Functions} There is frequently the need in applications to separate out the hour\index{hour}, minute\index{minute} and second\index{second} from a time\index{time} value. To make this easier, and to permit the continued use of strong typing, the following generic functions are available:% \footnote{It could be argued that these generic functions do not go the full generic distance, because the return value types are standard types only (types Hour\_Number, Minute\_Number and Second\_Number).% } \begin{Code} generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Hour( TM : Time_Type ) return Hour_Number; -- local time zone is assumed \end{Code} \begin{Code} generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Minute( TM : Time_Type ) return Minute_Number; \end{Code} \begin{Code} generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Second( TM : Time_Type ) return Second_Number; \end{Code} The following example shows how to apply this procedure: \begin{Example} declare type Evt_Time_Type is new Ada.Calendar.Day_Duration; function Hour is new Generic_Hour(Evt_Time_Type); function Minute is new Generic_Minute(Evt_Time_Type); Evt_Time : Evt_Time_Type; HH : Hour_Number; MM : Minute_Number; begin ... HH := Hour(Evt_Time); MM := Minute(Evt_Time); \end{Example} Notice these generic functions are designed torward the \emph{Day\_Duration} type and thus there is no conflict with the ones available at \emph{Ada.Calendar.Formatting} standard package. \chapter{Decimal Support} In order to support accurate number calculations, particularly for financial work, the package APQ\-.PostgreSQL\-.Decimal\index{APQ.PostgreSQL.Decimal} is available for the programmer to use. This package is based upon the C source\index{C source} code extracted out of the PostgreSQL server.% \footnote{Portions copyright (c) 1996-2001, The PostgreSQL Global Development Group, and portions copyright (c) 1994, The Regents of the University of California.% } The decimal support\index{decimal support} is \emph{not} a floating point\index{floating point} package, but does support approximately 1,000 digits worth of accuracy\index{accuracy}. Note that this is currently PostgreSQL\index{PostgreSQL} specific code, and as such, it has not been reworked for general use in databases like MySQL\index{MySQL}. \section{Introduction} The APQ\-.PostgreSQL\-.Decimal package is a binding to the extracted server decimal code. This gives the Ada programmer access to the same numeric support\index{numeric support} as used by the database engine to sum columns etc. Because it is decimal\index{decimal} based, you will not have to worry about representation issues for values like 0.3,% \footnote{In binary floating point, the value 0.3 must be represented as 0.29999 repeat.} allowing for accurate sums and hash total calculations. \begin{quote} Special Note: The APQ\-.PostgreSQL\-.Decimal package is still under development, and is subject to change. One of the most serious limitations at present is the fact that assignment clobbers any prior concept of precision\index{precision} and scale\index{scale} for the variable being assigned to. To overcome this, it is possible that a future implementation of this package may provide task safe storage to preserve the variable's precision and scale. This can be done by saving the variable's precision and scale in task safe storage at finalization time. When the Adjust primitive is later called, the saved precision and scale can be restored and followed by a call to the Constrain()\index{Constrain} function. This will implicitly keep the variable within its configured precision and scale parameters. \end{quote} \section{Decimal Exceptions} The APQ\-.PostgreSQL\-.Decimal binding can raise any of the exceptions listed in Table~\ref{t:decx}. \begin{table} \begin{center} \begin{tabular}{ll} Exception Name & Reason\\ \hline Decimal\_NaN & The value is ``Not a Number{}`` (or NULL)\\ Decimal\_Format & Input does not represent a decimal number\\ Decimal\_Overflow & Value over/under-flowed\\ Undefined\_Result & Computation does not have a defined result\\ Divide\_By\_Zero & An attempt to divide by zero occurred\\ \end{tabular} \end{center} \caption{Decimal Exceptions}\label{t:decx} \end{table} \section{``Not a Number'' Operations} A new Decimal\_Type\index{Decimal\_Type} value is initialized to NaN\index{NaN} (Not a Number). This is a special status for the value, which can be assigned to other Decimal\_Type values. When this status is detected in an expression where a computation is being performed, the exception Decimal\_NaN\index{Decimal\_NaN exception} is raised to indicate that no valid result can be determined. \section{The Decimal\_Type Type} Decimal values are manipulated in a type, which is defined in terms of a tagged\index{tagged} controlled\index{controlled} record: \begin{Code} type Decimal_Type is new Ada.Finalization.Controlled with private; \end{Code} These values are further defined by the following additional two attributes: \begin{description} \item [Precision] specifies the precision of the decimal variable \item [Scale] specifies the scale of the decimal variable \end{description} \section{Is\_NaN Function} To test if a value is ``Not a Number'', the Is\_NaN\index{Is\_NaN} function can be used: \begin{Code} function Is_Nan( DT : Decimal_Type ) return Boolean; \end{Code} The following example shows how to apply the function: \begin{Example} declare D : Decimal_Type; begin if Is_NaN(D) then Put_Line("D is NaN!"); ... \end{Example} \section{Convert Procedure} To import\index{import} a large decimal value from a String, the programmer may invoke the Convert\index{Convert} procedure: \begin{Code} procedure Convert( DT : in out Decimal_Type; S : in String; Precision : in Precision_Type := 0; Scale : in Scale_Type := 2 ); \end{Code} The arguments \emph{Precision} and \emph{Scale} arguments can be omitted if you can accept the default values of 0 and 2 for the precision and scale respectively. When \emph{Precision} is given as zero, the value has no defined precision, and may grow to whatever size is necessary to carry the result.% \footnote{The source code indicates that the maximum precision is approximately 1,000 decimal digits.} The following example shows how to initialize a Decimal\_Type from a string: \begin{Example} declare D : Decimal_Type; begin Convert(D,"12345.6789",0,4); \end{Example} \section{To\_String Function} To make a Decimal\_Type value printable, you can call upon the To\_String\index{To\_String} function: \begin{Code} function To_String( DT : Decimal_Type ) return String; \end{Code} The To\_String will return the string ``NULL''\index{NULL} if the value is in the ``Not a Number'' state. The following example shows how to use it in a Put\_Line call: \begin{Example} declare D : Decimal_Type; begin ... Put_Line("D := " & To_String(D)); \end{Example} \section{Constrain Function} Sometimes it is desireable to constrain\index{constraining values} a result to a particular precision and scale, while watching for overflows. The Constrain function takes an input value, and returns a new value with the values constrained to the given precision and scale\index{Constrain}: \begin{Code} function Constrain( DT : in Decimal_Type; Precision : in Precision_Type; Scale : in Scale_Type ) return Decimal_Type; \end{Code} The returned value is rounded (if necessary) to accomodate the \emph{Scale}\index{scale} argument. The result must fit within the precision\index{precision} given by the \emph{Precision} argument. The following example illustrates how the function is used: \begin{Example} declare A : Decimal_Type; B : Decimal_Type; begin A := ...some calculation...; B := Constrain(A,10,2); -- Precision 10, Scale 2 \end{Example} \section{Expression Operations} The Decimal\_Type values can be both assigned and computed with the normal set of operators\index{operators} as shown in Table~\ref{t:decopr}. \begin{table} \begin{center} \begin{tabular}{|c|c|} \hline Operator & Description\\ \hline + & Add\\ - & Subtract\\ {*} & Multiply\\ / & Divide\\ unary - & Negate\\ = & Equal\\ < & Less than\\ <= & Less than or equal\\ > & Greater than\\ >= & Greater than or equal\\ \hline \end{tabular} \end{center} \caption{Decimal Operators}\label{t:decopr} \end{table} The following code fragment shows some Decimal\_Type expressions\index{expressions} at work: \begin{Example} declare Watts_per_Hp : Decimal_Type; Watts : Decimal_Type; Volts : Decimal_Type; Amperes : Decimal_Type; Hp : Decimal_Type; begin Convert(Watts_per_Hp,"745.577",0,3); -- Watts/HP Convert(Volts,"120.0",0,1); Convert(Amperes,"7.0",0,1); Watts := Volts * Amperes; -- # of Watts Hp := Watts / Watts_per_Hp; -- # of Horsepower \end{Example} \section{Minimum and Maximum Values} The Min\_Value\index{Min\_Value} and Max\_Value\index{Max\_Value} functions are available to the programmer to conveniently return the minimum\index{minimum} or maximum\index{maximum} value of a pair, respectively. These functions share the following common calling signature: \begin{Code} function Min_Value( Left, Right : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Max_Value( Left, Right : Decimal_Type ) return Decimal_Type; \end{Code} The following example illustrates its use: \begin{Example} declare A, B : Decimal_Type; Smallest : Decimal_Type; begin Smallest := Min_Value(A,B); \end{Example} \section{Abs\_Value, Sign, Ceil and Floor Functions} The functions in the following table are documented in this section\index{Abs\_Value}\index{Sign}\index{Ceil} \index{Floor}: \begin{Code} function Abs_Value( DT : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Sign( DT : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Ceil( DT : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Floor( DT : Decimal_Type ) return Decimal_Type; \end{Code} The following example illustrates its use: \begin{Example} declare A, B : Decimal_Type; Pos_Val : Decimal_Type; begin Pos_Val := Abs_Value(A,B); \end{Example} \section{Sqrt, Exp, Ln and Log10 Functions} The functions in the following table are documented in this section% \index{Sqrt}\index{Exp}\index{Ln}\index{Log10}: \begin{Code} function Sqrt( X : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Exp( X : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Ln( X : Decimal_Type ) return Decimal_Type; \end{Code} \begin{Code} function Log10( X : Decimal_Type ) return Decimal_Type; \end{Code} The following example illustrates its use: \begin{Example} declare X : Decimal_Type; L10 : Decimal_Type; begin L10 := Log10(X); \end{Example} \section{The Log Function} The Log\index{Log} function permits the caller to evaluate a logrithm $\log$ $_{\textrm{base}}$ x . It has the following calling requirements: \begin{Code} function Log( X, Base : Decimal_Type ) return Decimal_Type; \end{Code} The following example illustrates its use: \begin{Example} declare X : Decimal_Type; Base : Decimal_Type; L : Decimal_Type; begin L := Log(X,Base); \end{Example} \section{The Power Function} The Power\index{Power} function permits the caller to evaluate the expression x$^{\textrm{y}}$. The function accepts the following calling arguments: \begin{Code} function Power( X, Y : Decimal_Type ) return Decimal_Type; \end{Code} The following example assigns to \emph{P}, the value x$^{\textrm{y}}$. \begin{Example} declare X : Decimal_Type; Y : Decimal_Type; P : Decimal_Type; begin P := Power(X,Y); \end{Example} \section{The Round and Trunc Functions} To round\index{round} or truncate\index{truncate} a Decimal\_Type value, the application designer may call the Round\index{Round} and Trunc\index{Trunc} functions respectively. They both accept the following calling arguments: \begin{Code} function Round( DT : in Decimal_Type; Scale : in Scale_Type ) return Decimal_Type; \end{Code} \begin{Code} function Trunc( DT : in Decimal_Type; Scale : in Scale_Type ) return Decimal_Type; \end{Code} The following example assigns to \emph{R}, the rounded value of \emph{X}, to 2 decimal places: \begin{Example} declare X : Decimal_Type; R : Decimal_Type; begin R := Round(X,2); \end{Example} \section{Builtin Decimal\_Type Constants} The builtin decimal constants\index{decimal constants} are defined as the following functions% \index{Zero}\index{One}\index{Two}\index{Ten}\index{NaN}: \begin{Code} function Zero return Decimal_Type; function One return Decimal_Type; function Two return Decimal_Type; function Ten return Decimal_Type; function NaN return Decimal_Type; \end{Code} The NaN function can be used to put a value into a ``Not a Number'' state. This doubles as setting the value to NULL\index{NULL}, for SQL query use. \section{Using Decimal\_Types with Query\_Type} Creating SQL\index{SQL} queries using the Decimal\_Type\index{Decimal\_Type} and retrieving values from SQL queries has been made easy for the application programmer. The NaN\index{NaN} state is used to represent a NULL\index{NULL} value. This eliminates the need for the application programmer to define indicator values. The Append procedure allows the programmer to build SQL queries with Decimal\_Type values. The Value\index{Value} function, permits the programmer to retrieve a column value into a Decimal\_Type variable (with or without a NULL\index{NULL} value). \subsection{Using Decimal\_Type with Append} The Append procedure has the following specification: \begin{Code} procedure Append( Query : in out PostgreSQL.Client.Query_Type; DT : in Decimal_Type'Class; After : in String := "" ); \end{Code} \subsection{Fetching Decimal\_Type Values} A decimal value may be retrieved from a SQL query, using the Value function: \begin{Code} function Value( Query : in PostgreSQL.Client.Query_Type; CX : in Column_Index_Type ) return Decimal_Type; \end{Code} If the returned value for the column is NULL\index{NULL}, the value returned will be in the NaN state. The following example illustrates how to apply the Value\index{Value} function: \begin{Example} declare C : Connection_Type; Q : Query_Type; D : Decimal_Type := NaN; begin ... Prepare(Q, "SELECT QTY, ..."); Append_Line("FROM ORDERS"); Execute(Q,C); while not End_of_Query loop Fetch(Q); D := Value(Q,1); -- Fetch Decimal_Type end loop; Clear(Q); \end{Example} \chapter{Generic Database Programming} With APQ 2.0, the support of the MySQL database becomes available. The future may allow APQ to support even more database technologies. With this in mind, it becomes very desireable in some circumstances to write applications in a database neutral way. Within this documentation, we will use the term ``Generic Database Programming'' to describe portable\index{portable} database code. This chapter is about programming for databases generically. Given that APQ is built using object oriented techniques (tagged\index{tagged} Ada2005\index{Ada2005} records), it should be possible to leverage this in a way to write application procedures once, and enjoy the flexibility of choosing or changing the database technology used later. \Ref{Generic APQ.Result} identified one aspect of generic database processing. \section{Generic Connections} For most routine database work, the only object that needs to be defined up front, is the database connection. In APQ version \apqversion and later, there are three concrete choices: \begin{enumerate} \item APQ.PostgreSQL.Client.Connection\_Type \item APQ.MySQL.Client.Connection\_Type \item APQ.Sybase.Client.Connection\_Type \end{enumerate} Once the high level layer of the application chooses one of these connection objects, and establishes a connection with the database, the connection object may be passed around as parameters to procedures. The recommended generic way to do this, is to pass the connection as a APQ\-.Root\_Connection\_Type\-'Class\index{Root\_Connection\_Type'Class} parameter. See the following example: \begin{Example} procedure MyApp(C : in out APQ.Root_Connection_Type'Class) is begin ... \end{Example} The classwide parameter then permits any database connection object to be passed as a parameter. The classwide attribute causes all operations performed upon that object to be dispatching calls. By dispatching on the object's primitives, you ensure that database specific operations are carried out according to the type of database being used. \section{Database Specific Code} Due to the wide differences that sometimes exist between database engines\index{engines}, it is sometimes necessary to take different course of action, depending upon the database being used. For example, PostgreSQL\index{PostgreSQL} allows a varchar(256)\index{varchar} column to be defined, where MySQL\index{MySQL} is limited to varchar(255) instead.% \footnote{MySQL requires you declare the type as TEXT if you need more than 255 characters.% } To determine the database being used, use the Engine\_Of\index{Engine\_Of} predicate\index{predicate} function. This primitive exists on both the Root\_Connection\_Type\index{Root\_Connection\_Type} and Root\_Query\_Type objects. \Ref{Generic Database Engine_Of} and \Ref{Generic APQ.Engine_Of} describe functions and examples for this purpose. Obviously, if you are only given a Root\_Connection\_Type'Class connection argument to use, you cannot know in advance which Query\_Type\index{Query\_Type} object to use. Make use of the New\_Query\index{New\_Query} factory\index{factory} function to create one (See \Ref{Query_Type Factories}) or use cloning\index{cloning} (\Ref{Query_Type Cloning}) if you have an existing Query\_Type object available. \subsection{Row ID Values}\label{Portability Note for Row ID Values} When designing a new system, it is important to plan for the use of row ID\index{row ID} values. MySQL\index{MySQL} does not support them at all, while PostgreSQL\index{PostgreSQL} encourages their use.% \footnote{For example, a blob is identified by a Oid value, which is basically a row ID.% } MySQL encourages the use of serial values instead, which is a good practice. For generic database programming you must plan for these differences to reduce the amount of specialized code. For more information about obtaining row ID values, see the \Ref{Command_Oid Function}, and \Ref{Portability Note for Row ID Values} for portability\index{portability} notes. Additionally, the assumptions about what constitutes a null row ID\index{null row ID} must be scrutinized. Since different databases use different values to represent ``no row'', you should make careful use of the APQ Null\_Oid\index{Null\_Oid} function, rather than depend upon a particular constant. See \Ref{Null_Oid Function} for information about that. \section{Data Types} When writing generic database code it is important to choose your datatypes\index{datatypes} very carefully.\\ A problem exists with PostgreSQL bit string types (APQ\_Bitstring\index{APQ\_Bitstring}). MySQL and Sybase do not support them. So if you want to write portable code, stick to simple data types in your application. \\ When you must make use of special database types, be prepared to specialize the code somewhat, depending upon the database being used.\\ The APQ\_Timezone data type was removed in favour of a more portable way of dealing with timestamps now Ada 2005 supports time zone information. \subsection{Column Types} Another area that is important to consider is the database column \index{column types} types that are chosen for tables. Comparing the table in \Ref{PostgreSQL SQL Data Types} and \Ref{MySQL Data Types}, the reader can see that most columns can be declared in SQL using the same column type declarations. However, there are some important differences. For example, a SERIAL\index{SERIAL} column in PostgreSQL must be declared as an INTEGER\index{INTEGER} type when using MySQL. For most applications, this is not too much of an issue, because applications usually don't create and drop tables. However, this can be an issue with temporary tables.\\ Also it's better to assure the table structure is expecting timestamp values set in UTC in order not to mess things around when updating or moving your server to another time zone.\\ \section{Pulling it All Together} This section will examine a fairly trivial example of a generic database procedure. It will make one exception for MySQL\index{MySQL}, so that the reader will know how to work with database engine\index{engine} differences. Ideally, you would want to avoid differences, where possible. The example is a real world example. A procedure is required to fetch the most recent stock price available on file, for a given security (by ticker symbol). While there may be a price for the security on the given day, if there is not one listed, the procedure is expected to fall back to the most recent price available. The table being consulted, is defined as follows:\label{PRICE_HIST Table Definition} \begin{SQL} CREATE TABLE PRICE_HIST ( SECURITY CHAR(10) NOT NULL, PRICE_DATE DATE NOT NULL, PRICE REAL NOT NULL, PRIMARY KEY(SECURITY,PRICE_DATE) ); \end{SQL} Here is the package spec for the Prices module, which makes the procedure Last\_Price available for use: \begin{Example} with APQ; use APQ; package Prices is procedure Last_Price( C : in out Root_Connection_Type'Class; Security : in String; Price : out APQ_Double ); end Prices; \end{Example} Given any database connection, and a ticker symbol provided in argument Security, the procedure Last\_Price is expected to lookup the most recent stock price in the PRICE\_HIST table and return that price in the Price argument. Here is the body of the package, written to work with any database: \begin{NumberedExample} package body Prices is procedure Last_Price( C : in out Root_Connection_Type'Class;(*@\label{Ex:RootConn}@*) Security : in String; Price : out APQ_Double ) is function Value is new Float_Value(APQ_Double); Q : Root_Query_Type'Class := New_Query(C);(*@\label{Ex:QFact}@*) begin Prepare(Q, "SELECT SECURITY,PRICE_DATE,PRICE"); Append_Line(Q, "FROM PRICE_HIST"); Append(Q, "WHERE SECURITY = "); Append_Quoted(Q,C,Security,Line_Feed); Append_Line(Q, "ORDER BY SECURITY,PRICE_DATE DESC");(*@\label{Ex:OrBy}@*) if Engine_Of(C) = Engine_MySQL then(*@\label{Ex:EngOf}@*) Append_Line(Q,"LIMIT 1");(*@\label{Ex:Limit1_Again}@*) end if; Execute(Q,C); begin Fetch(Q); exception when No_Tuple => raise; -- Indicates no price end; Price := Value(Q,3); end Last_Price; end Prices; \end{NumberedExample} A few notes are in order here: The spec already with's and uses the package APQ. So it is not repeated in the body of the package. The Last\_Price procedure takes a Root\_Connection\_Type'Class (line~\ref{Ex:RootConn} connection object type, so it can be supplied with a MySQL or PostgreSQL database connection\index{connection} (Connection\_Type). The New\_Query factory\index{factory} function (line~\ref{Ex:QFact}) is used to create the correct Query\_Type object necessary to match the connection. It is used to form and execute the query. The Prepare, Append\_line, Append\_Quoted calls build up an SQL query, and then the type of the database is queried by calling Engine\_Of (line \ref{Ex:EngOf}). If the database being used is a MySQL database, the query is optimized \footnote{One could also argue that it is {}``fixed'' here, since MySQL insists that all row results of a query be fetched.} so that only one row is returned by use of the extended SQL ``LIMIT 1''\index{LIMIT} clause (line~\ref{Ex:Limit1_Again}). Note that the ``ORDER BY''\index{ORDER BY} clause in line~\ref{Ex:OrBy} requires that the sort order be descending (most recent dates first). Given that the ``ORDER BY'' clause specifies indexed columns, this retrieval should be quick since a reverse index retrieval is possible (if the database cannot do this, you should create a new index or fix the primary key to be descending). Since we are only interested in the most recent price (ie. one price), only one Fetch call is made. This is not a problem for PostgreSQL, but it is for MySQL if there there are more than one row (see \Ref{Fetch Limitations} to find out why). If the database is MySQL the problem is addressed by adding to the query a MySQL extended clause ``LIMIT 1''\index{LIMIT}, to limit the results to one row (line~\ref{Ex:Limit1_Again}). The price is then fetched from column 3 (PRICE) and the procedure returns. If no rows are returned, we simply raise the APQ.No\_Tuple exception here to keep the example simple. A finished application would handle this in a more elegant way perhaps. The important thing to recognize here is that there is nothing specific to the type of database being used in this Prices package, except for the MySQL work-around. The only APQ package being used is the top level package APQ, and the root types for connection and query types. Here is a PostgreSQL main program: \begin{Example} with Ada.Text_IO; with APQ. with Prices; use APQ, Prices, APQ. procedure Price_PG is C : Connection_Type; P : APQ_Double; begin Set_DB_Name(C,"investments"); Connect(C); Last_Price(C,"RHAT",P); Put_Line("RHAT $" & APQ_Double'Image(P)); Disconnect(C); end Price_PG; \end{Example} Please notice the following points about the main program: \begin{enumerate} \item The database specific package is with'ed as APQ.PostgreSQL.Client here to choose the database connection being used. \item The Connection\_Type object is declared in APQ.PostgreSQL.Client and derives from APQ.Root\_Connection\_Type. \item The database is chosen and a connection is established. \item The Last\_Price procedure is called, providing only the connection and the security's ticker symbol that the price is being sought for. \item The returned price P is then printed (albeit crudely) \item The application disconnects from the server and exits. \end{enumerate} The same main program using MySQL looks like this: \begin{Example} with Ada.Text_IO; with APQ. with Prices; use APQ, Prices, APQ. procedure Price_My is C : Connection_Type; P : APQ_Double; begin Set_DB_Name(C,"investments"); Connect(C); Last_Price(C,"RHAT",P); Put_Line("RHAT $" & APQ_Double'Image(P)); Disconnect(C); end Price_My; \end{Example} The only difference between this MySQL\index{MySQL} main program and the prior PostgreSQL\index{PostgreSQL} main program, is the name of the package used (APQ\-.MySQL\-.Client). APQ truly is the closest thing to database independance! \section{Miscellaneous Portability Issues} There are a number of other database portability issues that should be born in mind. An incomplete list has begun in this document below: \begin{itemize} \item temporary tables creation \item SELECT ... INTO TABLE ... \end{itemize} This list will grow with submissions and experience. \footnote{Contributions are welcome.} \subsection{Temporary Tables\label{Creating Temp Tables}} Many databases allow the SQL programmer to create a temporary\index{temporary tables} table prior to its use in the application. This temporary table is only visible to the user of the established database connection. When the database connection is closed or disconnected, the temporary table is automatically discarded and its space recycled by the database engine. The difficulty that a generic database programmer needs to be aware of is that some databases work differently. Normally, an application would perform something like the following to create a temporary table in the database session that required it: \begin{SQL} CREATE TEMP TABLE INTERMED_RESULTS ( SECURITY CHAR(10) NOT NULL, HOLDINGS BIGINT NOT NULL ); \end{SQL} Subsequent to the successful creation\index{create temp table} of this temporary table, the application would populate it and use it as necessary. The application may even create indexes on the table after the table is populated, to help performance in later stages of the table's use. While this works for PostgreSQL\index{PostgreSQL} and MySQL\index{MySQL}, the generic programmer should be aware that this will not work on an Oracle\index{Oracle} database (when APQ gets there some day). Oracle permits the same syntax, but operates differently: Oracle only permits one CREATE TEMP TABLE\index{CREATE TEMP TABLE} operation to be performed, in the same way that a permanent table is created. Once created, the user implicitly gets access to the table upon demand. Upon the first reference to the temporary table in a particular session, you get a temporary table created, which is empty. You then populate and use that temporary table without ever having to create it within that particular session. When the session is over, the table's contents are discarded. So how do you plan for this? If the Engine\_Of\index{Engine\_Of} function indicates Engine\_Oracle\index{Engine\_Oracle}, you must \emph{not} create the temporary table during your database session. This will be done when the permanent tables are created.% \footnote{In many respects, this is perhaps the best time to declare and plan for a temporary table.% } For other database engines, you should create the temporary table when you are about to use them in your application. Perhaps the most sensible thing for temporary tables is to isolate much of that work to stored\index{stored procedures} procedures. Your program can then just invoke the stored procedure in a portable fashion. \subsubsection{Indexes on Temporary Tables} There is an additional piece of advice to consider when creating indexes for temporary tables. For performance reasons, it is often best to populate the temp table with no indexes\index{indexes} created. After the table has been populated, indexes can then be efficiently added and dropped as the needs arise. In the Oracle case, these indexes are likely to be predefined as is the declaration of the temporary table itself. So when creating indexes for temporary tables, you should also probably test for Oracle in the generic code. When using Oracle, you probably do \emph{not} want to create or drop the index\index{index, create/drop}, as it will probably affect all users of that temporary table definition.% \footnote{The author has not verified this point, but the reader is encouraged to do so.% } \subsection{SELECT ... INTO TABLE} A number of database engines support a SQL syntax along the lines of: \label{SelectIntoTempTable} \begin{SQL} SELECT * FROM MY_TABLE WHERE ... INTO TEMP TABLE TEMP123 \end{SQL} The above SQL code performs the usual SELECT\index{SELECT INTO TEMP}, but places its results into a temporary table named TEMP123. \footnote{One application framework that the author is familiar with used a suffix of ``123'' to denote the name of a temporary table.} Alternatively, databases will also often permit: \begin{SQL} SELECT * FROM MY_TABLE WHERE ... INTO TABLE RESULTS \end{SQL} This query places the results into a permanent table named RESULTS (note that the keyword TEMP was dropped). Both of these operations are very convenient for processing intermediate results. However, database engines vary in their support. Neither of these formats are supported by PostgreSQL or MySQL, but they are supported by INFORMIX. The SQL-99\index{SQL-99} way to perform this operation is specified as follows: \begin{SQL} INSERT INTO RESULTS SELECT * FROM MY_TABLE WHERE ... \end{SQL} This syntax is supported by both PostgreSQL\index{PostgreSQL} and MySQL\index{MySQL} for permanent tables. There is no provision currently to create a temporary table on the fly with syntax shown on page \pageref{SelectIntoTempTable} using PostgreSQL or MySQL. So even SQL-99 syntax won't help you there. You can only create a temporary table, and then use the INSERT INTO\index{INSERT INTO} ... SELECT syntax after the temporary table is created. But don't forget the limitation in \Ref{Creating Temp Tables}. \chapter{Troubleshooting} There are several problems\index{problems} that can crop up in applications using the APQ Binding. These problems usually fall into one of the following categories: \begin{itemize} \item PostgreSQL database server ``personality'' \item The PostgreSQL libpq C library interface \item The MySQL client library \item Sybase libraries and/or interfaces file \item The APQ binding itself \end{itemize} The APQ Binding attempts to insulate the user as much as is practical from the client library issues and the database server. However, some issues still manage to poke through. This chapter is an attempt to provide some useful advice for those people that are encountering unexpected behaviour, using the APQ Binding. \section{General Problems} The following subsections provide general troubleshooting help with APQ binding issues. \subsection{Missing Rows After Inserts (PostgreSQL)} The first step in identifying whether this section applies or not, is to ask: \begin{itemize} \item is a transaction\index{transaction} processing being used? \item or, is a transaction pending when it shouldn't be? \end{itemize} If the second bullet applies to you, then you need to correct the logic in your program (but read on to find out why). On the other hand, if you are purposely using transactions (first case) and you are losing\index{losing rows} inserted row information, then it is likely that you are suffering from an aborted transaction in PostgreSQL\index{PostgreSQL} (this is PostgreSQL specific). It might also represent an APQ binding bug\index{bug}, but check first to make sure that you have not put PostgreSQL into an ``abort state''\index{abort state} (ie. in a snit). This is unusal database behavior, but the PostgreSQL group seems to be proud of it. The APQ Binding should prevent aborted\index{aborted transactions} transactions from being left unnoticed.% \footnote{If however, the Abort\_State\index{Abort\_State} exception is never being raised, then it is possible you have a PostgreSQL porting issue. If the PostgreSQL notice message format changes, the APQ binding code will fail to recognize the notification of an ``abort state'' from the database server.% } When the database server notificaties the APQ binding that an {}``abort state'' has been entered% \footnote{After a duplicate key on insert error, for example.% }, any further attempts to execute SQL queries or COMMIT WORK\index{COMMIT WORK} on that connection, will raise the Abort\_State exception for PostgreSQL (see also \Ref{In_Abort_State Function} and \Ref{Abort_State exception}). One common reason this happens is when an application inserts\index{insert of rows} rows into a table, and intercepts the SQL\_Error\index{SQL\_Error} exception. This exception is caught because the application writer wants to ignore the insert on a duplicate\index{duplicate key insert} key error. The difficulty here is that the PostgreSQL database engine will enter an ``abort state'' after the failed INSERT\index{INSERT} operation, regardless of how the application handles the exception. The only recourse to recovery at this point is to rollback the transaction with a call to Rollback\_Work (\Ref{Begin, Commit and Rollback Work functions}). This brings up a question about the APQ Binding. Why doesn't the APQ binding raise Abort\_State immediately after the failed INSERT\index{INSERT} operation within a transaction? There are two reasons: \begin{enumerate} \item The ``Abort State'' notice is provided to the APQ binding in the form of a callback. \item Processing SQL\_Error exception within a transaction implies an aborted transaction (for PostgreSQL only). \end{enumerate} Notices are received by the APQ binding by registering a callback with the database server. As a result, it is not always possible to know about the ``abort state''\index{abort state} when it might be critical to the application. Even if the information is available, this may not always be so in future versions of PostgreSQL\index{PostgreSQL} (timing may change). The very fact that you've started a transaction with Begin\_Work and you have encountered an SQL\_Error exception should tell you that you must Rollback\_Work and recover (remember this is only for PostgreSQL). So as the developer, you should be thinking: $Abort\, State=Begin\, Work+SQL\, Error$ The APQ binding has been designed to avoid several SQL statements from being executed and being ignored because the database server is in this ``Abort State''. This is why the Execute and Commit\_Work calls check for this and raise the Abort\_State\index{Abort\_State} exception. However, the best advice is to not rely on this mechanism when programming the logic of your application. \subsection{Missing Time Data (Or Time is 00:00:00)} You build a query to insert or update a row with date and time\index{time} information, but only the date\index{date} is getting stored in the database. The time component always reads midnight\index{midnight} (00:00:00). Or perhaps you provide a date and timestamp as part of a WHERE\index{WHERE clause} clause, but it fails because only the date value is being put into the query (the time component always shows as midnight). You print out the variables using To\_String and they show the correct values, as follows: \begin{Example} declare type My_Date_Type is new APQ_Timestamp; My_Date : My_Date_Type; begin ... Put_Line( "My_Date='" & To_String(APQ_Timestamp(My_Date)) & "'" ); \end{Example} The above symptoms are the result of a common problem. This human error is easy to make and is due to choosing the incorrect generic procedure. Look for a generic instantiation statement like the following: \begin{Code} procedure Append is new Append_Date(My_Date_Type); \end{Code} If your data type My\_Date\_Type holds time information, then it is likely that you meant to code the following instead: \begin{Code} procedure~Append is new Append_Timestamp(My_Date_Type); \end{Code} The error was choosing generic procedure Append\_Date\index{Append\_Date} over the correct Append\_Timestamp\index{Append\_Timestamp} routine. A similar mistake can be made choosing between Encode\_Date\index{Encode\_Date} and Encode\_Timestamp\index{Encode\_Timestamp} generic procedures. So watch for these subtle differences! \subsection{Exception No\_Tuple} If you are having the exception No\_Tuple\index{No\_Tuple} being raised when you don't think it should be, then check to see if the following apply: \begin{itemize} \item Are you using MySQL\index{MySQL}? \item Do you use the End\_of\_Query\index{End\_of\_Query} function calls? \end{itemize} If you do, then you need to look for any code calling End\_of\_Query, particularly loops: \begin{Example} while not End_of_Query(Q) loop Fetch(Q); ... end loop; \end{Example} This type of code works well for PostgreSQL\index{PostgreSQL}, but may be problematic with some other databases (MySQL has a problem with this). Restructure your code to eliminate the calls to End\_of\_Query (this call is now considered \emph{obsolete} within APQ). \Ref{End_of_Query} describes the problem in greater detail. Restructure the loop to something like the following: \begin{Example} loop begin Fetch(Q); exception when No_Tuple => exit; end; ... end loop; \end{Example} \subsection{Null Values} If you are using Sybase\index{Sybase} and experiencing a problem where you are receiving a Null\_Value\index{Null\_Value} exception when there should be a value, then check to make sure that you have called Fetch\index{Fetch}. MySQL and PostgreSQL will raise No\_Result\index{No\_Result} when this happens. Sybase however, will appear to APQ as holding row results (which it might be), but APQ will not realize that Fetch has not yet been called. The Sybase library will then return a NULL\index{NULL} value if an attempt to get a column value is made, without a prior call to Fetch. Forgetting to call Fetch is easy to do when you code a SELECT\index{SELECT} to return one row with the help of a primary key reference in a WHERE\index{WHERE clause} clause. Since you are expecting one row to be returned, you will not code it as part of a traditional loop. So it is human nature to forget to code the call to Fetch after the Execute call. The following example might be typical of this: \begin{Example} Prepare(Sy_Q, "SELECT PUB_ID,PUB_NAME,CITY,STATE"); Append_Line(Sy_Q, "FROM PUBLISHERS"); Append(Sy_Q, "WHERE PUB_ID = "); Append_Quoted(Sy_Q,Sy_C,Pub_Id); Execute(Sy_Q,Sy_C); Fetch(Sy_Q); -- Easy to forget \end{Example} \subsection{Database Client Problems} If problems with the database engine begin to occur after a particular query, look for the following: \begin{itemize} \item Are you using MySQL\index{MySQL}? \item Are your doing a SELECT\index{SELECT}, or otherwise returning row results? \item Is your Query\_Type object in Sequential\_Fetch mode? \item Is your code fetching all row data? \end{itemize} This problem may occur with MySQL\index{MySQL}, since the client library for MySQL requires that all row result data be fetched. Failure to fetch all rows may cause a backlog in communication with the database server and cause strange behaviour or errors. Check the Query\_Type fetch mode. \subsection{Client Performance or Memory Problems} Check to see if the following apply: \begin{itemize} \item Are you using MySQL\index{MySQL}? \item Are you doing a SELECT\index{SELECT} or otherwise returning large row sets? \item Is your Query\_Type object in Random\_Fetch\index{Random\_Fetch} mode? \end{itemize} If the above are true, then it is possible you have formed a query that has generated a large row set. Since the default for the MySQL Query\_Type object is for Random\_Fetch mode, the APQ library calls upon mysql\_store\_result() to fetch all of the result set into the client's memory for random access. For reasonable sized sets of rows, this works well, but for larger results, this can be very expensive and may run your application out of memory. Consider the PRICE\_HIST table like the one discussed on page \pageref{PRICE_HIST Table Definition}. For MySQL, if you fail to include the LIMIT 1 clause, and your Query\_Type object uses the default Random\_Fetch mode, you could easily find your application selecting the entire history of one security into your application client memory! If you have several years of price history for that security, your application may be destined to run out of memory the first time that query is run. When using the MySQL database, you must consider the following: \begin{itemize} \item MySQL fetches in Random\_Fetch mode must guarantee a \emph{reasonably small result set} (use the LIMIT clause if necessary). \item MySQL fetches in Sequential\_Fetch mode must fetch \emph{all} row data \end{itemize} Unless otherwise noted, you probably do not need to be concerned about this. PostgreSQL\index{PostgreSQL} for example, does not require all row data to be fetched. However, if there are ways to restrict the row set, this may improve database server performance. \subsection{Can't Find Existing Table Names} Some databases use caseless\index{caseless} references to database objects, while others are case\index{case sensitive} sensitive (MySQL can be either). If you are using MySQL and experiencing problems, one solution is to configure the MySQL parameter: \begin{Code} [mysqld] set-variable = lower_case_table_names=1 \end{Code} By default, MySQL distinguishes between table names PRICE\_HIST, Price\_Hist, and price\_hist for example. Setting the parameter true (1), causes all table names to be lowercased (effectively caseless)\index{caseless table names}. The another approach is to check the SQL case policy\index{case policy} being used. APQ can work with MySQL in Lower\_Case, Upper\_Case or Preserve\_Case mode. The last choice only makes sense of course, if the SQL text in the program is correct. The suggested approach is to configure lower\_case\_table\_names=1 (as shown above) and to Set\_Case(C,Upper\_Case). Uppercase\index{uppercase} is easier to read in the trace logs, since the SQL stands out from the other trace information. If you are using Sybase\index{Sybase}, you cannot change the server. This means that either a Upper\_Case or Lower\_Case policy has to work for you, or you have to use exact case\index{exact case} for SQL code in the Ada code. It is possible to use a Lower\_Case policy most of the time, and make exceptions where they are required. The following shows how to make exceptions for a table name only: \begin{Example} declare C : Connection_Type; Q : Query_Type; begin Prepare(Q,"SELECT DESCRIPTION"); Append(Q,"FROM "); Set_Case(Q,Preserve_Case); Append(Q,"Part_Info",Line_Feed); Set_Case(Q,Lower_Case); Append_Line(Q,"WHERE ..."); ... Execute(Q,C); \end{Example} In the example presented, the case policy\index{case policy} was changed temporarily while building the query. Here the table name Part\_Info will have its case preserved, even though it is not a quoted string\index{quoted string}. The example assumes here that the normal policy is Lower\_Case. Note however, that any case policy change in the Query\_Type object is lost once Execute is called. An example will clarify this. Assume from our example above, two things: \begin{enumerate} \item The case policy in effect in the connection object C, is Lower\_Case (all SQL text is lowercased except where case must be preserved). \item Assume that the second Set\_Case(Q,Lower\_Case) call in the example code was commented out (the policy for Q is left at Preserve\_Case) \end{enumerate} If the above two assumptions are true, then upon return from the Execute(Q,C) call, the Query\_Type object would now hold the case policy of Lower\_Case (this came from Connection\_Type). Even after you call Clear, or Prepare and start a new query, this is the SQL case policy that is now in effect for Q. \section{Blob Related Problems} Blob operations on a database can be tricky to get right. The following subsections provide some assistance with blob related issues. \section{Blob\_Create and Blob\_Open Fails} You have written what seems like a simple piece of code that creates a blob, and then writes some data to it. It couldn't possibly fail on paper, but it does when you run it. Or you are wondering why that Blob\_Open\index{Blob\_Open failures} call keeps failing, because you are certain that the OID of that blob surely does exist. These are both symptoms of the same problem! \begin{quote} \emph{``All blob operations in PostgreSQL must be performed within a transaction''} \end{quote} Repeat it to yourself again. It is too easy to forget this fact! Unless you have started a transaction on the connection that you are using, \emph{all blob operations will fail}. They will only succeed within a transaction\index{transaction}. Furthermore, make certain your application commits\index{commit} the changes to your blob, after they have been performed successfully. Otherwise your application may fall prey to the default actions of PostgreSQL, which may be to rollback\index{rollback} your changes.% \footnote{Check your PostgreSQL documentation to determine what the default transaction action is for your version of PostgreSQL database.} \section{Blob I/O Buffering Bugs Suspected} If you have good reason to believe that the APQ binding software% \footnote{Only APQ versions 1.2 and later have buffered blob I/O.% } has a bug\index{bug} in its buffered\index{buffered blob I/O} blob I/O, you can disable blob I/O buffering. This is done by specifying a value of zero for the Buf\_Size argument in the Blob\_Open and/or Blob\_Create calls that you are troubleshooting. Be prepared to accept a large degradation in performance when specifying unbuffered I/O this way. The performance\index{performance} is especially poor when array I/O is performed. Another possibility might be that you need to call upon Blob\_Flush\index{Blob\_Flush} at strategic points in your application. While the buffering algorithms used are such that you should not need to worry about this, it is worth investigating when problems exist. Note also that multiple write access to the same blob is definitely \emph{not} supported by APQ. \section{Transaction Problems} The following subsections deal with transaction problems that may occur with application termination. \subsection{Abnormal Termination of Transactions} The APQ binding is designed to commit or rollback a transaction when the Connection\_Type object finalizes. The default behavior of the Connection\_Type is to ROLLBACK WORK\index{ROLLBACK WORK}, when the object finalizes\index{finalizes}% \footnote{Provided that the Connection\_Type object is connected to the database at the time of finalization.}. Consequently, if your program raises an uncaught exception (perhaps Program\_Error or Constraint\_Error), the Connection\_Type object will finalize\index{finalize} and rollback\index{rollback} the transaction on you. \footnote{Unless you have changed the default setting for the object. } If this is undesired behaviour, then check out the Set\_Rollback\_On\_Finalize primitive in section \Ref{Set_Rollback_On_Finalize Procedure}. \subsection{Aborted Applications} The APQ binding can only perform the default COMMIT/ROLLBACK action (see \Ref{Set_Rollback_On_Finalize Procedure}) if the Connection\_Type object is permitted to have its Finalize\index{finalize} primitive called. If the process under UNIX for example, is terminated with a signal (by the kill(1)\index{kill(1) command} command), the objects within your application may not experience a Finalize call, because normal Ada shutdown procedures were not invoked.% \footnote{There are Ada2005 ways to deal with UNIX signals, which permit an orderly Ada shutdown of your application. However, a kill -9 prevents any action at all from being performed by the application!% } If this is the reason for your problem, then you have two courses of action: \begin{itemize} \item Commit/Rollback explicitly in the program (prior to receiving a signal) \item Avoid signalling the application \item Add signal\index{signal handling} handling capability to your Ada application, to permit an orderly application shutdown \item Not use kill -9, which prevents any application recovery or notification \end{itemize} The choice is generally up to the application designer. Whenever possible however, where it is important, the application should perform its own explicit commit or rollback operation. Note however, that if the Connection\_Type object is not permitted to finalize\index{finalize} successfully on its own, the database software itself has default procedures for dealing with disconnected sessions. Some databases will rollback transactions if the socket/pipe connection to the server is disconnected. Others will commit. You'll need to check your server documentation and configuration to sort that one out. \section{SQL Problems\label{SQL Problems}} If you are experiencing SQL problems that you don't understand, the quickest way to inspect what is really going on is to use the APQ trace\index{trace facility} facility. The documentation for the SQL trace facility is given in \Ref{Trace Facilities}. So RTFM. \subsection{Tracing SQL} Where your Connection\_Type connects to the database, add a call to Open\_DB\_Trace as follows: \begin{Example} declare C : Connection_Type; begin ... Connect(C); Open_DB_Trace(C,"trace_file.txt",Trace_APQ); \end{Example} Without adding another line of code, every SQL interaction will be captured to trace\_file.txt, which you can inspect when the application completes.% \footnote{Note however that the tracing facilities are not task (thread) safe. If your application uses tasking, then disable tracing in the tasks or avoid using APQ in more than one task.% } \subsection{Too Much Trace Output} If your application performs so many SQL operations that the trace file becomes too large, then disable\index{disable tracing} the tracing until you get to a strategic point in the program: \begin{Example} declare C : Connection_Type; begin ... Connect(C); Open_DB_Trace(C,"trace_file.txt",Trace_APQ); Set_Trace(C,False); -- Disable trace for now.. ... Set_Trace(C,True); -- Start tracing now \end{Example} The overhead of the Set\_Trace primitive is light, unless you have selected Trace\_libpq or Trace\_Full (these add the overhead of invoking libpq functions PQtrace() and PQuntrace()). Light overhead permits you to use Set\_Trace within a loop without severe penalty, to gather only the information you need. \subsection{Captured SQL Looks OK} If the SQL code captured in \Ref{SQL Problems} looks OK, but the database engine is still reporting a problem, then try the following: \begin{enumerate} \item Create a capture file using Trace\_APQ (or use the current one you have). \item Edit (cut) out the portion of the SQL queries in the capture file that you are having difficulty with. \item Use the database interactive SQL command (psql for PostgreSQL) and replay the extracted problem SQL queries. \item Edit SQL query and repeat step \#3 as necessary until you discover your error. \end{enumerate} This allows you to experiment with the SQL text as your applicaton created it. Once you achieve success with psql, you can then go back and correct your application to form the query correctly. \subsection{You Want to Report a Problem to PostgreSQL} If you want to report a trace file in terms that the PostgreSQL people understand, simply choose the Trace\_libpq trace mode when creating a trace file. Then send them the trace file with a description of the problem. \subsection{Missing Trace Information} The trace information is collected at the Connection\_Type object level. Check to see if you have more than one Connection\_Type object involved. If so, make sure you set the appropriate trace settings\index{trace settings} on the connections that you want to collect trace information for. Different instances of a Connection\_Type object should write its traces to different files. Note also, that when a Connection\_Type object finalizes\index{finalizes}, its trace file is closed. \section{Cursor Related Problems} To use a cursor\index{cursor} you generally need an SQL phrase of the form\index{WHERE CURRENT OF}: \begin{SQL} WHERE CURRENT OF \end{SQL} Obviously, the APQ function primitive Cursor\_Name\index{Cursor\_Name} is expected to provide this name. But does this function primitive seem to raise the exception \emph{No\_Results}\index{No\_Results} for you? If so, you've probably supplied the wrong Query\_Type object to the function Cursor\_Name. Review the test program on page \pageref{Cursor Example Program}, where you see the statement: \begin{Example} Append_Line(Q2,"WHERE CURRENT OF " & Cursor_Name(Q)); \end{Example} There are two Query\_Type objects being used: \begin{enumerate} \item Q for the cursor fetch (outer query) \item Q2 for the inner SQL query (the UPDATE) \end{enumerate} When coding this statement, it is very easy to type Q2 for Cursor\_Name argument, instead of Q.% \footnote{The author made this very mistake the first time the example program was written.% } However, the cursor name is only available for the outer query\index{outer query} (the one with the cursor and cursor results). So be certain to carefully distinguish between the inner and outer query objects. \section{Connection Related Problems} If you are experiencing trouble establishing a connection to the database itself, then there are a number of environment\index{environment} related issues. \subsection{PostgreSQL Connections} A number of environment variables affect a PostgreSQL database connection:% \footnote{Check your PostgreSQL documentation for the final word on this subject.% } \begin{description} \item [PGHOST]Host name of the database server \item [PGPORT]IP port number or UNIX socket pathname of the database server \item [PGDATABASE]Database name within the database server \item [PGUSER]Database user name \item [PGPASSWORD]Database password \item [PGREALM]Kerberos realm for the database server \item [PGOPTIONS]Database server options \end{description} Any of these connection mode parameters that are not configured in the application are defaulted to the ones defined by the above environment variables. If you are experiencing trouble, make certain that your variables are \emph{exported}\index{exported variables}. In many shells, like the Bourne\index{Bourne shell} and Korn\index{Korn shell} shells,% \footnote{I won't encourage anyone here to use the csh.% } this is done as follows (for the PGHOST\index{PGHOST} variable): \begin{Example} export PGHOST \end{Example} Some shells, like the Korn shell and the GNU bash\index{bash shell, GNU} shell, allow multiple variable names to be listed at once: \begin{Example} export PGHOST PGPORT PGDATABASE PGUSER \end{Example} Once you have the environment configured correctly, you should be able to access the database with the PostgreSQL psql\index{psql} command. If the psql% \footnote{Do a ``man psql'' for details about the psql client command.% } command still fails, then you may need to revisit your environment variable settings or possibly even the database server configuration.% \footnote{Check the security aspects of your connection first.% } \subsubsection{PostgreSQL UNIX (Local) Connections} The way that the local socket\index{local socket} is specified for PostgreSQL seems to have changed with its different releases. Make sure you choose the correct Set\_Port\index{Set\_Port} procedure to specify the local UNIX socket. Use the Set\_Port that accepts a string argument. The string indicates that a local UNIX connection is required. PostgreSQL 7.3.5 and later (unless it has changed again), requires only the ``number'' to specify the local socket. For example, if you ``netstat -na'' command shows the following:\footnote{The output lines have had the RefCnt and Flags columns removed to allow the lines to fit the space available.} \begin{ShellNumberedExample} $ netstat -na --unix Active UNIX domain sockets (servers and established) Proto Type State I-Node Path unix DGRAM 2086 /dev/log unix STREAM LISTENING 2937 /var/run/mysqld/mysqld.sock unix STREAM LISTENING 2942 /tmp/.s.PGSQL.5432(*@\label{Ex:5432}@*) unix STREAM CONNECTED 3363 unix STREAM CONNECTED 3362 unix DGRAM 3138 ... \end{ShellNumberedExample} From this display, you can see that a database connection is available with UNIX\index{UNIX socket} socket /tmp/.s.PGSQL.5432 (line~\ref{Ex:5432}). For Set\_Port, you only need to supply the last numerical part, namely ``5432'' (which happens to match the default IP port number). So to specify a UNIX socket connection for this, you would code: \begin{Example} Set_Port(C,"5432"); \end{Example} Note especially, that the number must be in a \emph{string} to cause a UNIX\index{UNIX socket} local\index{local socket} socket to be used. If you specify an integer costant, a TCP/IP\index{TCP/IP socket} socket will be used, which uses the IP port number you specified. \subsection{MySQL Connections} APQ does not currently look for environment variables for MySQL.\footnote{although changes to MySQL are possible} If you suspect environmental influences, check the MySQL C client library documentation for conditions where the environment may be consulted. A successful MySQL connection must have: \begin{enumerate} \item A designated host name or address for the database server\index{host name} \item A port number\index{port number} \item Userid\index{userid} and password\index{password} (or ``'') \item Options (only if necessary)\index{options} \end{enumerate} Any supplied instance information is ignored. \subsection{Sybase Connections} APQ itself does not currently look for environment variables for Sybase\index{Sybase}. The Sybase client libraries \emph{probably} do, if the variables exist. Check the Sybase documentation (\emph{todo: check documentation for influencing environment variables that are believed to exist}). A successful Sybase connection must have: \begin{enumerate} \item A designated instance name (Set\_Instance)\index{Set\_Instance} \item A userid\index{userid} and password\index{password} (or {}``'') \item Options (only if necessary)\index{options} \end{enumerate} Sybase ignores the host name/address and port information. The database name is only important once the connection has been established. See the Sybase specific notes about Set\_DB\_Name in \Ref{Context_Setting_Operations}. The instance\index{instance name} name must exist in the local hosts \emph{interfaces} file. In most cases this file can be found in /opt/sybase/interfaces (\$SYBASE/interfaces) on UNIX platforms or possibly C:\textbackslash{}opt\textbackslash{}sybase\textbackslash{}ini\textbackslash{}sql.ini (\%SYBASE\%\textbackslash{}ini\textbackslash{}sql.ini) on windows (depending upon where it was installed). There may be exceptions to this rule in more advanced Sybase configurations. \subsection{Sybase Disconnect Problems} If you experience a APQ.Not\_Connected\index{Not\_Connected} exception in one of the following scenarios: \begin{itemize} \item When the Connection\_Type object is finalized\index{finalized} \item When Disconnect is called on the Connection\_Type object \end{itemize} then look for Query\_Type objects that are still hanging onto query results. This most often happens in a program where the Connection\_Type object and Query\_Type objects are declared together and the Connection\_Type object finalizes\index{finalizes} first. The solution is to either arrange it so that all Query\_Type objects finalize first, or clear the query results explicitly by calling Clear, prior to disconnecting or finalizing the connection. For example if Q is the Query\_Type object and C the connection, then the following sequence will ensure that the disconnect (or finalize) will always succeed\index{Clear}: \begin{Example} Clear(Q); -- Release query results Disconnect(C); -- Disconnect (or finalize) \end{Example} \subsection{Sybase Options} APQ permits the application developer to set various Sybase\index{Options} server options. Some of these are known to create problems for APQ. Rather than dictate policy for the developer, APQ gives you full access to the Sybase options. Clearly some options should be avoided when using APQ. One such option is the following: \begin{Example} Set_Options(C,"SHOWPLAN=TRUE"); -- CS_OPT_SHOWPLAN \end{Example} This option setting seems to do something strange to the underlying Sybase connection after it is set. APQ has been observed raising Program\_Error\index{Program\_Error} when other exceptions were supposed to have been raised. Unless you know what you are doing, you seem to be well advised to stay clear of this option when using APQ for Sybase. The developer should also avoid using any Sybase options that change the way the date is formatted. APQ functions look for dates to be in a specific format so that they can be converted into APQ data types. \subsection{Connection Cloning Problems} If the original Connection\_Type object connects OK, but the Connect clone\index{clone} call fails, then it could be that the network has gone bad since the original connection was made. If exceptions other than Not\_Connected are being raised, then check that: \begin{itemize} \item Make sure the parameters are in the correct order in the Connect call. \item Make certain that the connected object, is indeed connected. \item Make certain that the new object is not already connected. \item Make sure you haven't exceeded the number of allowed database server connections \end{itemize} \subsection{Connection Tracing} Problem: Your first Connection\_Type object is tracing to a file successfully, but the cloned\index{cloned} Connection\_Type object is not. Reason: Cloned connections do not have the trace\index{cloned trace} file parameters cloned. This was a compromise to make APQ more portable to other platforms that may not share files well. Solution: Configure the cloned connection to trace to a file separate from the original connection, after the clone operation is complete. \appendix \chapter{PostgreSQL Credits} \section*{PostgreSQL Decimal C Sources} PostgreSQL Database Management System (formerly known as Postgres, then as Postgres95) \begin{itemize} \item Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group \item Portions Copyright (c) 1994, The Regents of the University of California \end{itemize} Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN ``AS IS'' BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. \section*{Modification Notice} The numeric C routines required extensive interface modifications for use in this APQ Binding. These modified C sources were extracted from the PostgreSQL server project. No guarantee is made with regard to the quality of these modifications. \section*{Contributor Notice} In no event shall the author or contributors to the APQ Binding be liable to any party for any cause that the modified PostgreSQL software may cause or contribute to. \chapter{APQ License} \label{license} \section*{Scope of the APQ Binding License} The {}``APQ Binding'' license covers those software modules not provided by or extracted from the PostgreSQL database software (such as the Decimal C source modules). The APQ license does not cover database products themselves that APQ binds to. \section*{APQ Binding License} The APQ Binding used to be covered under a dual-license arrangement. This was reflected in the file name COPYING. The following two licenses were available: \begin{enumerate} \item The Ada Community License (ACL). \item The GNU Public License 2 (GPL2) \end{enumerate} This dual-license arrangement was to allow use of the package both with GPL programs and non GPL programs. This can be achieved by using a single license now, and thus APQ has changed it's license to MGPL. Please see pages \pageref{gmgpl} and \pageref{gpl} for more information. \section*{Patents} The author is not aware of any patent infringements made by the APQ software. However the author makes \emph{absolutely no warrante} about any possible patent infringements. You are encouraged to lobby against any kind of software patents, since software patents today do not serve the public's best interest. Companies and individuals are using software patents to legally extort from other companies and individuals. This is not in the spirit of the original patent legislation and works against all reasonable public interests. \chapter{GNAT Modified GPL} \label{gmgpl} \begin{quote} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if other files instantiate generics from this unit, or you link this unit with other files to produce an executable, this unit does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Public License. \end{quote} \chapter{GNU Public License} \label{gpl} \section*{GNU GENERAL PUBLIC LICENSE Version 2, June 1991} \begin{quote} Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. \end{quote} \subsection*{Preamble} The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: \begin{enumerate} \item copyright the software, and \item offer you this license which gives you legal permission to copy, distribute and/or modify the software. \end{enumerate} Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. \section*{GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION} \paragraph{0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''.} \paragraph{Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.} \paragraph{1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.} \paragraph{You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.} \paragraph{2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:} \subparagraph*{a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.} \subparagraph*{b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.} \subparagraph{c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) } \paragraph{These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.} \paragraph{Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.} \paragraph{In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.} \paragraph*{3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:} \subparagraph*{a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,} \subparagraph{b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,} \subparagraph{c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)} \paragraph{The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.} \paragraph{If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. ~4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.} \paragraph*{5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.} \paragraph{6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.} \paragraph{7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.} \paragraph{If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.} \paragraph{It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.} \paragraph{This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. ~8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.} \paragraph{9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.} \paragraph{Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.} \paragraph{10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.} \subsection*{NO WARRANTY} \paragraph{11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.} \paragraph{12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.} \paragraph{END OF TERMS AND CONDITIONS} \chapter{Credits} This appendix documents the contributors to the ``APQ Binding'' that are separate from the PostgreSQL project. \section*{Authors} \begin{itemize} \item Warren W. Gay VE3WWG \begin{itemize} \item 29 Glen Park Road, St. Catharines, Ontario \item Canada L2N 3E3 \item ve3wwg@cogeco.ca \end{itemize} \item Marcelo Cora\c ca de Freitas \item Daniel Norte de Moraes \end{itemize} \section*{Contributions} \subsection*{Source Code Modifications} Some people has contributed to the 3.0 release: \begin{itemize} \item Alex Abate Biral \begin{itemize} \item Most notably implemented the ODBC support which is not yet complete \end{itemize} \end{itemize} \subsection*{Bug Reports} \begin{itemize} \item There appears to be a problem with win32 releases using PostgreSQL 7.2.1, where specifying the database server by IP \# creates a problem. The problem is believed to be in libpq.dll. (September 22, 2004: this problem is believed to be fixed in more current releases of PostgreSQL). \item Jeffrey R. Carter, Chief Software Engineer from Singo Solution, Inc., who contributed with bug fixes in 2007 for the apq-postgresql module. \end{itemize} \subsection*{Bug Report/Fix Contributions} \begin{itemize} \item Charles Darcy , November 23, 2002 \item Jesse Lang , March 2008 \end{itemize} \chapter{History} \section*{APQ 1.0} First released August 3, 2002, under the Ada Community License (ACL). \section*{APQ 1.1} Second release August 4, 2002, but under the dual ACL and GPL2% \footnote{GNU Public License 2% } license. This license change was suggested by Florian Weimer. \section*{APQ 1.2} \begin{itemize} \item Added function End\_Of\_Blob to streamline sequential processing. \item Added buffered blob I/O for higher performance. \item Added procedure Blob\_Flush to force unwritten blob data to the database server. \item Blob\_Create has new optional Buf\_Size argument. \item Blob\_Open has new optional Buf\_Size argument. \item Fixed Blob\_Create to release the created blob, if the blob cannot be opened. This most often happens when the caller is attempting to create a blob, outside of a transaction. \end{itemize} \section*{APQ 1.3} \begin{itemize} \item Removed some debug Put\_Line statements that should have been removed in 1.2. \item Added a few pragma Inline statements to the spec PostgreSQL.Client \end{itemize} \section*{APQ 1.4} \begin{itemize} \item Added Generic\_Command\_Oid for strong PG\_Oid type use \item Added Generic\_Blob\_Open for strong PG\_Oid type use \item Added Generic\_Blob\_Oid function for strong PG\_Oid type use \item Added Generic\_Blob\_Unlink for strong PG\_Oid type use \item Added Generic\_Blob\_Import and Generic\_Blob\_Export for strong PG\_Oid type use \end{itemize} \section*{APQ 1.5} \begin{itemize} \item Bug fix: Append\_Time, Append\_Date and Append\_Timestamp now emit the surrounding single quote characters around the value to satisfy the SQL syntax required by the database server. \item Troubleshooting help added to this manual for {}``Missing Time Data (Or Time is 00:00:00)''. \end{itemize} \section*{APQ 1.6} \begin{itemize} \item Added Set\_Rollback\_On\_Finalize controlling primitive for Connection\_Type. \item Added Will\_Rollback\_On\_Finalize function for Connection\_Type for inquiry. \item Expanded manual and added transaction problem help to the Troubleshooting chapter. \end{itemize} \section*{APQ 1.7} \begin{itemize} \item Open\_DB\_Trace and Close\_DB\_Trace procedures added. \item Set\_Trace procedure added to enable and disable tracing. \item Is\_Trace function added to query the tracing state. \end{itemize} \section*{APQ 1.8} \begin{itemize} \item Connection information functions like Host\_Name and Port were added. \item A connection cloning primitive was added. \end{itemize} \section*{APQ 1.9} \begin{itemize} \item A compiler work-around was provided. Some versions of GNAT would not compile the APQ source code, because certain instantiations of Ada.Text\_IO.Integer\_IO were producing duplicate symbol errors in the assembler phase of the compile. This problem was absent in gnat 3.13p compiles, but have shown up in gcc-3.1.1 and probably in gnat 3.14p and later releases. The instantiation names INTIO were made unique within the source code to avoid this problem. \end{itemize} \section*{APQ 1.91} \begin{itemize} \item The PostgreSQL Connect call now performs an automatic {}``SET DATESTYLE TO ISO'' command prior to returning from a successful connect. This is necessary to guarantee that ISO date format is returned from the database engine and recognized from the engine. This guarantees that APQ correctly handles dates, even when the user has specified a PGDATESTYLE environment variable value that is different than ISO. \item Fixed bug in Host\_Name function. It was returning a null string when a host name was set in the Connection\_Type object. \item Win32 apq-1.91 source release (subdirectory win32) and apq-1.91-win32-2.7.1 binary release created. \end{itemize} \section*{APQ 1.92} \begin{itemize} \item Fixed bug for floating point and fixed point types (was rounding the value to the nearest integer, due to the fact that the Ada.Text\_IO.Float\_IO.Put call was receiving the argument Aft => 0). Omitting the Aft parameter causes the value to be formatted as required for the SQL floating/fixed point type. The bug was reported by Charles Darcy . \end{itemize} \section*{APQ 1.93} \begin{itemize} \item Modified the Ada2005 package hierarchy to insert a top level package named APQ. Hence package PostgreSQL now becomes APQ.PostgreSQL. This is an interim release, which will pave the way to future support of other database products such as MySQL. \end{itemize} \section*{APQ 2.0} \begin{itemize} \item MySQL support added. This was made possible by the package restructuring done in the interim release APQ 1.93. \item Generic database programming support added. Special generic services like Engine\_Of, New\_Query etc. were added to make this possible. A heavy reliance is made upon object inheritance and polymorphism to make this work. \item A new example subdirectory eg2 was added. The programs in this subdirectory show the original example program, but done in a database generic way. The test program can be compiled and run for both PostgreSQL and MySQL databases. \item PG\_Oid is now named APQ\_Row\_ID and is 64 bits unsigned integer. \item Null\_Oid() function added for generic database support (and much more). \item Engine\_Of() function added for generic database support. \item Exception {}``Failed'' was added to handle some general failures. \item Fetch\_Mode() and Set\_Fetch\_Mode() were added to accommodate MySQL limitations. \item Documentation went through some restructuring to accomodate two databases, and their differences. \end{itemize} \section*{APQ 2.1} \begin{itemize} \item This was the win32 port. \item See win32.pdf for instructions for building APQ on a win32 platform. \item win32\_test.adb program was added to the distribution to allow testing of APQ in the windows environment. \end{itemize} \section*{APQ 2.2} \begin{itemize} \item PostgreSQL now defaults to Set\_Port(C,5432), which is an TCP/IP connection for port 5432. \item APQ now uses Ada.Exceptions.Raise\_Exception in many places to provide more information. For example if a Value() function raises a Constraint\_Error, it now indicates in the message which column \# the error occurred for (where Value takes a Column\_Index\_Type argument). The informative message makes it easier to debug a new APQ application. \item Documentation added for Set\_Port for UNIX socket connections. \item The primitives Begin\_Work, Commit\_Work and Rollback\_Work now include an implicit call to Clear before and after the Query\_Type's object's use. This is necessary in some cases to clean up results and to put the object into the right state (Sybase made this necessary). The fetch mode of the Query\_Type object is preserved, even though it may be changed to something else while being used. \item The Set\_DB\_Name now works differently for PostgreSQL, if the connection has already been established. In the past, APQ (for PostgreSQL) simply took note of the new database name, but did nothing with it. This was inconsitent behavior compared to the fact that APQ\-.MySQL\-.Client\-.Set\_DB\_Name() would make a database switch on the connected connection. Now this behaviour is harmonized, by having the PostgreSQL version perform a hidden {}``USE '' SQL query to make it happen. \item When a APQ\-.MySQL\-.Set\_DB\_Name(C) fails on a connected C, the exception raised is now APQ.Use\_Error instead of APQ.Failed. This helps to distinguish the difference between a successful connection and failed database change. \item Sybase always connects to the server's configured default database for the user. To make APQ.Sybase consistent with other supported databases, any Set\_DB\_Name(C) on connection C prior to the connection, now queues up a ``USE '' query to be performed, once the connection is successful (effectively making it appear the same in APQ). Any call to Set\_DB\_Name(C) while C is connected, will result in another ``USE '' SQL query being performed behind the scenes. \item Fixed bug in APQ\-.MySQL\-.Client\-.Reset so that the Connection\_Type object was properly reset for re-use. \item APQ.Sybase.Client support was added \item Set\_Instance and Instance functions were added to permit specification of Sybase instances. \item Fetch modes Cursor\_For\_Update and Cursor\_For\_Read\_Only were added for Sybase cursor support. \item Function Cursor\_Name was added for Sybase cursor support. \item Functions Set\_Case and Case were added to deal with Sybase's case sensitivity for database agnostic code. \item Fixed MySQL encoding of APQ\_Boolean types. Now sends 1 or 0, for True or False respectively (MySQL uses bit or tinyint to represent boolean values). \item Fixed MySQL decoding of date/time types (MySQL provides YYYYMMDDHHMMSS instead of YYYY-MM-DD HH:MM:SS, which APQ expected). \item APQ.PostgreSQL.Client.Value now trims trailing blanks returned for string values. This helps the returned values to be consistent across all database vendor products (MySQL always trims the trailing blanks). \end{itemize} \section*{APQ 3.0} \begin{itemize} \item New build system. \item GPR file support \item APQ was divided into sub projects: \begin{itemize} \item \textbf{apq} the core APQ classes \item \textbf{apq-ct\_lib} ct\_lib backend support (MySQL Server and Sybase) \item \textbf{apq-mysql} MySQL backend support \item \textbf{apq-odbc} ODBC support \item \textbf{apq-postgresql} PostgreSQL backend support \end{itemize} \item Microsoft SQL Server and ODBC Support \item Can be built with FreeTDS and Sybase's ct\_lib \item New single license in favour of the old dual-license \item some bug fixes \end{itemize} \section*{APQ 3.1} \begin{itemize} \item Some minor PostgreSQL bug fixes \item Support to PostgreSQL SSL connections \end{itemize} \section*{APQ 3.2} \begin{itemize} \item Moved on to gprbuild \item Removed Pragma Linker\_Options from the code \item APQ\_Timestamp in UTC \item Support Ada2005's Ada.Calendar.Time\_Zones package \end{itemize} \printindex \end{document} apq-3.2.0/samples/000077500000000000000000000000001171626402600137465ustar00rootroot00000000000000apq-3.2.0/samples/COPYING000066400000000000000000000020411171626402600147760ustar00rootroot00000000000000This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if other files instantiate generics from this unit, or you link this unit with other files to produce an executable, this unit does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Public License. apq-3.2.0/samples/GPL000066400000000000000000000431311171626402600143150ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. apq-3.2.0/samples/Makefile000077500000000000000000000005331171626402600154120ustar00rootroot00000000000000# Makefile for the KOW Generic Library Framework # # @author Marcelo Coraça de Freitas # # # Please, read Makefile.include for more information all: ./scripts/build.sh install: ./scripts/install.sh uninstall: ./scripts/uninstall.sh clean: ./scripts/clean.sh distclean: @-${MAKE} clean @-${MAKE} -C samples clean apq-3.2.0/samples/apq-samples.gpr000066400000000000000000000015741171626402600167120ustar00rootroot00000000000000-- Build file for Aw_Lib. -- -- author Marcelo Coraça de Freitas -- -- Repository information: -- $Date: 2008-02-25 19:47:48 -0300 (Seg, 25 Fev 2008) $ -- $Revision: 234 $ -- $Author: ogro $ with "apq.gpr"; project APQ.Samples is version := "2.3.0"; type Supported_OS is ("Windows_NT", "GNU/Linux"); target: Supported_OS := external("OS", "GNU/Linux"); for Source_Dirs use ( "src" ); for Object_Dir use "obj"; -- LIBRARY for Library_Dir use "lib"; for Library_Name use "apq-samples"; case target is when "Windows_NT" => for Library_Kind use "dynamic"; when "GNU/Linux" => for Library_Kind use "dynamic"; end case; for Library_Version use "libapq-samples.so." & Version; package Compiler is for Default_Switches ("ada") use ("-O2", "-gnat05"); end Compiler; --package Linker renames APQ.Linker; end APQ.Samples; apq-3.2.0/samples/configure000077500000000000000000000056471171626402600156710ustar00rootroot00000000000000#!/usr/bin/env bash # Main configuration file for KOW framework projects # # @author Marcelo C. de Freitas source scripts/buildutil.sh ################### # Default Options # ################### enable_debug="false"; enable_static="true"; enable_relocatable="true"; include_files=src/* work_path="$PWD/work" prefix=$(dirname `which gnatls`) prefix=$(dirname $prefix) version=$(cat version) processors=2 GPRBUILD="gprbuild" if [[ $OS -eq "" ]] then OS="GNU/Linux" fi ########################### # Command Line Parameters # ########################### # Setup build environment for i in $@ do option=`echo $i | cut -d= -f1` value=`echo $i | cut -d= -f2` case $option in --prefix ) prefix="$value";; --enable-debug ) enable_debug="true";; --disable-static ) enable_static="false";; --disable-relocatable ) enable_relocatable="false";; --os ) OS="$value";; --work-path ) work_path="$value";; --gprbuild ) GPRBUILD="$value";; --gprbuild-params ) gprbuild_params="$value";; --processors ) processors=$value;; esac done ######################### # Initial configuration # ######################### check_in_path gprbuild check_in_path gnatprep init_configuration init_gnatprep ########################### # Run local configuration # ########################### if [[ -x configure.local ]] then source configure.local fi ####################### # Include Files Setup # ####################### echo "Copying source files" source_destination="$work_path/src/$project" mkdir -p $source_destination for i in $include_files do cpu "$i" $source_destination done ############# # GPR Files # ############# echo "Copying standard project files" gpr_destination="$work_path/lib/gnat" mkdir -p "$gpr_destination" for i in gnat/*.gpr do if [[ -f $i ]] then cpu $i $gpr_destination fi done echo "Preparing def file.." set_gnatprep version $version set_gnatprep prefix "$prefix" set_gnatprep project "$project" for i in gnat/*.gpr.in do if [[ -f $i ]] then fname=$(basename "$i" .in) destination="$gpr_destination/$fname" gnatprep "$i" "$destination" gnatprep.def fi done ####################################### # Store the usual configuration flags # ####################################### set_configuration prefix "$prefix" set_configuration enable_debug $enable_debug set_configuration enable_static $enable_static set_configuration enable_relocatable $enable_relocatable set_configuration OS "$OS" set_configuration include_files "$include_files" set_configuration version "$version" set_configuration work_path "$work_path" set_configuration GPRBUILD "$GPRBUILD" set_configuration gprbuild_params "$gprbuild_params" set_configuration processors $processors set_configuration project "$project" echo echo "################################################" echo "# This is the build environment you did setup: #" echo "################################################" cat_configuration apq-3.2.0/samples/configure.local000077500000000000000000000001421171626402600167430ustar00rootroot00000000000000#!/usr/bin/env bash project="apq-samples" set_configuration APQSAMPLES_EXTERNALLY_BUILT false apq-3.2.0/samples/gnat/000077500000000000000000000000001171626402600146775ustar00rootroot00000000000000apq-3.2.0/samples/gnat/apq-samples.gpr.in000066400000000000000000000030401171626402600202360ustar00rootroot00000000000000-- Build file for APQ. -- -- author Marcelo Coraça de Freitas -- -- Repository information: -- $Date$ -- $Revision$ -- $Author$ with "apq"; project APQ.Samples is ----------------------- -- Type declarations -- ----------------------- type True_False is ( "true", "false" ); type Supported_OS is ("Windows_NT", "GNU/Linux", "Darwin" ); -------------------- -- Main Variables -- -------------------- version := $version; OS : Supported_OS := external( "OS", "GNU/Linux" ); Debug : True_False := external( "DEBUG", "false" ); ---------------- -- Parameters -- ---------------- for Library_Name use $project; for Source_Dirs use ( "../../src/" & Project'Library_Name & "/" ); for Library_kind use external( "LIBRARY_KIND", "static" ); case Debug is when "true" => for Library_Dir use "../" & Project'Library_Name & "-debug/" & Project'Library_Kind; when "false" => for Library_Dir use "../" & Project'Library_name & "/" & Project'Library_Kind; end case; for Object_Dir use Project'Library_Dir & "/objects/"; for Library_Version use "lib" & Project'Library_Name & ".so." & Version; for Externally_Built use External( "APQSAMPLES_EXTERNALLY_BUILT", "true" ); ---------------------- -- Compiler Package -- ---------------------- package Compiler is case Debug is when "true" => for Default_Switches ("ada") use ("-O2", "-gnat05", "-fPIC", "-g"); when "false" => for Default_Switches ("ada") use ("-O2", "-gnat05", "-fPIC" ); end case; end Compiler; end APQ.Samples; apq-3.2.0/samples/scripts/000077500000000000000000000000001171626402600154355ustar00rootroot00000000000000apq-3.2.0/samples/scripts/build.sh000077500000000000000000000011711171626402600170730ustar00rootroot00000000000000#!/usr/bin/env bash # # Builder for the KOW Framework project # # All it actually does is to call gprbuild several times ################## # Initialization # ################## source scripts/buildutil.sh load_configuration echo $KOWLIB_EXTERNALLY_BUILT if [[ "$enable_debug" = "true" ]] then echo "############################"; echo "# Building Debug Libraries #"; echo "############################"; export DEBUG="true"; build_libraries; fi echo "##############################"; echo "# Building Regular Libraries #"; echo "##############################"; export DEBUG="false"; build_libraries; gen_filelist; apq-3.2.0/samples/scripts/buildutil.sh000077500000000000000000000132701171626402600177740ustar00rootroot00000000000000#!/usr/bin/env bash # # Auxiliary functions for the KOW Framework main build system # # @author Marcelo C. de Freitas ###################### # Environment Checks # ###################### # Check if a given command is in path; # usage: # check_in_path COMMAND_NAME check_in_path(){ echo -n "Looking for $1 ... " hash $1 2>&- || { echo "[false]"; echo >&2 "I need $1 in path but I can't find it... aborting"; exit 1; } && echo "[ok]" } # Check if a project file is available # usage: # check_project projectname check_project(){ proj=$1; echo -n "Looking for project $proj ... " ${GPRBUILD} -ws -P$proj 2>&- || { echo "[false]"; echo "${GPRBUILD} can't find $proj in ADA_PROJECT_PATH"; exit -1;} && echo "[ok]"; } # Copy updating a regular file or directory # usage: # cpu origin destination cpu(){ origin="$1" fname=$(basename "$1") destination="$2/$fname" if [[ -f "$origin" ]] then if [[ "$origin" -nt "$destination" ]] then cp "$origin" "$destination" else echo "Skipping \"$origin\"" >> configure.log fi else echo "Can't copy (not a regular file): \"$origin\"" >&2 exit 1; fi } ############################ # Configuration Management # ############################ # reset the configuration file init_configuration(){ echo -n "" > .configuration } # Set a configuration key/value: # usage: # setconfiguration key value set_configuration() { echo export $1=\"$2\" >> .configuration } # Printout the configuration file # usage: # cat_configuration cat_configuration(){ cat .configuration } # load the configuration file: # usage: # load_configuration load_configuration(){ if [[ -f .configuration ]] then source .configuration else echo "Please run configure first" >&2; exit 1; fi } ################### # Data Processing # ################### # iterate for printing a list of declarations, used internally by print_enum_declaration and print_for_declaration # usage: # iterate_enum_list "the list of values" echo_function_name # # The list of values should respect the format: # number name # number name # number name # number name # # and eatch line is trimmed before calling the given function iterate_enum_list(){ local is_first=1; echo "$1" | while read a do if [[ "$a" = "" ]] then echo -n #skip empty lines else if [[ $is_first -eq 1 ]] then is_first=0; else echo ','; fi; echo -n " "; $2 $a fi done echo; } _enum_declaration(){ echo -n $2; } # For each entry print as expected for the enum declaration type echo_enum_declaration(){ iterate_enum_list "$1" _enum_declaration } _for_declaration(){ echo -n "$2 => $1"; } echo_for_declaration(){ iterate_enum_list "$1" _for_declaration } # Will set a enum value using the same list as the one used in iterate_enum_list # in the given file (edit the given file). # usage: # set_enum_values FILE LIST_OF_VALUES PREFIX # # This will replace: # %${PREFIX}_DECLARATION% with the result of echo_enum_declaration # %${PREFIX}_FOR% with the result of echo_for_declaration # set_enum_values(){ local outfile="$1" local values="$2" local prefix="$3" declaration_values=`echo_enum_declaration "$values"` for_values=`echo_for_declaration "$values"` replace_in_file "$outfile" "%${prefix}_DECLARATION%" "$declaration_values" replace_in_file "$outfile" "%${prefix}_FOR%" "$for_values" echo "[ok]" } # Simple str_replace in a file # usage # replace_in_file FILENAME FROM TO replace_in_file(){ filename="$1" from="$2" to=$(echo "$3" | sed -e 's/$/\\&/' | sed -e 's/\//\\&/g' ); sed -i -e "s/$from/$to /" "$filename" } ################################ # Gnatprep def file management # ################################ # see the documentation for configuration files; basically the same thing init_gnatprep() { echo -n "" > gnatprep.def } set_gnatprep(){ echo $1:=\"$2\" >> gnatprep.def } # transform a list of parameters in a format both sed and gprbuild will understand... # the output of this function is meant to be used by replace_in_file, which processes / and new lines sedfy_gpr_list(){ is_first=1 for option in $1 do if [[ $is_first -eq 1 ]] then is_first=0; else echo -n "," fi #option=`echo $i | sed 's/\//\\\&/g'` echo -n \\\"$option\\\" done } ############ # Building # ############ build_libraries(){ if [[ "$enable_static" = "true" ]] then build_library static fi if [[ "$enable_relocatable" = "true" ]] then build_library relocatable fi } build_library(){ kind=$1; echo "Building $kind library"; export LIBRARY_KIND=$kind $GPRBUILD -P$work_path/lib/gnat/$project.gpr -d -q -j$processors --create-missing-dirs $gprbuild_params } ############# # File list # ############# gen_filelist(){ list="$PWD/files.list" cd "$work_path" && find * > "$list" } cat_filelist(){ if [[ -f files.list ]] then cat files.list else echo "Please remember to build $project first" >&2; fi; } # iterate over the list of files... # usage: # iterate_filelist thecommandtobexecuted iterate_filelist(){ cat_filelist | while read a; do $1 "$a";done } # Reverse iterate in the sense of listing first files than directories.. reverse_iterate_filelist(){ cat_filelist | sort -nr | while read a; do $1 "$a";done } ########### # Install # ########### install_item(){ if [[ -d "$work_path"/"$1" ]] then install_directory "$1"; else install_file "$1"; fi } install_directory(){ install -d "$prefix/$1"; } install_file(){ install "$work_path/$1" "$prefix/$1" } ############# # Uninstall # ############# uninstall_item(){ if [[ -d "$work_path"/"$1" ]] then uninstall_directory "$1"; else uninstall_file "$1"; fi } uninstall_directory(){ rmdir "$prefix/$1" || echo skipping "$prefix/$1" } uninstall_file(){ rm "$prefix/$1" } apq-3.2.0/samples/scripts/clean.sh000077500000000000000000000002571171626402600170620ustar00rootroot00000000000000#!/usr/bin/env bash source scripts/buildutil.sh load_configuration rm -rf "$work_path" rm -rf "$object_path" rm -f gnatprep.def rm -f .configuration rm -f configure.log apq-3.2.0/samples/scripts/install.sh000077500000000000000000000004241171626402600174420ustar00rootroot00000000000000#!/usr/bin/env bash # Installer for KOW Framework applications # # @author Marcelo C. de Freitas # # All this script does is to recursivelly install everything from $work_path inside $prefix source scripts/buildutil.sh load_configuration iterate_filelist install_item apq-3.2.0/samples/scripts/uninstall.sh000077500000000000000000000004551171626402600200110ustar00rootroot00000000000000#!/usr/bin/env bash # Installer for KOW Framework applications # # @author Marcelo C. de Freitas # # All this script does is to recursivelly install everything from $work_path inside $prefix source scripts/buildutil.sh load_configuration reverse_iterate_filelist uninstall_item rmdir $prefix apq-3.2.0/samples/src/000077500000000000000000000000001171626402600145355ustar00rootroot00000000000000apq-3.2.0/samples/src/apq-samples.adb000066400000000000000000000064741171626402600174430ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- B o d y -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2009, Ada Works Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- ------------------------------------------------------------------------------ with Ada.Text_IO; use Ada.Text_IO; package body APQ.Samples is procedure Query_Results( C: in out Root_Connection_Type'Class ) is Q: Root_Query_Type'Class := New_Query( C ); function Value( S: in String ) return String is begin return Value( Q, Column_Index( Q, S ) ); end Value; begin Prepare( Q, "SELECT * FROM USERS" ); Execute( Q, C ); loop begin Fetch( Q ); exception when No_Tuple => exit; end; Put( "Name: " & Value( "Name" ) ); Put( " | " ); Put( "Birth date: " & Value( "Birth" ) ); New_Line; end loop; end Query_Results; procedure Insert_Value( C: in out Root_Connection_Type'Class; Name: in String; Birth: in APQ_Date ) is Q: Root_Query_Type'Class := New_Query( C ); begin Prepare( Q, "INSERT INTO USERS(Name, Birth) VALUES(" ); Append_Quoted( Q, C, Name, "," ); Append( Q, Birth, ")" ); Execute( Q, C ); end Insert_Value; end APQ.Samples; apq-3.2.0/samples/src/apq-samples.ads000066400000000000000000000051511171626402600174530ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- S p e c -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2009, Ada Works Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- ------------------------------------------------------------------------------ package APQ.Samples is procedure Query_Results( C: in out Root_Connection_Type'Class ); procedure Insert_Value( C: in out Root_Connection_Type'Class; Name: in String; Birth: in APQ_Date ); end APQ.Samples; apq-3.2.0/scripts/000077500000000000000000000000001171626402600137715ustar00rootroot00000000000000apq-3.2.0/scripts/build.sh000077500000000000000000000011711171626402600154270ustar00rootroot00000000000000#!/usr/bin/env bash # # Builder for the KOW Framework project # # All it actually does is to call gprbuild several times ################## # Initialization # ################## source scripts/buildutil.sh load_configuration echo $KOWLIB_EXTERNALLY_BUILT if [[ "$enable_debug" = "true" ]] then echo "############################"; echo "# Building Debug Libraries #"; echo "############################"; export DEBUG="true"; build_libraries; fi echo "##############################"; echo "# Building Regular Libraries #"; echo "##############################"; export DEBUG="false"; build_libraries; gen_filelist; apq-3.2.0/scripts/buildutil.sh000077500000000000000000000132701171626402600163300ustar00rootroot00000000000000#!/usr/bin/env bash # # Auxiliary functions for the KOW Framework main build system # # @author Marcelo C. de Freitas ###################### # Environment Checks # ###################### # Check if a given command is in path; # usage: # check_in_path COMMAND_NAME check_in_path(){ echo -n "Looking for $1 ... " hash $1 2>&- || { echo "[false]"; echo >&2 "I need $1 in path but I can't find it... aborting"; exit 1; } && echo "[ok]" } # Check if a project file is available # usage: # check_project projectname check_project(){ proj=$1; echo -n "Looking for project $proj ... " ${GPRBUILD} -ws -P$proj 2>&- || { echo "[false]"; echo "${GPRBUILD} can't find $proj in ADA_PROJECT_PATH"; exit -1;} && echo "[ok]"; } # Copy updating a regular file or directory # usage: # cpu origin destination cpu(){ origin="$1" fname=$(basename "$1") destination="$2/$fname" if [[ -f "$origin" ]] then if [[ "$origin" -nt "$destination" ]] then cp "$origin" "$destination" else echo "Skipping \"$origin\"" >> configure.log fi else echo "Can't copy (not a regular file): \"$origin\"" >&2 exit 1; fi } ############################ # Configuration Management # ############################ # reset the configuration file init_configuration(){ echo -n "" > .configuration } # Set a configuration key/value: # usage: # setconfiguration key value set_configuration() { echo export $1=\"$2\" >> .configuration } # Printout the configuration file # usage: # cat_configuration cat_configuration(){ cat .configuration } # load the configuration file: # usage: # load_configuration load_configuration(){ if [[ -f .configuration ]] then source .configuration else echo "Please run configure first" >&2; exit 1; fi } ################### # Data Processing # ################### # iterate for printing a list of declarations, used internally by print_enum_declaration and print_for_declaration # usage: # iterate_enum_list "the list of values" echo_function_name # # The list of values should respect the format: # number name # number name # number name # number name # # and eatch line is trimmed before calling the given function iterate_enum_list(){ local is_first=1; echo "$1" | while read a do if [[ "$a" = "" ]] then echo -n #skip empty lines else if [[ $is_first -eq 1 ]] then is_first=0; else echo ','; fi; echo -n " "; $2 $a fi done echo; } _enum_declaration(){ echo -n $2; } # For each entry print as expected for the enum declaration type echo_enum_declaration(){ iterate_enum_list "$1" _enum_declaration } _for_declaration(){ echo -n "$2 => $1"; } echo_for_declaration(){ iterate_enum_list "$1" _for_declaration } # Will set a enum value using the same list as the one used in iterate_enum_list # in the given file (edit the given file). # usage: # set_enum_values FILE LIST_OF_VALUES PREFIX # # This will replace: # %${PREFIX}_DECLARATION% with the result of echo_enum_declaration # %${PREFIX}_FOR% with the result of echo_for_declaration # set_enum_values(){ local outfile="$1" local values="$2" local prefix="$3" declaration_values=`echo_enum_declaration "$values"` for_values=`echo_for_declaration "$values"` replace_in_file "$outfile" "%${prefix}_DECLARATION%" "$declaration_values" replace_in_file "$outfile" "%${prefix}_FOR%" "$for_values" echo "[ok]" } # Simple str_replace in a file # usage # replace_in_file FILENAME FROM TO replace_in_file(){ filename="$1" from="$2" to=$(echo "$3" | sed -e 's/$/\\&/' | sed -e 's/\//\\&/g' ); sed -i -e "s/$from/$to /" "$filename" } ################################ # Gnatprep def file management # ################################ # see the documentation for configuration files; basically the same thing init_gnatprep() { echo -n "" > gnatprep.def } set_gnatprep(){ echo $1:=\"$2\" >> gnatprep.def } # transform a list of parameters in a format both sed and gprbuild will understand... # the output of this function is meant to be used by replace_in_file, which processes / and new lines sedfy_gpr_list(){ is_first=1 for option in $1 do if [[ $is_first -eq 1 ]] then is_first=0; else echo -n "," fi #option=`echo $i | sed 's/\//\\\&/g'` echo -n \\\"$option\\\" done } ############ # Building # ############ build_libraries(){ if [[ "$enable_static" = "true" ]] then build_library static fi if [[ "$enable_relocatable" = "true" ]] then build_library relocatable fi } build_library(){ kind=$1; echo "Building $kind library"; export LIBRARY_KIND=$kind $GPRBUILD -P$work_path/lib/gnat/$project.gpr -d -q -j$processors --create-missing-dirs $gprbuild_params } ############# # File list # ############# gen_filelist(){ list="$PWD/files.list" cd "$work_path" && find * > "$list" } cat_filelist(){ if [[ -f files.list ]] then cat files.list else echo "Please remember to build $project first" >&2; fi; } # iterate over the list of files... # usage: # iterate_filelist thecommandtobexecuted iterate_filelist(){ cat_filelist | while read a; do $1 "$a";done } # Reverse iterate in the sense of listing first files than directories.. reverse_iterate_filelist(){ cat_filelist | sort -nr | while read a; do $1 "$a";done } ########### # Install # ########### install_item(){ if [[ -d "$work_path"/"$1" ]] then install_directory "$1"; else install_file "$1"; fi } install_directory(){ install -d "$prefix/$1"; } install_file(){ install "$work_path/$1" "$prefix/$1" } ############# # Uninstall # ############# uninstall_item(){ if [[ -d "$work_path"/"$1" ]] then uninstall_directory "$1"; else uninstall_file "$1"; fi } uninstall_directory(){ rmdir "$prefix/$1" || echo skipping "$prefix/$1" } uninstall_file(){ rm "$prefix/$1" } apq-3.2.0/scripts/clean.sh000077500000000000000000000003001171626402600154030ustar00rootroot00000000000000#!/usr/bin/env bash source scripts/buildutil.sh load_configuration rm -rf "$work_path" rm -rf "$object_path" rm -f gnatprep.def rm -f .configuration rm -f configure.log rm -f files.list apq-3.2.0/scripts/install.sh000077500000000000000000000004241171626402600157760ustar00rootroot00000000000000#!/usr/bin/env bash # Installer for KOW Framework applications # # @author Marcelo C. de Freitas # # All this script does is to recursivelly install everything from $work_path inside $prefix source scripts/buildutil.sh load_configuration iterate_filelist install_item apq-3.2.0/scripts/uninstall.sh000077500000000000000000000004551171626402600163450ustar00rootroot00000000000000#!/usr/bin/env bash # Installer for KOW Framework applications # # @author Marcelo C. de Freitas # # All this script does is to recursivelly install everything from $work_path inside $prefix source scripts/buildutil.sh load_configuration reverse_iterate_filelist uninstall_item rmdir $prefix apq-3.2.0/src/000077500000000000000000000000001171626402600130715ustar00rootroot00000000000000apq-3.2.0/src/apq.adb000066400000000000000000001667571171626402600143500ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- S p e c -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2011, KOW Framework Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- ------------------------------------------------------------------------------ with APQ_Helper; with Ada.Calendar.Formatting; with Ada.Characters.Latin_1; with Ada.Strings.Fixed; with Ada.Characters.Handling; package body APQ is type Time_Unit is ( Hour, Minute, Second ); ---------------- -- EXCEPTIONS -- ---------------- function To_Pattern_Array(Zero: in String) return Pattern_Array is -- return a Pattern array that maps from 0 to Zero. A: Pattern_Array := ( 0 => To_Unbounded_String(Zero)); begin return A; end To_Pattern_Array; function To_Pattern_Array(Zero, One: in String) return Pattern_Array is -- same as the previous, but including both zero and one. A: Pattern_Array := ( 0 => To_Unbounded_String(Zero) , 1 => To_Unbounded_String(One) ); begin return A; end To_Pattern_Array; function To_Pattern_Array(Zero, One, Two: in String) return Pattern_Array is -- same as the previous, but including both zero, one and two. A: Pattern_Array := ( 0 => To_Unbounded_String(Zero), 1 => To_Unbounded_String(One), 2 => To_Unbounded_String(Two) ); begin return A; end To_Pattern_Array; procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero: in String := "" ) is -- Raise the Exception E with a comprehensive error message Pragma Inline(Raise_APQ_Error_Exception); A: Pattern_Array := To_Pattern_Array( Zero ); begin Raise_APQ_Error_Exception( E, Code, Where, A ); end Raise_APQ_Error_Exception; procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero, One: in String ) is -- Raise the Exception E with a comprehensive error message Pragma Inline(Raise_APQ_Error_Exception); A: Pattern_Array := To_Pattern_Array( Zero, One ); begin Raise_APQ_Error_Exception( E, Code, Where, A ); end Raise_APQ_Error_Exception; procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero, One, Two: in String ) is -- Raise the Exception E with a comprehensive error message Pragma Inline(Raise_APQ_Error_Exception); A: Pattern_Array := To_Pattern_Array( Zero, One, Two ); begin Raise_APQ_Error_Exception( E, Code, Where, A ); end Raise_APQ_Error_Exception; procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Patterns: in Pattern_Array ) is -- Raise the Exception E with a comprehensive error message use Ada.Strings; -- for selecting the sides to Trim use Ada.Strings.Fixed; -- Trim use APQ_Helper; -- Str_Replace function Process_Message return String is Desc: Unbounded_String := Unbounded_String(APQ_Error_Descriptions(Code)); function Get_Pattern( i: in Integer ) return Unbounded_String is -- TODO: change the following line to a decent (and a LOT faster) implementation: P: String := "%" & Trim( Integer'Image( i ), Ada.Strings.Both ) & "%"; begin return To_Unbounded_String( P ); end Get_Pattern; begin for i in Patterns'Range loop Desc := Str_Replace( From => Get_Pattern(i), To => Patterns(i), Str => Desc ); end loop; return To_String( Desc ); end Process_Message; Message : String := "[" & APQ_Error'Image(Code) & " @ " & Where & "] " & Process_Message; begin Raise_Exception( E, Message ); end Raise_APQ_Error_Exception; ---------------------------------------------------------------------------------- -- IMPLEMENTED METHODS FOR BOTH -- -- . Root_Connection_Type and -- -- . Root_Query_Type -- ---------------------------------------------------------------------------------- -- These methods are provided by the APQ base package but the driver implementor-- -- might provide their own implementations. -- -- Those methods, in their original implementation, make use of the abstract -- -- methods defined in the previous code session. -- ---------------------------------------------------------------------------------- function New_Query(C : Root_Connection_Type'Class) return Root_Query_Type'Class is -- Use this function to create a new query object for your connection. Q : Root_Query_Type'Class := Query_Factory(C); begin Q.SQL_Case := C.SQL_Case; -- Preserve setting in connection return Q; end New_Query; -------------------------- -- ROOT_CONNECTION_TYPE -- -------------------------- function Get_Case(C : Root_Connection_Type) return SQL_Case_Type is -- Get the SQL case used by default in this connection. -- All new queries will use this casing. begin return C.SQL_Case; end Get_Case; procedure Set_Case(C : in out Root_Connection_Type; SQL_Case : SQL_Case_Type) is -- Set the SQL case used by default in this connection. -- All new queries will use this casing. begin C.SQL_Case := Set_Case.SQL_Case; end Set_Case; function Get_Instance(C : Root_Connection_type) return String is -- Get the instance Name for the Database. begin return To_String(C.Instance); end Get_Instance; procedure Set_Instance(C : in out Root_Connection_Type; Instance : String) is -- Set the instance Name for the Database. begin Replace_String(C.Instance,""); Replace_String(C.Instance,Instance); end Set_Instance; function Get_Host_Name(C : Root_Connection_Type) return String is -- Get the host name for the Database server. begin return To_String(C.Host_Name); end Get_Host_Name; procedure Set_Host_Name(C : in out Root_Connection_Type; Host_Name : String) is -- Set the host name for the Database server. begin Replace_String(C.Host_Address,""); Replace_String(C.Host_Name,Set_Host_Name.Host_Name); c.Port_Format := UNIX_Port; end Set_Host_Name; function Get_Host_Address( C: in Root_Connection_Type ) return String is -- Set the host address for the database server. begin return To_String( C.Host_Address ); end Get_Host_Address; procedure Set_Host_Address(C : in out Root_Connection_Type; Host_Address : String) is -- Set the host address for the database server. begin Replace_String(C.Host_Name,""); Replace_String(C.Host_Address, Set_Host_Address.Host_Address); c.Port_Format := IP_Port; end Set_Host_Address; function Get_Port(C : Root_Connection_Type) return Integer is -- Get the TCP port number. begin case C.Port_Format is when IP_Port => return C.Port_Number; when UNIX_Port => Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ01, Where => "Port" ); return 0; -- so GNAT won't complaint end case; end Get_Port; procedure Set_Port(C : in out Root_Connection_Type; Port_Number : Integer) is -- Set the TCP port number. begin C.Port_Format := IP_Port; C.Port_Number := Set_Port.Port_Number; end Set_Port; function Get_Port(C : Root_Connection_Type) return String is -- Get the Unix Port. begin case C.Port_Format is when IP_Port => Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ02, Where => "Port" ); return ""; -- so GNAT won't complaint when UNIX_Port => return To_String(C.Port_Name); end case; end Get_Port; procedure Set_Port(C : in out Root_Connection_Type; Port_Name : String) is -- Set the Unix Port begin C.Port_Format := UNIX_Port; Free_Ptr(C.Port_Name); C.Port_Name := new String(1..Port_Name'Length); C.Port_Name.all := Set_Port.Port_Name; end Set_Port; function Get_DB_Name(C : Root_Connection_Type) return String is -- Get the Database name used in this connection. begin return To_String(C.DB_Name); end Get_DB_Name; procedure Set_DB_Name(C : in out Root_Connection_Type; DB_Name : String) is -- Set the Database name used in this connection. begin Replace_String(C.DB_Name,Set_DB_Name.DB_Name); end Set_DB_Name; function Get_User( C: in Root_Connection_Type ) return String is -- Get the Username for this connection. begin return To_String(C.User_Name); end Get_User; procedure Set_User( C: in out Root_Connection_Type; User: in String ) is -- Set the Username for this connection. begin Replace_String( C.User_Name, User ); end Set_User; function Get_Password( C: Root_Connection_Type ) return String is -- Get the Password for this connection. begin return To_String( C.User_Password ); end Get_Password; procedure Set_Password( C: in out Root_Connection_Type; Password: in String ) is -- Get the Password for this connection. begin Replace_String( C.User_Password, Password ); end Set_Password; procedure Set_User_Password(C : in out Root_Connection_Type; User_Name, User_Password : String) is -- Set both the username and the password for this connection. begin Set_User( C, Set_User_Password.User_Name ); Set_Password( C, Set_User_Password.User_Password ); end Set_User_Password; function In_Abort_State(C : Root_Connection_Type) return Boolean is -- Some database products (eg, PostgreSQL) can enter in a status where -- every operation is ignored. -- There is the Abort_State Exception for this, but there is also -- this function that checks if the connection is in this state. begin return C.Abort_State; end In_Abort_State; function Get_Rollback_On_Finalize(C : Root_Connection_Type) return Boolean is -- Get if the work will be rollbacked when finalizing. begin return C.Rollback_Finalize; end Get_Rollback_On_Finalize; procedure Set_Rollback_On_Finalize(C : in out Root_Connection_Type; Rollback : Boolean) is -- Set if the work will be rollbacked when finalizing begin C.Rollback_Finalize := Rollback; end Set_Rollback_On_Finalize; procedure Set_Auto_Reconnect( C : in out Root_Connection_Type; Auto_Reconnect : in Boolean := True ) is -- set if it should reconnect automatically when the connection is droped. begin C.Auto_Reconnect := Auto_Reconnect; end Set_Auto_Reconnect; function Get_Auto_Reconnect( C : in Root_Connection_Type ) return Boolean is -- return true if the connection should be automatically restablished when droped begin return C.Auto_Reconnect; end Get_Auto_Reconnect; --------------------- -- ROOT_QUERY_TYPE -- --------------------- -- Query setup ... function Get_Case(Q : Root_Query_Type) return SQL_Case_Type is -- Get the case used by this query -- This case might be different from the one used by default begin return Q.SQL_Case; end Get_Case; procedure Set_Case(Q : in out Root_Query_Type; SQL_Case : SQL_Case_Type) is -- Set the case used by this query. begin Q.SQL_Case := Set_Case.SQL_Case; end Set_Case; function Get_Fetch_Mode(Q : Root_Query_Type) return Fetch_Mode_Type is -- Get the fetch mode used by this query. begin return Q.Mode; end Get_Fetch_Mode; procedure Set_Fetch_Mode(Q : in out Root_Query_Type; Mode : Fetch_Mode_Type) is -- Set the fetch mode used by this query. begin Q.Mode := Mode; end Set_Fetch_Mode; procedure Raise_Exceptions(Query : in out Root_Query_Type; Raise_On : Boolean := True) is -- when Execute_Checked is called, should raise the exception back to the caller? begin Query.Raise_Exceptions := Raise_On; end Raise_Exceptions; procedure Report_Errors(Query : in out Root_Query_Type; Report_On : Boolean := True) is -- report sql erros when Execute_Checked is called? begin Query.Report_Errors := Report_On; end Report_Errors; -- Query information ... function To_String(Query : Root_Query_Type) return String is -- get the query text use Ada.Characters.Latin_1; Total_Length : Natural := 0; Append_NL : Boolean := False; begin for X in 1..Query.Count loop Total_Length := Total_Length + Query.Collection(X).all'Length; end loop; if Total_Length <= 0 then return ""; -- No query started end if; Append_NL := Query.Collection(Query.Count).all(Query.Collection(Query.Count).all'Last) /= LF; if Append_NL then Total_Length := Total_Length + 1; end if; declare Return_String : String(1..Total_Length); RX : Positive := Return_String'First; EX : Positive; begin for X in 1..Query.Count loop EX := RX + Query.Collection(X).all'Length - 1; case Query.SQL_Case is when Preserve_Case => Return_String(RX..EX) := Query.Collection(X).all; when Upper_Case | Lower_Case => if Query.Caseless(X) = True then Return_String(RX..EX) := To_Case(Query.Collection(X).all,Query.SQL_Case); else Return_String(RX..EX) := Query.Collection(X).all; end if; end case; RX := EX + 1; end loop; if Append_NL then Return_String(Return_String'Last) := LF; end if; return Return_String; end; end To_String; function Is_Select(Q : Root_Query_Type) return Boolean is -- is this query a select statement? begin if Q.Count < 1 then return False; end if; declare use Ada.Characters.Handling, Ada.Strings, Ada.Strings.Fixed; -- Get start of query : Query_Start : String := To_Upper(Trim(Q.Collection(1).all,Left)); begin return Query_Start'Length >= 6 and then Query_Start(1..6) = "SELECT"; end; end Is_Select; function Cursor_Name(Query : Root_Query_Type) return String is -- get the cursor name for the current result -- this function is meant to be overwriten by the driver if it supports cursor begin Raise_APQ_Error_Exception( E => Not_Supported'Identity, Code => APQ28, Where => "Cursor_Name"); return "?"; -- For compiler only end Cursor_Name; -- SQL creation ... procedure Clear(Q : in out Root_Query_Type) is -- Clear the query so one can start a new SQL expression. begin for X in 1..Q.Count loop Free_Ptr(Q.Collection(X)); end loop; Free(Q.Collection); Q.Count := 0; Q.Tuple_Index := Tuple_Index_Type'First; Q.Rewound := True; end Clear; procedure Grow(Q : in out Root_Query_Type) is -- used internally to grow the query size so Append works begin if Q.Count <= 0 then Q.Alloc := 64; Q.Collection := new String_Ptr_Array(1..Q.Alloc); Q.Caseless := new Boolean_Array(1..Q.Alloc); elsif Q.Count >= Q.Alloc then declare New_Alloc : Natural := Q.Alloc + 128; New_Array : String_Ptr_Array_Access := new String_Ptr_Array(1..New_Alloc); New_Case : Boolean_Array_Access := new Boolean_Array(1..New_Alloc); begin New_Array(1..Q.Alloc) := Q.Collection.all; New_Case(1..Q.Alloc) := Q.Caseless.all; Free(Q.Collection); Free(Q.Caseless); Q.Alloc := New_Alloc; Q.Collection := New_Array; Q.Caseless := New_Case; end; end if; end Grow; procedure Prepare(Q : in out Root_Query_Type; SQL : String; After : String := Line_Feed) is -- Clear the query, starting a new one. begin Clear(Root_Query_Type'Class(Q)); Append(Root_Query_Type'Class(Q),SQL,After); end Prepare; procedure Append(Q : in out Root_Query_Type; SQL : String; After : String := "") is -- Append a string to the query use Ada.Characters.Latin_1; NSL : Natural := SQL'Length + After'Length; begin Grow(Q); Q.Count := Q.Count + 1; Q.Collection(Q.Count) := new String(1..NSL); Q.Collection(Q.Count).all(1..SQL'Length) := SQL; Q.Collection(Q.Count).all(SQL'Length+1..NSL) := After; Q.Caseless(Q.Count) := True; -- Don't preserve case end Append; procedure Append(Q: in out Root_Query_Type; SQL: in Ada.Strings.Unbounded.Unbounded_String; After: String := "") is -- Append an Unbounded_String to the query Pragma Inline(Append); begin Append( Q, Ada.Strings.Unbounded.To_String( SQL ), After ); end Append; -- procedure Append(Q : in out Root_Query_Type; SQL : Ada.Strings.Unbounded.Unbounded_String; After : String := "") is -- use Ada.Characters.Latin_1, Ada.Strings.Unbounded; -- Len : Natural := Length(SQL); -- NSL : Natural := Len + After'Length; -- begin -- Grow(Q); -- Q.Count := Q.Count + 1; -- Q.Collection(Q.Count) := new String(1..NSL); -- Q.Collection(Q.Count).all(1..Len) := To_String(SQL); -- Q.Collection(Q.Count).all(Len+1..NSL) := After; -- Q.Caseless(Q.Count) := True; -- Don't preserve case -- end Append; procedure Append_Line(Q : in out Root_Query_Type; SQL : String := "") is New_Line : String(1..1); begin New_Line(1) := Ada.Characters.Latin_1.LF; Append(Q, SQL, New_Line); end Append_Line; procedure Append(Q : in out Root_Query_Type; V : APQ_Boolean; After : String := "") is -- Append a boolean to the query begin Append(Root_Query_Type'Class(Q),To_String(V),After); end Append; procedure Append(Q : in out Root_Query_Type; V : APQ_Date; After : String := "") is -- Append a date to the query use Ada.Calendar; S : String := To_String(V); begin Append(Root_Query_Type'Class(Q),"'",S); Append(Root_Query_Type'Class(Q),"'",After); end Append; procedure Append(Q : in out Root_Query_Type; V : APQ_Time; After : String := "") is -- Append a time... use Ada.Calendar; S : String := To_String(V); begin Append(Root_Query_Type'Class(Q),"'",S); Append(Root_Query_Type'Class(Q),"'",After); end Append; procedure Append(Q : in out Root_Query_Type; V : APQ_Timestamp; After : String := "") is -- Append a timestamp... use Ada.Calendar; D : String := To_String(V); begin Append(Root_Query_Type'Class(Q),"'",D); Append(Root_Query_Type'Class(Q),"'",After); end Append; procedure Append(Q : in out Root_Query_Type; V : Row_ID_Type; After : String := "") is -- Append a row_id_type... function To_String is new Modular_String(Row_ID_Type); begin Append(Root_Query_Type'Class(Q),To_String(V),After); end Append; procedure Append(Q : in out Root_Query_Type; V : APQ_Bitstring; After : String := "") is -- Append a bitstring... S : String := To_String(V); begin Append(Root_Query_Type'Class(Q),"B'",S); Append(Root_Query_Type'Class(Q),"'",After); end Append; procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : String; After : String := "") is -- Append a quoted String. -- The case of this String isn't changed. -- This primitive should normally be overriden for a specific database. -- PostgreSQL and MySQL will potentially have different quoting requirements. begin Append(Root_Query_Type'Class(Q),"'" & SQL & "'",After); Q.Caseless(Q.Count) := False; -- Preserve case here end Append_Quoted; procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; After : String := "") is -- Append a quoted String. -- The case of this String isn't changed. -- This primitive should normally be overriden for a specific database. -- PostgreSQL and MySQL will potentially have different quoting requirements. begin Append_Quoted(Root_Query_Type'Class(Q),Connection,Ada.Strings.Unbounded.To_String(SQL),After); end Append_Quoted; -- Data retrieval: procedure Value(Query: Root_Query_Type; CX : Column_Index_Type; V : out String) is -- Get the value of the CXth column as String. -- Fixed length String Fetch S : String := Value(Root_Query_Type'Class(Query),CX); begin if S'Length = V'Length then V := S; elsif S'Length > V'Length then Raise_APQ_Error_Exception( E => Small_Buffer'Identity, Code => APQ09, Where => "Value", Zero => Column_Index_Type'Image(CX) ); else V(V'First..S'Length) := S; V(S'Length+1..V'Last) := ( others => ' ' ); end if; end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Ada.Strings.Unbounded.Unbounded_String is -- Get the value of the CXth column as Unbounded_String. use Ada.Strings.Unbounded; Str: String := Value(Root_Query_Type'Class(Query),CX); begin return To_Unbounded_String(Str); end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Row_ID_Type is -- Get the value of the CXth column as Row_Id_Type. S : String := Value(Root_Query_Type'Class(Query),CX); begin return Row_ID_Type'Value(S); exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ08, Where => "Value", Zero => Column_Index_Type'Image(CX) ); return 0; -- so GNAT won't complaint end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Bitstring is -- Get the value of the CXth column as Bitstring. use Ada.Strings, Ada.Strings.Fixed; S : String := Trim(Value(Root_Query_Type'Class(Query),CX),Both); R : APQ_Bitstring(1..S'Length); begin for X in S'Range loop R(X) := S(X) /= '0'; end loop; return R; end Value; -- METHODS THAT SHOULD BE OVERRIDDEN BY THE DATABASE DRIVER -- function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Boolean is V : Integer := Value(Root_Query_Type'Class(Query),CX); begin if V = 0 then return FALSE; else return TRUE; end if; exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ10, Where => "Value (Returns Boolean)", Zero => Column_Index_Type'Image(CX) ); return false; -- we return something so gnat won't complaint end Value; --TODO: Solve a possible problem with databases that can store values bigger or smaller than Integer. function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Integer is S : String := Value(Root_Query_Type'Class(Query), CX); begin return Integer'Value(S); exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ11, Where => "Value (Returns Integer)", Zero => Column_Index_Type'Image(CX) ); end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Float is S : String := Value(Root_Query_Type'Class(Query), CX); begin return Float'Value(S); exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ13, Where => "Value (Returns Float)", Zero => Column_Index_Type'Image(CX) ); end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Date is function To_Date is new Convert_To_Timestamp(APQ_Date); begin return To_Date( S => Value( Root_Query_Type'Class( Query ), CX ) & " 03:03:03", TZ => Ada.Calendar.Time_Zones.UTC_Time_Offset( Ada.Calendar.Clock ) ); exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ17, Where => "Value (Returns APQ_Date)", Zero => Column_Index_Type'Image(CX) ); when Invalid_Format => Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ18, Where => "Value (Returns APQ_Date)", Zero => Value( Root_Query_Type'Class(Query), CX ), One => Column_Index_Type'Image(CX) ); end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Time is function To_Time is new Convert_To_Time(APQ_Time); Text : String := Value(Root_Query_Type'Class(Query),CX); begin return To_Time(Text); exception when Constraint_Error => Raise_APQ_Error_Exception( E => Constraint_Error'Identity, Code => APQ19, Where => "Value (Returns APQ_Time)", Zero => Value(Root_Query_Type'Class(Query), CX), One => Column_Index_Type'Image(CX) ); end Value; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Timestamp is function To_Timestamp is new Convert_To_Timestamp( APQ_Timestamp ); Text : String := Value( Root_Query_Type'Class( Query ), CX ); begin return To_Timestamp( S => Text, TZ => 0 ); exception when Constraint_Error | Invalid_Format => Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ20, Where => "Value (Returns APQ_Timestamp)", Zero => Value(Root_Query_Type'Class(Query), CX), One => Column_Index_Type'Image(CX) ); end Value; ---------------------------------------------------------------------------------- -- GENERIC METHODS FOR -- -- . Root_Query_Type -- ---------------------------------------------------------------------------------- -- These methods are implemented using the abstract and implemented methods -- -- that are listed before this block. -- -- -- -- They are meant to enforce strong typing with Database programming. -- ---------------------------------------------------------------------------------- -- SQL creation :: append ... procedure Append_Boolean(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is begin Append( Q, APQ_Boolean( V ), After ); end Append_Boolean; procedure Append_Integer(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Integer_String(Val_Type); S : String := To_String(V); begin Append(Root_Query_Type'Class(Q),S,After); end Append_Integer; procedure Append_Modular(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Modular_String(Val_Type); S : String := To_String(V); begin Append(Root_Query_Type'Class(Q),S,After); end Append_Modular; procedure Append_Float(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Float_String(Val_Type); begin Append(Root_Query_Type'Class(Q),To_String(V),After); end Append_Float; procedure Append_Fixed(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new APQ.Fixed_String(Val_Type); begin Append(Root_Query_Type'Class(Q),To_String(V),After); end Append_Fixed; procedure Append_Decimal(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Decimal_String(Val_Type); begin Append(Root_Query_Type'Class(Q),To_String(V),After); end Append_Decimal; procedure Append_Date(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Date_String(Val_Type); begin Append(Root_Query_Type'Class(Q),"'",To_String(V)); Append(Root_Query_Type'Class(Q),"'",After); end Append_Date; procedure Append_Time(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Time_String(Val_Type); begin Append(Root_Query_Type'Class(Q),"'",To_String(V)); Append(Root_Query_Type'Class(Q),"'",After); end Append_Time; procedure Append_Timestamp(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is function To_String is new Timestamp_String(Val_Type); begin Append(Root_Query_Type'Class(Q),"'",To_String(V)); Append(Root_Query_Type'Class(Q),"'",After); end Append_Timestamp; procedure Append_Bitstring(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := "") is begin Append(Root_Query_Type'Class(Q),To_String(APQ_Bitstring(V)),After); end Append_Bitstring; procedure Append_Bounded(Q : in out Root_Query_Type'Class; SQL : P.Bounded_String; After : String := "") is begin Append(Root_Query_Type'Class(Q),P.To_String(SQL),After); end Append_Bounded; procedure Append_Bounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : P.Bounded_String; After : String := "") is begin Append_Quoted(Root_Query_Type'Class(Q),Connection,P.To_String(SQL),After); end Append_Bounded_Quoted; -- SQL creation :: encode... -- encode is the same as append, but supporting null values. procedure Encode_Boolean(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Boolean(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Boolean; procedure Encode_Integer(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Integer(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Integer; procedure Encode_Modular(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Modular(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Modular; procedure Encode_Float(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Float(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Float; procedure Encode_Fixed(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Fixed(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Fixed; procedure Encode_Decimal(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Decimal(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Decimal; procedure Encode_Date(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Date(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Date; procedure Encode_Time(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure Append is new Append_Time(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),V,After); end if; end Encode_Time; procedure Encode_Timestamp(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure App is new Append_Timestamp(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else App(Root_Query_Type'Class(Q),V,After); end if; end Encode_Timestamp; procedure Encode_Bitstring(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := "") is procedure App is new Append_Bitstring(Val_Type); begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else App(Root_Query_Type'Class(Q),V,After); end if; end Encode_Bitstring; procedure Encode_String_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : String; Indicator : Ind_Type; After : String := "") is begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append_Quoted(Root_Query_Type'Class(Q),Connection,SQL,After); end if; end Encode_String_Quoted; procedure Encode_Bounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : P.Bounded_String; Indicator : Ind_Type; After : String := "") is begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append_Quoted(Root_Query_Type'Class(Q),Connection,P.To_String(SQL),After); end if; end Encode_Bounded_Quoted; procedure Encode_Unbounded(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; Indicator : Ind_Type; After : String := "") is use Ada.Strings.Unbounded; begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append(Root_Query_Type'Class(Q),To_String(SQL),After); end if; end Encode_Unbounded; procedure Encode_Unbounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; Indicator : Ind_Type; After : String := "") is use Ada.Strings.Unbounded; begin if Indicator then Append(Root_Query_Type'Class(Q),"NULL",After); else Append_Quoted(Root_Query_Type'Class(Q),Connection,To_String(SQL),After); end if; end Encode_Unbounded_Quoted; -- Data retrieval :: misc ... function Column_Is_Null(Q : Root_Query_Type'Class; CX : Column_Index_Type) return Ind_Type is -- checks if the result in the CXth column is null. begin return Ind_Type(Is_Null(Root_Query_Type'Class(Q),CX)); end Column_Is_Null; -- Data retrieval :: value operations ... function Boolean_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is -- function To_Boolean is new Convert_To_Boolean(Val_Type); -- Text : String := Value(Root_Query_Type'Class(Query),CX); B: Boolean; begin B := Value( Query, CX ); return Val_Type(B); -- case Engine_Of(Query) is -- when Engine_PostgreSQL => -- return To_Boolean(Text); -- when Engine_MySQL => -- declare -- I : Integer; -- begin -- I := Integer'Value(Text); -- May raise Constraint_Error -- return Val_Type(I /= 0); -- Tinyint or Bit is TRUE when /= 0 for MySQL -- end; -- when Engine_Sybase => -- return To_Boolean(Text); -- when Engine_Other => -- return To_Boolean(Text); -- end case; end Boolean_Value; function Integer_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is -- S : String := Value(Root_Query_Type'Class(Query),CX); I : Integer; begin -- return Val_Typel'Value(S); I := Value(Query, CX); return Val_Type(I); end Integer_Value; function Modular_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is --This method may raise constraint error if the user is careless with his types. -- S : String := Value(Root_Query_Type'Class(Query),CX); I : Integer; begin -- return Val_Typel'Value(S); I := Value(Query, CX); return Val_Type(I); end Modular_Value; function Float_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is -- S : String := Value(Root_Query_Type'Class(Query),CX); F : Float; begin -- return Val_Typel'Value(S); F := Value(Query, CX); return Val_Type(F); end Float_Value; function Fixed_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is --This method may raise constraint error if the user is careless with his types. -- S : String := Value(Root_Query_Type'Class(Query),CX); F : Float; begin -- return Val_Typel'Value(S); F := Value(Query, CX); return Val_Type(F); end Fixed_Value; function Decimal_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is --This method may raise constraint error if the user is careless with his types. -- S : String := Value(Root_Query_Type'Class(Query),CX); F : Float; begin -- return Val_Typel'Value(S); F := Value(Query, CX); return Val_Type(F); end Decimal_Value; function Date_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is date : APQ_Date; begin date := Value(Query, CX); return Val_Type(date); end Date_Value; -- MySQL does not format the result: Explode it into YYYY-MM-DD HH:MM:SS format. -- -- Acceptable formats: -- -- "YYYY-MM-DD HH:MM:SS" S'Length = 19 -- 1234567890123456789 -- "YYYYMMDDHHMMSS" S'Length = 14 -- 1234567890123456789 -- "YYMMDDHHMMSS" S'Length = 12 -- function MySQL_YYYYMMDDHHMMSS(S : String) return String is --TODO: Send this method over to the mysql client. T : String(1..S'Length) := S; begin case T'Length is when 19 => return T; when 14 => return T(1..4) & "-" & T(5..6) & "-" & T(7..8) & " " & T(9..10) & ":" & T(11..12) & ":" & T(13..14); when 12 => declare YY : Natural; begin YY := Natural'Value(T(1..2)); if YY >= 50 then YY := YY + 1900; else YY := YY + 2000; end if; declare YYYY : String(1..5) := Natural'Image(YY); begin return YYYY(2..5) & "-" & T(3..4) & "-" & T(5..6) & " " & T(7..8) & ":" & T(9..10) & ":" & T(11..12); end; exception when others => raise Constraint_Error; end; when others => raise Constraint_Error; end case; end MySQL_YYYYMMDDHHMMSS; -- -- MySQL does not format the result: Explode it into YYYY-MM-DD HH:MM:SS format. -- -- Acceptable formats: -- -- "HH:MM:SS" S'Length = 8 -- 12345678 -- "HHMMSS" S'Length = 6 -- function MySQL_HHMMSS(S : String) return String is --TODO: Send this method over to the mysql client. T : String(1..S'Length) := S; begin case T'Length is when 8 => return T; when 6 => return T(1..2) & ":" & T(3..4) & ":" & T(5..6); when others => raise Constraint_Error; end case; end MySQL_HHMMSS; function Time_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is Time : APQ_Time; begin Time := Value(Query, CX); return Val_Type(Time); end Time_Value; function Timestamp_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type is Timestamp : APQ_Timestamp; begin Timestamp := Value(Query, CX); return Val_Type(Timestamp); exception when Constraint_Error | Invalid_Format => Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ20, Where => "Timestamp_Value", Zero => Value(Root_Query_Type'Class(Query), CX), One => Column_Index_Type'Image(CX) ); end Timestamp_Value; function Bounded_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return P.Bounded_String is use Ada.Strings.Bounded; begin return P.To_Bounded_String(Value(Root_Query_Type'Class(Query),CX)); end Bounded_Value; -- Data retrieval :: fetch operations ... -- They are the same as the value operations, but with null support procedure Boolean_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Boolean_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Boolean_Fetch; procedure Integer_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Integer_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Integer_Fetch; procedure Modular_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Modular_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Modular_Fetch; procedure Float_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Float_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Float_Fetch; procedure Fixed_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Fixed_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Fixed_Fetch; procedure Decimal_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Decimal_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Decimal_Fetch; procedure Date_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Date_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); end if; end Date_Fetch; procedure Time_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Time_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); else V := Val_Type'First; end if; end Time_Fetch; procedure Timestamp_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is function Value is new Timestamp_Value(Val_Type); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := Value(Root_Query_Type'Class(Query),CX); end if; end Timestamp_Fetch; procedure Bitstring_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out APQ_Bitstring; Last : out Natural; Indicator : out Ind_Type) is begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then declare B : APQ_Bitstring := Value(Root_Query_Type'Class(Query),CX); begin if B'Length > V'Length then Raise_APQ_Error_Exception( E => Small_Buffer'Identity, Code => APQ27, Where => "Bitstring_Fetch", Zero => Column_Index_Type'Image(CX) ); end if; Last := V'First + B'Length - 1; V(V'First..Last) := B; end; end if; end Bitstring_Fetch; procedure Bounded_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out P.Bounded_String; Indicator : out Ind) is use Ada.Strings, P; begin Indicator := Ind( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then declare S : String := Value(Root_Query_Type'Class(Query),CX); begin if S'Length > Max_Length then Raise_APQ_Error_Exception( E => Small_Buffer'Identity, Code => APQ26, Where => "Bounded_Fetch", Zero => Column_Index_Type'Image(CX) ); else V := To_Bounded_String(S,Error); end if; end; else V := Null_Bounded_String; end if; end Bounded_Fetch; procedure Unbounded_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Ada.Strings.Unbounded.Unbounded_String; Indicator : out Ind_Type) is use Ada.Strings.Unbounded; Str: String := Value(Root_Query_Type'Class(Query),CX); begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then V := To_Unbounded_String(Str); else V := Null_Unbounded_String; end if; end Unbounded_Fetch; procedure Char_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out String; Indicator : out Ind_Type) is begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then declare S : String := Value(Root_Query_Type'Class(Query),CX); Last : Natural := V'First + S'Length - 1; begin if S'Length > V'Length then Raise_APQ_Error_Exception( E => Small_Buffer'Identity, Code => APQ25, Where => "Char_Fetch", Zero => Column_Index_Type'Image(CX) ); end if; if S'Length > 0 then V(V'First..Last) := S; if Last < V'Last then V(Last+1..V'Last) := ( others => ' ' ); end if; else V := ( others => ' ' ); end if; end; end if; end Char_Fetch; procedure Varchar_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out String; Last : out Natural; Indicator : out Ind_Type) is begin Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) ); if not Indicator then declare S : String := Value(Root_Query_Type'Class(Query),CX); begin if S'Length > V'Length then Raise_APQ_Error_Exception( E => Small_Buffer'Identity, Code => APQ24, Where => "Varchar_Fetch", Zero => Column_Index_Type'Image(CX) ); end if; Last := V'First + S'Length - 1; V(V'First..Last) := S; end; end if; end Varchar_Fetch; -- Conversion :: anything to string (APQ primitives) ... function To_String(V : APQ_Boolean) return String is begin if V then return "1"; else return "0"; end if; end To_String; function To_String( V : APQ_Date ) return String is use Ada.Calendar; Str : constant String := Ada.Calendar.Formatting.Image( Date => V, Include_time_Fraction => False, Time_Zone => Ada.Calendar.Time_Zones.UTC_Time_Offset( V ) ); begin return Str( Str'First .. Ada.Strings.Fixed.Index( Str, " " ) ); end To_String; function To_String( V : APQ_Time ) return String is begin return Ada.Calendar.Formatting.Image( Elapsed_Time => Duration( V ), Include_Time_Fraction => True ); end To_String; function To_String( V : APQ_Timestamp ) return String is begin return Ada.Calendar.Formatting.Image( Date => Ada.Calendar.Time( V ), Include_Time_Fraction => True, Time_zone => 0 ); end To_String; function To_String(V : APQ_Bitstring) return String is S : String(V'Range); begin for X in V'Range loop if V(X) then S(X) := '1'; else S(X) := '0'; end if; end loop; return S; end To_String; -- Conversion :: anything to string (generic for derived types) ... function Modular_String(V : Val_Type) return String is use Ada.Strings.Fixed, Ada.Strings; package MODIO is new Ada.Text_IO.Modular_IO(Val_Type); S : String(1..40); begin MODIO.Put(To => S, Item => V, Base => 10); return Trim(S,Both); end Modular_String; function Integer_String(V : Val_Type) return String is use Ada.Strings.Fixed, Ada.Strings; package INTIO1 is new Ada.Text_IO.Integer_IO(Val_Type); S : String(1..40); begin INTIO1.Put(To => S, Item => V, Base => 10); return Trim(S,Both); end Integer_String; function Float_String(V : Val_Type) return String is use Ada.Strings.Fixed, Ada.Strings; package FLTIO is new Ada.Text_IO.Float_IO(Val_Type); S : String(1..50); begin FLTIO.Put(To => S, Item => V, Exp => 3); return Trim(S,Both); end Float_String; function Fixed_String(V : Val_Type) return String is use Ada.Strings.Fixed, Ada.Strings; package FXTIO is new Ada.Text_IO.Fixed_IO(Val_Type); S : String(1..50); begin FXTIO.Put(To => S, Item => V); return Trim(S,Both); end Fixed_String; function Decimal_String(V : Val_Type) return String is use Ada.Strings.Fixed, Ada.Strings; package DECIO is new Ada.Text_IO.Decimal_IO(Val_Type); S : String(1..50); begin DECIO.Put(To => S, Item => V); return Trim(S,Both); end Decimal_String; function Date_String(V : Val_Type) return String is begin return To_String(APQ_Date(V)); end Date_String; function Time_String(V : Val_Type) return String is begin return To_String(APQ_Time(V)); end Time_String; function Timestamp_String(V : Val_Type) return String is begin return To_String(APQ_Timestamp(V)); end Timestamp_String; -- Conversion :: anything from string ... function Convert_To_Boolean(S : String) return Val_Type is use Ada.Characters.Handling, Ada.Strings, Ada.Strings.Fixed; UC : String := To_Upper(Trim(S,Both)); begin if UC'Length = 1 then if UC = "T" then return True; elsif UC = "F" then return False; end if; else return Val_Type'Value( S ); end if; Raise_APQ_Error_Exception( E => Invalid_Format'Identity, Code => APQ07, Where => "Convert_To_Boolean", Zero => S ); --This is here to avoid useless warnings. return False; end Convert_To_Boolean; function Convert_To_Time(S : String) return Val_Type is -- S must be HH:MM:SS[.FFF] format begin return Val_Type( Ada.Calendar.Formatting.Value( Elapsed_Time => S ) ); end Convert_To_Time; function Convert_to_Timestamp( S : in String; TZ : in Ada.Calendar.Time_Zones.Time_Offset ) return Val_Type is D : Ada.Calendar.Time; begin D := Ada.Calendar.Formatting.Value( Date => S, Time_Zone => TZ ); return Val_Type( D ); end Convert_To_Timestamp; function Convert_Date_and_Time( DT : in Date_Type; TM : in Time_Type ) return Result_Type is -- return a new timestamp in DT's timezone at TM duration use Ada.Calendar; Year : Year_Number; Month : Month_Number; Day : Day_Number; Hour : Formatting.Hour_Number; Minute : Formatting.Minute_Number; Second : Formatting.Second_Number; Sub_Second : Formatting.Second_Duration; begin Formatting.Split( Date => Time( DT ), Year => Year, Month => Month, Day => Day, Hour => Hour, -- placeholder Minute => Minute, -- placeholder Second => Second, -- placeholder Sub_Second => Sub_Second, -- placeholder Time_Zone => Time_Zones.UTC_Time_Offset( Time( DT ) ) ); Formatting.Split( Seconds => Day_Duration( TM ), Hour => Hour, Minute => Minute, Second => Second, Sub_Second => Sub_Second ); return Result_Type( Formatting.Time_Of( Year => Year, Month => Month, Day => Day, Hour => Hour, Minute => Minute, Second => Second, Sub_Second => Sub_Second, Time_Zone => Time_Zones.UTC_Time_Offset( Time( DT ) ) ) ); end Convert_Date_and_Time; -- Misc ... function Generic_Command_Oid(Query : Root_Query_Type'Class) return Oid_Type is -- The Generic_Command_Oid causes GNAT 3.14p to fall over and die. -- -- It isn't really required, since Command_Oid(Query) can be used instead, -- and the return value converted to whatever Oid_Type is. Row : Row_ID_Type := Command_Oid(Query); begin return Oid_Type(Row); end Generic_Command_Oid; --------------------------------- -- EXTENDED CALENDAR FUNCTIONS -- --------------------------------- -- A special note on these functions: -- -- They have been split out to avoid a GNAT 3.13p compiler bug. -- internal functions ... function Time_Component(TM : Ada.Calendar.Day_Duration; Unit : Time_Unit) return Natural is S : Ada.Calendar.Day_Duration := TM; Hr : Natural range 0 .. 23; Min : Natural range 0 .. 59; begin -- Time_Component if TM >= Ada.Calendar.Day_Duration'Last then -- 00:00:00.0 of the next day. return 0; end if; Hr := Integer'Max (Integer (S / 3600 - 0.5), 0); if Unit = Hour then return Hr; end if; S := S - Duration (Hr) * 3600; Min := Integer'Max (Integer (S / 60 - 0.5), 0); if Unit = Minute then return Min; end if; S := S - Duration (Min) * 60; return Integer'Max (Integer (S - 0.5), 0); end Time_Component; function Internal_Time_of_Day(DT : Ada.Calendar.Time) return Ada.Calendar.Day_Duration is use Ada.Calendar; Year : Year_Number; Month : Month_Number; Day : Day_Number; Seconds : Day_Duration; begin Split(DT,Year,Month,Day,Seconds); return Seconds; end Internal_Time_of_Day; -- implementation of the package spec ... function Generic_Time_of_Day(V : Date_Type) return Time_Type is begin return Time_Type(Internal_Time_of_Day(Ada.Calendar.Time(V))); end Generic_Time_of_Day; function Generic_Hour(TM : Time_Type) return Hour_Number is begin return Hour_Number(Time_Component(Ada.Calendar.Day_Duration(TM),Hour)); end Generic_Hour; function Generic_Minute(TM : Time_Type) return Minute_Number is begin return Minute_Number(Time_Component(Ada.Calendar.Day_Duration(TM),Minute)); end Generic_Minute; function Generic_Second(TM : Time_Type) return Second_Number is begin return Second_Number(Time_Component(Ada.Calendar.Day_Duration(TM),Second)); end Generic_Second; -- private function To_Case(S : String; C : SQL_Case_Type) return String is -- convert the string to the selected case use Ada.Characters.Handling; begin case C is when Preserve_Case => return S; when Lower_Case => return To_Lower(S); when Upper_case => return To_Upper(S); end case; end To_Case; procedure Clear_Abort_State(C : in out Root_Connection_Type) is begin C.Abort_State := False; end Clear_Abort_State; procedure Adjust(Q : in out Root_Query_Type) is begin Q.Count := 0; Q.Alloc := 0; Q.Collection := null; Q.Caseless := null; Q.Tuple_Index := Tuple_Index_Type'First; end Adjust; function Is_Insert(Q : Root_Query_Type) return Boolean is begin if Q.Count < 1 or else Q.Collection = null then return False; end if; declare use Ada.Characters.Handling; SQL : String := To_Upper(Q.Collection(Q.Collection'First).all); X : Positive := SQL'First; begin while X <= SQL'Last loop exit when SQL(X) /= ' '; X := X + 1; end loop; if X + 5 > SQL'Last then return False; end if; return SQL(X..X+5) = "INSERT"; end; end Is_Insert; function Is_Update(Q : Root_Query_Type) return Boolean is begin if Q.Count < 1 or else Q.Collection = null then return False; end if; declare use Ada.Characters.Handling; SQL : String := To_Upper(Q.Collection(Q.Collection'First).all); X : Positive := SQL'First; begin while X <= SQL'Last loop exit when SQL(X) /= ' '; X := X + 1; end loop; if X + 5 > SQL'Last then return False; end if; return SQL(X..X+5) = "UPDATE"; end; end Is_Update; procedure Free_Ptr(SP : in out String_Ptr) is begin if SP /= null then Free(SP); end if; end Free_Ptr; function To_String(S : String_Ptr) return String is begin if S /= null then return S.all; else return ""; end if; end To_String; function To_Ada_String(P : Interfaces.C.Strings.chars_ptr) return String is use Interfaces.C, Interfaces.C.Strings; begin if P = Null_Ptr then return ""; end if; return To_Ada(Value(P)); end To_Ada_String; function Blanks_To_Zero(S : String) return String is R : String(S'Range) := S; begin for X in S'Range loop if R(X) = ' ' then R(X) := '0'; end if; end loop; return R; end Blanks_To_Zero; procedure C_String(S : String_Ptr; CP : out Interfaces.C.Strings.char_array_access; Addr : out System.Address) is use Interfaces.C; begin if S /= null then CP := new char_array'(To_C(S.all)); Addr := CP.all'Address; else CP := null; Addr := System.Null_Address; end if; end C_String; procedure C_String(S : String; CP : out Interfaces.C.Strings.char_array_access; Addr : out System.Address) is use Interfaces.C; begin CP := new char_array'(To_C(S)); Addr := CP.all'Address; end C_String; function Strip_NL(S : String) return String is use Ada.Characters.Latin_1; NX : Natural := S'Last; begin for X in S'Range loop if S(X) = LF or S(X) = CR then return S(S'First..X-1); end if; end loop; return S; end Strip_NL; procedure Replace_String(SP : in out String_Ptr; S : String) is begin if SP /= null then Free(SP); end if; if S'Length > 1 then SP := new String(1..S'Length); SP.all := S; end if; end Replace_String; function Value_Of(C_String : Interfaces.C.Strings.chars_ptr) return String is use Interfaces.C.Strings, Interfaces.C; begin return To_Ada(Value(C_String)); end Value_Of; function Is_Null(C_String : Interfaces.C.Strings.chars_ptr) return Boolean is use Interfaces.C.Strings; begin return C_String = Null_Ptr; end Is_Null; -- function to_string( val : Unsigned_Integer ) return string is use ada.Strings.Fixed; begin return string'(trim(string'(Unsigned_Integer'Image(val)), ada.Strings.Both)); end to_string; function to_string( val : Unsigned_Integer ) return string_ptr is begin return new string'(to_string(val)); end to_string; -- function to_string( val : Unsigned_Integer_ptr ) return string is use ada.Strings.Fixed; begin if val /= null then return string'(trim(string'(Unsigned_Integer'Image(val.all)), ada.Strings.Both)); end if; return ""; end to_string; function to_string( val : Unsigned_Integer_ptr ) return string_ptr is use ada.Strings.Fixed; begin return new string'(to_string(val)); end to_string; -- -- function to_unsigned_integer( val : string ) return Unsigned_Integer is use Ada.Strings.Fixed; mi_hold : Unsigned_Integer := 0; begin declare val_hold : string := trim( val, ada.Strings.Both); begin mi_hold := Unsigned_Integer'(Unsigned_Integer'value(val_hold)); exception when others => mi_hold := 0; end; return mi_hold; end to_unsigned_integer; function to_unsigned_integer( val : string ) return Unsigned_Integer_Ptr is begin return new Unsigned_Integer'(to_unsigned_integer(val)); end to_unsigned_integer; function to_unsigned_integer( val : string_ptr ) return Unsigned_Integer is begin if val /= null then return Unsigned_Integer'(to_unsigned_integer(val.all)); end if; return 0; end to_unsigned_integer; function to_unsigned_integer( val : String_Ptr ) return Unsigned_Integer_Ptr is begin return new Unsigned_Integer'(to_unsigned_integer(val)); end to_unsigned_integer; function is_valid_unsigned( val : string ) return boolean is use Ada.Strings.Fixed; mi_hold : Unsigned_Integer := 0; mi_bool : boolean := false; begin declare val_hold : string := trim( val, ada.Strings.Both); begin if val_hold = "" then return false; end if; mi_hold := Unsigned_Integer'(Unsigned_Integer'value(val_hold)); mi_bool := true; exception when others => mi_bool := false; end; return mi_bool; end is_valid_unsigned; function is_valid_unsigned( val : String_Ptr ) return boolean is begin if val = null then return false; end if; return boolean'(is_valid_unsigned(val.all)); end is_valid_unsigned; end APQ; apq-3.2.0/src/apq.ads000066400000000000000000001400741171626402600143510ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- S p e c -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2011, KOW Framework Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------- -- This is the base package for APQ. -- -- That's everything that should be used when developping in a database -- -- vendor independent manner. -- -- It doesn't mean that by only using those methods your code will run at any-- -- backend. This only assures that your code will be able to be linked -- -- against other drivers, even in runtime (using plugins). -- ------------------------------------------------------------------------------- -- TODO: move all the database dependent code to the database driver! -- TIP for Time and Date values: -- make the Value() return String abstract in such way that, when it's -- a date value, it should be automatically translated to a standard way -- -- This way should be the ISO way so it's a lot easier to develop. -- -- An equivalent technique should be applied whenever needed. -- Other approach might be implemeting Value() for each primitive APQ supports. -- Then the generic methods would use those primitives whever needed. -- These generic methods would have to be changed in order to receive Class wide objetcs. with Ada.Calendar; with Ada.Calendar.Time_Zones; with Ada.Exceptions; use Ada.Exceptions; with Ada.Text_IO; with Ada.Finalization; with Ada.Unchecked_Deallocation; with Ada.Streams; with Ada.Characters.Latin_1; with Ada.Strings.Bounded; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Interfaces.C.Strings; with Interfaces.C_Streams; with System; package APQ is ---------------- -- EXCEPTIONS -- ---------------- SQL_Error : exception; -- SQL Error Occurred Use_Error : exception; -- USE Database error occurred Not_Connected : exception; -- Connect failed, or no connection Already_Connected : exception; -- A connection has already been established No_Result : exception; -- No result available No_Column : exception; -- Column does not exist (at index) No_Tuple : exception; -- No such tuple Null_Value : exception; -- Attempt to access a null value Invalid_Format : exception; -- Invalid format or bad data Small_Buffer : exception; -- Truncation into a small buffer Blob_Error : exception; -- Operation on blob failed Abort_State : exception; -- A ROLLBACK operation is required Tracing_State : exception; -- Already tracing to a file Failed : exception; -- General operation failed Not_Supported : exception; -- Feature or attribute is not supported type APQ_Error is ( APQ01, APQ02, APQ03, APQ04, APQ05, APQ06, APQ07, APQ08, APQ09, APQ10, APQ11, APQ12, APQ13, APQ14, APQ15, APQ16, APQ17, APQ18, APQ19, APQ20, APQ24, APQ25, APQ26, APQ27, APQ28); -- It's a type used to raise exceptions with messages -- Each APQ_Error is linked to an error message that can be retrieved from the -- constant array APQ_Error_Descriptions. subtype APQ_Error_Description is Unbounded_String; -- represents a description message for an APQ error. -- This message should follow the pattern: -- "some text %0% %1% some other text %2% ...." -- Where %i% will be substituted by the 1th element of an pattern array -- See To_UString_Array() and Raise_APQ_Exception. type APQ_Error_Description_Array is Array(APQ_Error range <>) of APQ_Error_Description; -- it's used to map the error codes to messages APQ_Error_Descriptions: constant APQ_Error_Description_Array := ( APQ01 => To_Unbounded_String("Unable to return UNIX socket port as Integer"), APQ02 => To_Unbounded_String("Unable to return TCP/IP port # as string"), APQ03 => To_Unbounded_String("String '%0%' is not a YYYY-MM-DD format date"), APQ04 => To_Unbounded_String("'%0%' is invalid APQ date format"), APQ05 => To_Unbounded_String("String '%0%' is an invalid time format"), APQ06 => To_Unbounded_String("String '%0%' is an invalid time format"), APQ07 => To_Unbounded_String("String '%0%' does not a boolean represent"), APQ08 => To_Unbounded_String("Converting Row_ID_Type value for column #%0%"), APQ09 => To_Unbounded_String("Buffer is too small to receive column #%0%"), APQ10 => To_Unbounded_String("Bad value for boolean in column #%0%"), APQ11 => To_Unbounded_String("Bad integer value for column #%0%"), APQ12 => To_Unbounded_String("Bad modular value for column #%0%"), APQ13 => To_Unbounded_String("Bad float value for column #%0%"), APQ14 => To_Unbounded_String("Bad fixed value for column #%0%"), APQ15 => To_Unbounded_String(""), -- empty error slot APQ16 => To_Unbounded_String("Bad decimal value for column #%0%"), APQ17 => To_Unbounded_String("Bad date value for column #%0%"), APQ18 => To_Unbounded_String("Bad date value (%0%) for column #%1%"), APQ19 => To_Unbounded_String("Bad time value (%0%) for column #%1%"), APQ20 => To_Unbounded_String("Bad timestamp format (%0%) for column #%1%"), APQ24 => To_Unbounded_String("Receiving string too small for column #%0%"), APQ25 => To_Unbounded_String("Receiving string too small for column #%0%"), APQ26 => To_Unbounded_String("Receiving bounded string too small for column #%0%"), APQ27 => To_Unbounded_String("Receiving bitstring too small for column #%0%"), APQ28 => To_Unbounded_String("Cursors are not supported for this database product in the client library") ); type Pattern_Array is Array(Natural range<>) of Unbounded_String; function To_Pattern_Array(Zero: in String) return Pattern_Array; -- return a Pattern array that maps from 0 to Zero. function To_Pattern_Array(Zero, One: in String) return Pattern_Array; -- same as the previous, but including both zero and one. function To_Pattern_Array(Zero, One, Two: in String) return Pattern_Array; -- same as the previous, but including both zero, one and two. procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero: in String := "" ); -- Raise the Exception E with a comprehensive error message procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero, One: in String ); -- Raise the Exception E with a comprehensive error message procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Zero, One, Two: in String ); -- Raise the Exception E with a comprehensive error message procedure Raise_APQ_Error_Exception( E: in Exception_Id; Code: in APQ_Error; Where: in String; Patterns: in Pattern_Array ); -- Raise the Exception E with a comprehensive error message -------------------- -- SQL DATA MODEL -- -------------------- -- scalar types type APQ_Smallint is range -32768..32767; type APQ_Integer is range -2 ** 31 .. 2 ** 31 - 1; type APQ_Bigint is range -2 ** 63 .. 2 ** 63 - 1; type APQ_Real is digits 6; type APQ_Double is digits 15; type APQ_Serial is range 1..2147483647; type APQ_Bigserial is range 1..9223372036854775807; -- time types subtype APQ_Date is Ada.Calendar.Time; -- Date (time ignored) subtype APQ_Time is Ada.Calendar.Day_Duration; -- Time only (date ignored) type APQ_Timestamp is new Ada.Calendar.Time; -- Date and time, stored in UTC type Hour_Number is range 0..23; type Minute_Number is range 0..59; type Second_Number is range 0..59; -- other types.. subtype APQ_Boolean is Boolean; -- Boolean type type APQ_Bitstring is array(Positive range <>) of APQ_Boolean; pragma pack(APQ_Bitstring); -------------- -- SQL MISC -- -------------- type SQL_Case_Type is ( Upper_Case, Lower_Case, Preserve_Case ); Line_Feed : constant String(1..1) := Ada.Characters.Latin_1.LF & ""; -- it's a String for a simple reason: -- it's appended by several functions to the end of a query. -- an this suffix can be changed by another (bigger) string. -- this makes things a lot easier type SQL_Code_Type is range -2 ** 31 .. 2 ** 31 - 1; ------------------------------------- -- SQL Fetch, Indexing and Tracing -- ------------------------------------- -- INDEX: type Row_ID_Type is mod 2 ** 64; -- Identifies a specific row type Tuple_Index_Type is mod 2 ** 64; -- Related concept to Row_ID_Type First_Tuple_Index : constant Tuple_Index_Type := 1; subtype Tuple_Count_Type is Tuple_Index_Type; type Column_Index_Type is new Positive; -- FETCH: type Fetch_Mode_Type is ( Sequential_Fetch, -- All databases : sequential fetch mode Random_Fetch, -- PostgreSQL, MySQL, not Sybase Cursor_For_Update, -- Sybase Cursor_For_Read_Only -- Sybase ); type Trace_Mode_Type is ( Trace_None, -- No tracing Trace_DB, -- Enable database library tracing Trace_APQ, -- APQ Trace Trace_Full -- Full trace information (Trace_DB and Trace_APQ) ); type Database_Type is ( Engine_PostgreSQL, -- PostgreSQL database engine is being used Engine_MySQL, -- MySQL database engine is being used Engine_Sybase, -- Sybase ASE 12.5x + Engine_CT_Lib, -- The native, low-level programming interface for -- the Sybase SQL Server database Engine_ODBC, -- ODBC engine (not ready) Engine_Other -- Other engine, not supported by the APQ team ); ---------------------------------------------------------------------------------- -- THE MAIN TYPEs -- ---------------------------------------------------------------------------------- -- Those types should be extended and have their abstract methods implemented -- -- by the new type. -- -- -- -- Those are the types responsible for interfacing with the database's native -- -- connector. -- ---------------------------------------------------------------------------------- type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with private; type Connection_Ptr is access all Root_Connection_Type'Class; type Root_Query_Type is abstract new Ada.Finalization.Controlled with private; type Query_Ptr is access all Root_Query_Type'Class; ---------------------------------------------------------------------------------- -- ABSTRACT METHOS FOR BOTH -- -- . Root_Connection_Type and -- -- . Root_Query_Type -- ---------------------------------------------------------------------------------- -- Those are the basic methos do be implemented by the driver implementor. -- -- Other methods shall be implemented as well, but these represent the basic set-- -- of funcionalities required by APQ. -- ---------------------------------------------------------------------------------- -------------------------- -- ROOT_CONNECTION_TYPE -- -------------------------- function Engine_Of(C : Root_Connection_Type) return Database_Type is abstract; -- Return a identifier for the connection used. procedure Connect(C : in out Root_Connection_Type; Check_Connection : Boolean := True) is abstract; -- Connect to the Database C. -- if Check_Connection = False, then assume it's not connected. -- Usefull when Is_Connected has been called before. procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is abstract; -- Clone the connection Same_As to C procedure Disconnect(C : in out Root_Connection_Type) is abstract; -- Close the database connection function Is_Connected(C : Root_Connection_Type) return Boolean is abstract; -- Checks if the connection is active procedure Reset(C : in out Root_Connection_Type) is abstract; -- Reset the Connection object, not the connection itself. -- It makes possible the reuse of the Root_Connection_Type object in another -- connection. -- It does not disconnect and then reconnect! function Error_Message(C : Root_Connection_Type) return String is abstract; -- Return an error message describing why the connection might have failed. -- To be used when the No_Connection exception is raised by the Connect predicate procedure Open_DB_Trace(C : in out Root_Connection_Type; Filename : String; Mode : Trace_Mode_Type := Trace_APQ) is abstract; -- Initialize the tracing --------------------- -- ROOT_QUERY_TYPE -- --------------------- function Engine_Of(Q : Root_Query_Type) return Database_Type is abstract; -- Return an identifier for the database type used. procedure Execute(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract; -- Execute the query using the specified connection procedure Execute_Checked(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class; Msg : String := "") is abstract; -- Execute the query using the specified connection, reporting -- any error that might occur to the Standard_Error output. -- -- The exception is then re-raised to leave control in the caller's hands. -- -- If the Msg string is specified, a line is printed before -- the error message following the pattern: -- **** SQL ERROR: [Msg] -- Transation Operations -- -- -- Use these procedures in favour of using the custom SQL syntax for better portability: procedure Begin_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract; procedure Commit_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract; procedure Rollback_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract; procedure Rewind(Q : in out Root_Query_Type) is abstract; -- Rewind to the first result when Random_Fetch mode is used. -- Raises SQL_Error when not in the right mode. procedure Fetch(Q : in out Root_Query_Type) is abstract; -- Fetch the next result of the query when in Random_Fetch or Sequential_Fetch mode procedure Fetch(Q : in out Root_Query_Type; TX : Tuple_Index_Type) is abstract; -- Fetch the TXth result when in the Random_Fetch mode. function End_of_Query(Q : Root_Query_Type) return Boolean is abstract; -- !!!!DEPRECATED!!!! -- Catch the No_Tuple exception instead! -- This won't work as expected with MySQL due to a bug in the client library used -- -- Checks if there are more results to be fetched. function Tuple(Q : Root_Query_Type) return Tuple_Index_Type is abstract; -- return the last tuple fetched function Tuples(Q : Root_Query_Type) return Tuple_Count_Type is abstract; -- count the tuples returned by the query function Columns(Q : Root_Query_Type) return Natural is abstract; -- count the columns returned by the query function Value(Query : Root_Query_Type; CX : Column_Index_Type) return String is abstract; -- get a value as an String. function Column_Name(Query : Root_Query_Type; Index : Column_Index_Type) return String is abstract; -- get the Index'th column name. function Column_Index(Query : Root_Query_Type; Name : String) return Column_Index_Type is abstract; -- get the index for the column "Name" function Result(Query : Root_Query_Type) return Natural is abstract; -- get the result code for the query -- the meaning of the returned code varies from database product to another. function Is_Null(Q : Root_Query_Type; CX : Column_Index_Type) return Boolean is abstract; -- checks if the result in the CXth column is null. function Command_Oid(Query : Root_Query_Type) return Row_ID_Type is abstract; -- After running an INSERT statement, return the Row_ID for the inserted column. -- Can raise: -- No_Result => there is no result status (no execution) -- SQL_Error => An SQL error occurred obtaining the OID -- -- Each database product has it's own requirements for this function to work. -- For more information reffer to the driver's documentation. function Null_Oid(Query : Root_Query_Type) return Row_ID_Type is abstract; -- Used to avoid hardcoded numbers. -- Return the ID that represents a NULL OID. function Error_Message(Query : Root_Query_Type) return String is abstract; -- Return an error message when the query has failed. function Is_Duplicate_Key(Query : Root_Query_Type) return Boolean is abstract; -- When an INSERT statement runs it might have a duplicated key. -- When it does, SQL_Error is raised and then the developer might use -- Is_Duplicate_Key to check if the error was due the row being duplicated. function SQL_Code(Query : Root_Query_Type) return SQL_Code_Type is abstract; -- Return a Code, that varies from database product to another, representing -- the result status. -- Currently, this feature is only avaliable to the Sybase binding. function Query_Factory( C: in Root_Connection_Type ) return Root_Query_Type'Class is abstract; -- create a query object for the selected connection type. -- this is used internally by the New_Query function. -- NOTE: DO NOT USE THIS FUNCTION AS IT'S MEANT TO BE USED INTERNALLY ONLY! -- NOTE: USE New_Query INSTEAD procedure Finalize(Q : in out Root_Query_Type) is abstract; -- finalization routines should be extended by database vendo support implementor ---------------------------------------------------------------------------------- -- IMPLEMENTED METHODS FOR BOTH -- -- . Root_Connection_Type and -- -- . Root_Query_Type -- ---------------------------------------------------------------------------------- -- These methods are provided by the APQ base package but the driver implementor-- -- might provide their own implementations. -- -- Those methods, in their original implementation, make use of the abstract -- -- methods defined in the previous code session. -- ---------------------------------------------------------------------------------- function New_Query(C : Root_Connection_Type'Class) return Root_Query_Type'Class; -- Use this function to create a new query object for your connection. -------------------------- -- ROOT_CONNECTION_TYPE -- -------------------------- function Get_Case(C : Root_Connection_Type) return SQL_Case_Type; -- Get the SQL case used by default in this connection. -- All new queries will use this casing by default. procedure Set_Case(C : in out Root_Connection_Type; SQL_Case : SQL_Case_Type); -- Set the SQL case used by default in this connection. -- All new queries will use this casing by default. pragma Inline(Get_Case,Set_Case); function Get_Instance(C: Root_Connection_Type) return String; -- Get the instance Name for the Database. function Instance(C : Root_Connection_type) return String renames Get_Instance; -- Get the instance Name for the Database. It's an alias for Get_Instance procedure Set_Instance(C : in out Root_Connection_Type; Instance : String); -- Set the instance Name for the Database. function Get_Host_Name(C: Root_Connection_Type) return String; -- Get the host name for the Database server. function Host_Name(C : Root_Connection_Type) return String renames Get_Host_Name; -- Get the host name for the Database server. It's an alias for Get_Host_Name procedure Set_Host_Name(C : in out Root_Connection_Type; Host_Name : String); -- Set the host name for the Database server. function Get_Host_Address(C: in Root_Connection_Type) return String; -- Set the host address for the database server. function Host_Address(C: in Root_Connection_Type) return String renames Get_Host_Address; -- Set the host address for the database server. It's an alias for Get_Host_Address procedure Set_Host_Address(C : in out Root_Connection_Type; Host_Address : String); -- Set the host address for the database server. function Get_Port( C: in Root_Connection_Type ) return Integer; -- Get the TCP port number. function Port(C : Root_Connection_Type) return Integer renames Get_Port; -- Get the TCP port number. It's an alias for Get_Port. procedure Set_Port(C : in out Root_Connection_Type; Port_Number : Integer); -- Set the TCP port number. function Get_Port( C: in Root_Connection_Type) return String; -- Get the Unix Port. function Port(C : Root_Connection_Type) return String renames Get_Port; -- Get the Unix Port. It's an alias for Get_Port. procedure Set_Port(C : in out Root_Connection_Type; Port_Name : String); -- Set the Unix Port function Get_DB_Name(C : Root_Connection_Type) return String; -- Get the Database name used in this connection. function DB_Name(C : Root_Connection_Type) return String renames Get_DB_Name; -- Get the Database name used in this connection. It's an alias for Get_DB_Name. procedure Set_DB_Name(C : in out Root_Connection_Type; DB_Name : String); -- Set the Database name used in this connection. function Get_User( C: in Root_Connection_Type ) return String; -- Get the Username for this connection. function User( C: in Root_Connection_Type ) return String renames Get_User; -- Get the Username for this connection. It's ana alias for Get_User procedure Set_User( C: in out Root_Connection_Type; User: in String ); -- Set the Username for this connection. function Get_Password( C: Root_Connection_Type ) return String; -- Get the Password for this connection. function Password(C : Root_Connection_Type) return String renames Get_Password; -- Get the Password for this connection. It's an alias for Get_Password procedure Set_Password( C: in out Root_Connection_Type; Password: in String ); -- Get the Password for this connection. procedure Set_User_Password(C : in out Root_Connection_Type; User_Name, User_Password : String); -- Set both the username and the password for this connection. function In_Abort_State(C : Root_Connection_Type) return Boolean; -- Some database products (eg, PostgreSQL) can enter in a status where -- every operation is ignored. -- There is the Abort_State Exception for this, but there is also -- this function that checks if the connection is in this state. function Get_Rollback_On_Finalize( C: in Root_Connection_Type ) return Boolean; -- Get if the work will be rollbacked when finalizing. function Will_Rollback_On_Finalize(C : Root_Connection_Type) return Boolean renames Get_Rollback_On_Finalize; -- Get if the work will be rollbacked when finalizing. -- It's an alias for Get_Rollback_on_Finalize. procedure Set_Rollback_On_Finalize(C : in out Root_Connection_Type; Rollback : Boolean); -- Set if the work will be rollbacked when finalizing procedure Set_Auto_Reconnect( C : in out Root_Connection_Type; Auto_Reconnect : in Boolean := True ); -- set if it should reconnect automatically when the connection is droped. function Get_Auto_Reconnect( C : in Root_Connection_Type ) return Boolean; -- return true if the connection should be automatically restablished when droped --------------------- -- ROOT_QUERY_TYPE -- --------------------- -- Query setup ... function Get_Case(Q : Root_Query_Type) return SQL_Case_Type; -- Get the case used by this query -- This case might be different from the one used by default procedure Set_Case(Q : in out Root_Query_Type; SQL_Case : SQL_Case_Type); -- Set the case used by this query. function Get_Fetch_Mode( Q: in Root_Query_Type ) return Fetch_Mode_Type; -- Get the fetch mode used by this query. function Fetch_Mode(Q : Root_Query_Type) return Fetch_Mode_Type renames Get_Fetch_Mode; -- Get the fetch mode used by this query. It's an alias for Get_Fetch_Mode procedure Set_Fetch_Mode(Q : in out Root_Query_Type; Mode : Fetch_Mode_Type); -- Set the fetch mode used by this query. procedure Raise_Exceptions(Query : in out Root_Query_Type; Raise_On : Boolean := True); -- when Execute_Checked is called, should raise the exception back to the caller? pragma No_Return (Raise_APQ_Error_Exception); procedure Report_Errors(Query : in out Root_Query_Type; Report_On : Boolean := True); -- report sql erros when Execute_Checked is called? -- Query information ... function To_String(Query : Root_Query_Type) return String; -- get the query text function Is_Select(Q : Root_Query_Type) return Boolean; -- is this query a select statement? function Cursor_Name(Query : Root_Query_Type) return String; -- get the cursor name for the current result -- this function is meant to be overwriten by the driver if it supports cursor -- SQL creation ... procedure Clear(Q : in out Root_Query_Type); -- Clear the query so one can start a new SQL expression. procedure Grow(Q : in out Root_Query_Type); -- used internally to grow the query lines size so one can Append to it. procedure Prepare(Q : in out Root_Query_Type; SQL : String; After : String := Line_Feed); -- Clear the query, starting a new one. procedure Append(Q : in out Root_Query_Type; SQL : String; After : String := ""); -- Append a string to the query procedure Append(Q : in out Root_Query_Type; SQL : Ada.Strings.Unbounded.Unbounded_String; After : String := ""); -- Append an Unbounded_String to the query procedure Append_Line(Q : in out Root_Query_Type; SQL : String := ""); -- Append a String followed by a new line. -- If the parameter SQL is omited, there is inserted only a line break procedure Append(Q : in out Root_Query_Type; V : APQ_Boolean; After : String := ""); -- Append a boolean to the query procedure Append(Q : in out Root_Query_Type; V : APQ_Date; After : String := ""); -- Append a date to the query procedure Append(Q : in out Root_Query_Type; V : APQ_Time; After : String := ""); -- Append a time... procedure Append(Q : in out Root_Query_Type; V : APQ_Timestamp; After : String := ""); -- Append a timestamp... procedure Append(Q : in out Root_Query_Type; V : APQ_Bitstring; After : String := ""); -- Append a bitstring... procedure Append(Q : in out Root_Query_Type; V : Row_ID_Type; After : String := ""); -- Append a row_id_type... procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : String; After : String := ""); -- Append a quoted String. -- The case of this String isn't changed. -- This primitive should normally be overriden for a specific database. -- PostgreSQL and MySQL will potentially have different quoting requirements. procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; After : String := ""); -- Append a quoted Unbouned_String. -- The case of this String isn't changed. -- This primitive should normally be overriden for a specific database. -- PostgreSQL and MySQL will potentially have different quoting requirements. -- Data retrieval: --Note: there is an abstract function value() which returns string; -- This function is used in all these following methods: procedure Value(Query: Root_Query_Type; CX : Column_Index_Type; V : out String); -- Get the value of the CXth column as String. -- Fixed length String Fetch function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Ada.Strings.Unbounded.Unbounded_String; -- Get the value of the CXth column as Unbounded_String. function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Row_ID_Type; -- Get the value of the CXth column as Row_Id_Type. function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Bitstring; -- Get the value of the CXth column as Bitstring. -- METHODS THAT SHOULD BE OVERRIDDEN BY THE DATABASE DRIVER -- --TODO: change the types to APQ_Something. function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Boolean; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Integer; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Float; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Date; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Time; function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Timestamp; ---------------------------------------------------------------------------------- -- GENERIC METHODS FOR -- -- . Root_Query_Type -- ---------------------------------------------------------------------------------- -- These methods are implemented using the abstract and implemented methods -- -- that are listed before this block. -- -- -- -- They are meant to enforce strong typing with Database programming. -- ---------------------------------------------------------------------------------- -- SQL creation :: append ... generic type Val_Type is new Boolean; procedure Append_Boolean(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is range <>; procedure Append_Integer(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is mod <>; procedure Append_Modular(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is digits <>; procedure Append_Float(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is delta <>; procedure Append_Fixed(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is delta <> digits <>; procedure Append_Decimal(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is new Ada.Calendar.Time; procedure Append_Date(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is new Ada.Calendar.Day_Duration; procedure Append_Time(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is new Ada.Calendar.Time; procedure Append_Timestamp(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic type Val_Type is new APQ_Bitstring; procedure Append_Bitstring(Q : in out Root_Query_Type'Class; V : Val_Type; After : String := ""); generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Append_Bounded(Q : in out Root_Query_Type'Class; SQL : P.Bounded_String; After : String := ""); generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Append_Bounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : P.Bounded_String; After : String := ""); -- SQL creation :: encode... -- encode is the same as append, but supporting null values. generic type Val_Type is new Boolean; type Ind_Type is new Boolean; procedure Encode_Boolean(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is range <>; type Ind_Type is new Boolean; procedure Encode_Integer(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is mod <>; type Ind_Type is new Boolean; procedure Encode_Modular(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is digits <>; type Ind_Type is new Boolean; procedure Encode_Float(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is delta <>; type Ind_Type is new Boolean; procedure Encode_Fixed(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is delta <> digits <>; type Ind_Type is new Boolean; procedure Encode_Decimal(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is new APQ_Date; type Ind_Type is new Boolean; procedure Encode_Date(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is new APQ_Time; type Ind_Type is new Boolean; procedure Encode_Time(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is new APQ_Timestamp; type Ind_Type is new Boolean; procedure Encode_Timestamp(Q : in out Root_Query_Type'Class; V : Val_Type; Indicator : Ind_Type; After : String := ""); generic type Val_Type is new APQ_Bitstring; type Ind_Type is new Boolean; procedure Encode_Bitstring(Q : in out Root_Query_Type'Class; V: Val_Type; Indicator : Ind_Type; After : String := ""); generic type Ind_Type is new Boolean; procedure Encode_String_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : String; Indicator : Ind_Type; After : String := ""); generic type Ind_Type is new Boolean; with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Encode_Bounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : P.Bounded_String; Indicator : Ind_Type; After : String := ""); generic type Ind_Type is new Boolean; procedure Encode_Unbounded(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; Indicator : Ind_Type; After : String := ""); generic type Ind_Type is new Boolean; procedure Encode_Unbounded_Quoted(Q : in out Root_Query_Type'Class; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; Indicator : Ind_Type; After : String := ""); -- Data retrieval :: misc ... generic type Ind_Type is new Boolean; function Column_Is_Null(Q : Root_Query_Type'Class; CX : Column_Index_Type) return Ind_Type; -- checks if the result in the CXth column is null. -- Data retrieval :: value operations ... -- TODO: Remove all these operations and implement value operations instead returning the correct type. generic type Val_Type is new Boolean; function Boolean_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is range <>; function Integer_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is mod <>; function Modular_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is digits <>; function Float_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is delta <>; function Fixed_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is delta <> digits <>; function Decimal_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is new APQ_Date; function Date_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is new APQ_Time; function Time_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic type Val_Type is new Ada.Calendar.Time; function Timestamp_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return Val_Type; generic with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); function Bounded_Value(Query : Root_Query_Type'Class; CX : Column_Index_Type) return P.Bounded_String; -- Data retrieval :: fetch operations ... -- They are the same as the value operations, but with null support generic type Val_Type is new Boolean; type Ind_Type is new Boolean; procedure Boolean_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is range <>; type Ind_Type is new Boolean; procedure Integer_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is mod <>; type Ind_Type is new Boolean; procedure Modular_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is digits <>; type Ind_Type is new Boolean; procedure Float_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is delta <>; type Ind_Type is new Boolean; procedure Fixed_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is delta <> digits <>; type Ind_Type is new Boolean; procedure Decimal_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is new Ada.Calendar.Time; type Ind_Type is new Boolean; procedure Date_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is new Ada.Calendar.Day_Duration; type Ind_Type is new Boolean; procedure Time_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Val_Type is new Ada.Calendar.Time; type Ind_Type is new Boolean; procedure Timestamp_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type); generic type Ind_Type is new Boolean; procedure Bitstring_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out APQ_Bitstring; Last : out Natural; Indicator : out Ind_Type); generic type Ind is new Boolean; with package P is new Ada.Strings.Bounded.Generic_Bounded_Length(<>); procedure Bounded_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out P.Bounded_String; Indicator : out Ind); generic type Ind_Type is new Boolean; procedure Unbounded_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Ada.Strings.Unbounded.Unbounded_String; Indicator : out Ind_Type); generic type Ind_Type is new Boolean; procedure Char_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out String; Indicator : out Ind_Type); generic type Ind_Type is new Boolean; procedure Varchar_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out String; Last : out Natural; Indicator : out Ind_Type); -- Conversion :: anything to string (APQ primitives) ... function To_String(V : APQ_Boolean) return String; function To_String(V : APQ_Date) return String; function To_String(V : APQ_Time) return String; function To_String(V : APQ_Timestamp) return String; function To_String(V : APQ_Bitstring) return String; -- Conversion :: anything to string (generic for derived types) ... generic type Val_Type is range <>; function Integer_String(V : Val_Type) return String; generic type Val_Type is mod <>; function Modular_String(V : Val_Type) return String; generic type Val_Type is digits <>; function Float_String(V : Val_Type) return String; generic type Val_Type is delta <>; function Fixed_String(V : Val_Type) return String; generic type Val_Type is delta <> digits <>; function Decimal_String(V : Val_Type) return String; generic type Val_Type is new Ada.Calendar.Time; function Date_String(V : Val_Type) return String; generic type Val_Type is new Ada.Calendar.Day_Duration; function Time_String(V : Val_Type) return String; generic type Val_Type is new Ada.Calendar.Time; function Timestamp_String(V : Val_Type) return String; -- Conversion :: anything from string ... --TODO: These functions may not need to be generic anymore. If so, make --them return the APQ_types. generic type Val_Type is new Boolean; function Convert_To_Boolean(S : String) return Val_Type; generic type Val_Type is new Duration; function Convert_To_Time(S : String) return Val_Type; generic type Val_Type is new Ada.Calendar.Time; function Convert_to_Timestamp( S : in String; TZ : in Ada.Calendar.Time_Zones.Time_Offset ) return Val_Type; generic type Date_Type is new Ada.Calendar.Time; type Time_Type is new Ada.Calendar.Day_Duration; type Result_Type is new Ada.Calendar.Time; function Convert_Date_and_Time( DT : in Date_Type; TM : in Time_Type ) return Result_Type; -- return a new timestamp in DT's timezone at TM duration -- Misc ... generic type Oid_Type is new Row_ID_Type; function Generic_Command_Oid(Query : Root_Query_Type'Class) return Oid_Type; -- The Generic_Command_Oid causes GNAT 3.14p to fall over and die. -- -- It isn't really required, since Command_Oid(Query) can be used instead, -- and the return value converted to whatever Oid_Type is. --------------------------------- -- EXTENDED CALENDAR FUNCTIONS -- --------------------------------- generic type Date_Type is new Ada.Calendar.Time; type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Time_of_Day(V : Date_Type) return Time_Type; generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Hour(TM : Time_Type) return Hour_Number; generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Minute(TM : Time_Type) return Minute_Number; generic type Time_Type is new Ada.Calendar.Day_Duration; function Generic_Second(TM : Time_Type) return Second_Number; ------------------- --- misc types ---- ------------------- type Unsigned_Integer is new interfaces.c.unsigned; type Unsigned_Integer_Ptr is access all unsigned_integer; private package CStr renames Interfaces.C_Streams; type String_Ptr is access all String; type String_Ptr_Array is array(Natural range <>) of String_Ptr; type String_Ptr_Array_Access is access all String_Ptr_Array; type Stream_Element_Array_Ptr is access all Ada.Streams.Stream_Element_Array; type Boolean_Array is array(Natural range <>) of Boolean; type Boolean_Array_Access is access all Boolean_Array; subtype Port_Integer is Integer range 0..32768; type Port_Format_Type is ( IP_Port, UNIX_Port ); type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with record Instance : String_Ptr; -- Engine instance name Host_Name : String_Ptr; -- Host name string or.. Host_Address : String_Ptr; -- Host IP address Port_Format : Port_Format_Type := UNIX_Port; -- I/O type Port_Number : Port_Integer := 0; -- Port number of the database server Port_Name : String_Ptr; -- UNIX pathname for UNIX socket DB_Name : String_Ptr; -- Database name User_Name : String_Ptr; -- The user name User_Password : String_Ptr; -- User password (if required) Abort_State : Boolean := False; -- Transaction abort state Rollback_Finalize : Boolean := True; -- Rollback transaction on Finalization Trace_Filename : String_Ptr; -- Filename for tracing Trace_On : Boolean := False; -- True if tracing is enabled Trace_Mode : Trace_Mode_Type := Trace_None; -- Current Trace mode Trace_File : CStr.FILEs := CStr.Null_Stream; -- C Stream (FILE *) Trace_Ada : Ada.Text_IO.File_Type; -- Ada version of Trace_File SQL_Case : SQL_Case_Type := Upper_Case; -- How to map SQL "case" Auto_Reconnect : Boolean := False; -- TODO: reconnect when the connection drops end record; type Root_Query_Type is abstract new Ada.Finalization.Controlled with record Count : Natural := 0; -- # of elements in the Collection Alloc : Natural := 0; -- # of allocated elements in the Collection Collection : String_Ptr_Array_Access; -- Array of strings Caseless : Boolean_Array_Access; -- True where case is to be preserved Raise_Exceptions: Boolean := True; -- Raise exception in Execute_Checked() Report_Errors : Boolean := True; -- Report SQL error in Execute_Checked() Mode : Fetch_Mode_Type := Random_Fetch; -- Random Fetches Rewound : Boolean := True; -- At first tuple Tuple_Index : Tuple_Index_Type := Tuple_Index_Type'First; -- Current tuple index SQL_Case : SQL_Case_Type := Upper_Case; -- How to map SQL "case" end record; function To_Case(S : String; C : SQL_Case_Type) return String; -- convert the string to the selected case procedure Clear_Abort_State(C : in out Root_Connection_Type); procedure Adjust(Q : in out Root_Query_Type); function Is_Insert(Q : Root_Query_Type) return Boolean; -- True if query is an INSERT statement function Is_Update(Q : Root_Query_Type) return Boolean; -- True if query is an UPDATE statement procedure Free is new Ada.Unchecked_Deallocation(String,String_Ptr); procedure Free is new Ada.Unchecked_Deallocation( Interfaces.C.char_array,Interfaces.C.Strings.char_array_access); procedure Free is new Ada.Unchecked_Deallocation(String_Ptr_Array,String_Ptr_Array_Access); procedure Free is new Ada.Unchecked_Deallocation(Boolean_Array,Boolean_Array_Access); procedure Free is new Ada.Unchecked_Deallocation( Ada.Streams.Stream_Element_Array,Stream_Element_Array_Ptr); procedure Free_Ptr(SP : in out String_Ptr); function To_String(S : String_Ptr) return String; function To_Ada_String(P : Interfaces.C.Strings.chars_ptr) return String; function Blanks_To_Zero(S : String) return String; procedure C_String(S : String_Ptr; CP : out Interfaces.C.Strings.char_array_access; Addr : out System.Address); procedure C_String(S : String; CP : out Interfaces.C.Strings.char_array_access; Addr : out System.Address); function Strip_NL(S : String) return String; procedure Replace_String(SP : in out String_Ptr; S : String); function Value_Of(C_String : Interfaces.C.Strings.chars_ptr) return String; function Is_Null(C_String : Interfaces.C.Strings.chars_ptr) return Boolean; function to_string( val : Unsigned_Integer ) return string; function to_string( val : Unsigned_Integer ) return string_ptr; function to_string( val : Unsigned_Integer_ptr ) return string; function to_string( val : Unsigned_Integer_ptr ) return string_ptr; function to_unsigned_integer( val : string ) return Unsigned_Integer; function to_unsigned_integer( val : string ) return Unsigned_Integer_Ptr; function to_unsigned_integer( val : string_ptr ) return Unsigned_Integer; function to_unsigned_integer( val : String_Ptr ) return Unsigned_Integer_Ptr; function is_valid_unsigned( val : string ) return boolean; function is_valid_unsigned( val : String_Ptr ) return boolean; procedure free is new Ada.Unchecked_Deallocation( Unsigned_Integer , Unsigned_Integer_Ptr ); pragma Inline( to_string , to_unsigned_integer ); end APQ; apq-3.2.0/src/apq_helper.adb000066400000000000000000000166451171626402600156750ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- S p e c -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2011, KOW Framework Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- This is the APQ_Helper package -- -- -- -- Library to perform actions over Strings -- ------------------------------------------------------------------------------ with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_IO; with Ada.Characters.Handling; use Ada.Characters.Handling; -- Used for string replacement -- with GNAT.Spitbol.Patterns; package body APQ_Helper is procedure Str_Replace( From, To: in Character; Str: in out String ) is -- replace all the ocurences of the character From by To. begin for i in Str'Range loop if Str(i) = From then Str(i) := To; end if; end loop; end Str_Replace; function Str_Replace( From, To: in Character; Str: in String ) return String is -- replace all the ocurences of the character From by To returning the new Value. R: String := Str; begin Str_Replace( From, To, R ); return R; end Str_Replace; procedure Str_Replace( From, To, Str: in Unbounded_String; Result: in out Unbounded_String; Case_Sensitive: Boolean := True ) is begin Result := Str_Replace( From, To, Str, Case_Sensitive ); end Str_Replace; function Str_Replace( From, To, Str: in Unbounded_String; Case_Sensitive: Boolean := True ) return Unbounded_String is begin return Str_Replace( To_String( From ), To_String( To ), To_String( Str ), Case_Sensitive ); end Str_Replace; procedure Str_Replace( From, To, Str: in String; Result: in out Unbounded_String; Case_Sensitive: Boolean := True ) is begin Result := Str_Replace( From, To, Str, Case_Sensitive ); end Str_Replace; function Str_Replace( From, To: in String; Str: in String; Case_Sensitive: Boolean := True ) return Unbounded_String is Occurances : Positions_Array := Find_Occurances( From, Str, Case_Sensitive ); Size_Dif : Integer := To'Length - From'Length; Result : Unbounded_String; Index_str : Positive := Str'First; Index_Occu : Integer := Occurances'First; -- Element_Occu : Integer; Actual : Natural; subtype i is Integer range To'Range; begin if Occurances'Length = 0 then return To_Unbounded_String( Str ); end if; while Index_str <= Str'Last loop if Index_Occu /= Occurances'Last + 1 then Actual :=Occurances( Index_Occu ); else Actual := 0; end if; if Index_str = Actual then -- replace for i in To'Range loop Append( Result, To( i ) ); end loop; Index_Str := Index_Str + From'Length; Index_Occu := Index_Occu + 1; -- Index_Occu := Occurances.Next; else Append( Result, Str( Index_Str ) ); Index_Str := Index_Str + 1; end if; end loop; return Result; end Str_Replace; function Find_Occurances( Find, Context : in String; Case_Sensitive: Boolean ) return Positions_Array is type List is array ( Natural range <> ) of Integer; function Pre_Compute( Str : in String; Case_Sensitive: Boolean ) return List is Pragma Inline ( Pre_Compute ); -- computes the failure_function table of the KMP algorithm pos : Integer; T : List( 0 .. Str'Length ) := ( 0 .. Str'Length => -1 ); Str2 : String := Str; use Ada.Text_IO; begin if Case_Sensitive then Str2 := To_Lower( Str ); end if; for i in 1 .. Str'Length loop pos := T( i - 1 ); while pos /= -1 and then Str( pos + 1 ) /= Str( i ) loop pos := T( pos ); end loop; T( i ) := pos + 1; end loop; return T; end; -- declarations Matches : Positions_Array( Context'Range ); Matches_Idx : Integer := Matches'First; Context_Idx : Positive := 1; Table : List := Pre_Compute( Find, Case_Sensitive ); Find_Idx : Integer := 0; Find2 : String := Find; Context2 : String := Context; use Ada.Text_IO; begin -- Knuth-Morris-Pratt algorithm if Case_Sensitive then Find2 := To_Lower( Find ); Context2 := To_Lower( Context ); end if; while Context_Idx <= Context2'Length loop while Find_Idx /= -1 and then ( Find_Idx = Find2'Length or else Find2( Find_Idx + 1 ) /= Context2( Context_Idx ) ) loop Find_Idx := Table( Find_Idx ); end loop; Find_Idx := Find_Idx + 1; Context_Idx := Context_Idx + 1; if Find_Idx = Find2'Length then Matches( Matches_Idx ) := Context_idx - Find2'Length; Matches_Idx := Matches_Idx + 1; end if; end loop; return Matches( Matches'First .. Matches_Idx - 1 ); end Find_Occurances; -- for compatibility with older version procedure Str_Replace( From, To: in Unbounded_String; Str: in out Unbounded_String ) is begin Str := Str_Replace( To_String( From ), To_String( To ), To_String( Str ) ); end Str_Replace; procedure Str_Replace( From, To: in String; Str: in out Unbounded_String ) is begin Str := Str_Replace( From, To, To_String( Str ) ); end Str_Replace; function Str_Replace( From, To: in String; Str: in Unbounded_String ) return Unbounded_String is begin return Str_Replace( From, To, To_String( Str ) ); end Str_Replace; end APQ_Helper; apq-3.2.0/src/apq_helper.ads000066400000000000000000000110251171626402600157010ustar00rootroot00000000000000------------------------------------------------------------------------------ -- -- -- APQ DATABASE BINDINGS -- -- -- -- A P Q -- -- -- -- S p e c -- -- -- -- Copyright (C) 2002-2007, Warren W. Gay VE3WWG -- -- Copyright (C) 2007-2011, KOW Framework Project -- -- -- -- -- -- APQ is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- -- ware Foundation; either version 2, or (at your option) any later ver- -- -- sion. APQ is distributed in the hope that it will be useful, but WITH- -- -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- -- for more details. You should have received a copy of the GNU General -- -- Public License distributed with APQ; see file COPYING. If not, write -- -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- -- MA 02111-1307, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- This is a simpler version of the Aw_Lib.String_Util package -- -- It's here to remove dependency of APQ over Aw_Lib -- -- -- -- Library to perform actions over Strings -- ------------------------------------------------------------------------------ with Ada.Strings; use Ada.Strings; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package APQ_Helper is type UString_Array is Array( Integer range <> ) of Unbounded_String; type Positions_Array is Array( Integer range <> ) of Integer; procedure Str_Replace( From, To: in Character; Str: in out String ); -- replace all the ocurences of the character From by To. function Str_Replace( From, To: in Character; Str: in String ) return String; -- replace all the ocurences of the character From by To returning the new Value. function Str_Replace( From, To, Str: in String; Case_Sensitive: Boolean := True ) return Unbounded_String; procedure Str_Replace( From, To, Str: in String; Result: in out Unbounded_String; Case_Sensitive: Boolean := True ); function Str_Replace( From, To, Str: in Unbounded_String; Case_Sensitive: Boolean := True ) return Unbounded_String; procedure Str_Replace( From, To, Str: in Unbounded_String; Result: in out Unbounded_String; Case_Sensitive: Boolean := True ); -- for compatibility procedure Str_Replace( From, To : in Unbounded_String; Str : in out Unbounded_String ); --function Str_Replace( From, To: in Unbounded_String; -- Str: in Unbounded_String ) return Unbounded_String; procedure Str_Replace( From, To: in String; Str: in out Unbounded_String ); function Str_Replace( From, To: in String; Str: in Unbounded_String ) return Unbounded_String; private function Find_Occurances( Find, Context : in String; Case_Sensitive: Boolean ) return Positions_Array; -- uses the Knuth-Morris_Pratt string searching algorithm to -- find all occurances of Find in Context and returns an vector -- with the starting positions of each occurance end APQ_Helper; apq-3.2.0/version000066400000000000000000000000061171626402600137060ustar00rootroot000000000000003.2.0