pax_global_header00006660000000000000000000000064151506363760014526gustar00rootroot0000000000000052 comment=25008ce251905cf0ee9664217dfe57f8664580a7 zgimbutas-mwrap-25008ce/000077500000000000000000000000001515063637600152075ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/.github/000077500000000000000000000000001515063637600165475ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/.github/workflows/000077500000000000000000000000001515063637600206045ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/.github/workflows/ci.yml000066400000000000000000000073601515063637600217300ustar00rootroot00000000000000name: Continuous Integration on: push: branches: [ master ] pull_request: branches: [ master ] jobs: makefile-build: name: Makefile build and test runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ bison \ flex \ zlib1g-dev \ octave \ octave-dev - name: Build run: make bin - name: Run tests run: make test cmake-build: name: CMake build and test runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ cmake \ bison \ flex \ zlib1g-dev - name: Configure CMake run: cmake -S . -B build -DBUILD_TESTING=ON - name: Build run: cmake --build build --target mwrap - name: Run tests run: cmake --build build --target mwrap_tests matlab-examples: name: Build and test MATLAB examples runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ cmake \ bison \ flex \ zlib1g-dev - name: Set up MATLAB uses: matlab-actions/setup-matlab@v2 - name: Configure with CMake run: | cmake -S . -B build-matlab \ -DMWRAP_BUILD_EXAMPLES=ON \ -DMWRAP_COMPILE_MEX=ON \ -DBUILD_TESTING=ON - name: Build examples and tests run: | cmake --build build-matlab --target mwrap_examples cmake --build build-matlab --target mwrap_testing_mex - name: Run MATLAB tests uses: matlab-actions/run-command@v2 with: command: addpath('testing'); run_matlab_tests('build-matlab', '.') octave-examples: name: Build and test Octave examples runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ cmake \ bison \ flex \ zlib1g-dev \ octave \ octave-dev - name: Configure examples with CMake run: | cmake -S . -B build-octave \ -DMWRAP_BUILD_EXAMPLES=ON \ -DMWRAP_COMPILE_MEX=ON \ -DMWRAP_MEX_BACKEND=OCTAVE \ -DBUILD_TESTING=ON - name: Build Octave examples run: cmake --build build-octave --target mwrap_examples - name: Run Octave example tests run: ctest --test-dir build-octave --output-on-failure -R '^octave-' python-tests: name: Python mwrap tests runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y --no-install-recommends \ build-essential \ cmake \ bison \ flex \ zlib1g-dev - name: Build C++ mwrap run: | cmake -S . -B build cmake --build build --target mwrap - name: Run Python tests run: bash testing/test_python.sh build/src/mwrap python/mwrap zgimbutas-mwrap-25008ce/CMakeLists.txt000066400000000000000000000101521515063637600177460ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.16) project(mwrap LANGUAGES C CXX) include(CTest) option(MWRAP_ENABLE_MATLAB_CLASSDEF "Enable MATLAB classdef support (adds -DR2008OO)" OFF) option(MWRAP_ENABLE_C99_COMPLEX "Enable C99 complex support helpers" OFF) option(MWRAP_ENABLE_CPP_COMPLEX "Enable C++ complex support helpers" OFF) option(MWRAP_BUILD_EXAMPLES "Build the MATLAB/Octave examples" OFF) option(MWRAP_COMPILE_MEX "Compile generated wrappers into MEX binaries" OFF) set(MWRAP_MEX_BACKEND "MATLAB" CACHE STRING "Select the MEX backend to use (MATLAB, OCTAVE, or ALL)") set_property(CACHE MWRAP_MEX_BACKEND PROPERTY STRINGS MATLAB OCTAVE ALL) set(MWRAP_MEX_BACKENDS "" CACHE INTERNAL "Resolved list of MEX backends to configure" FORCE) unset(MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE CACHE) if(MWRAP_COMPILE_MEX) string(TOUPPER "${MWRAP_MEX_BACKEND}" _mwrap_mex_backend_upper) if(_mwrap_mex_backend_upper STREQUAL "ALL") set(_mwrap_resolved_backends MATLAB OCTAVE) elseif(_mwrap_mex_backend_upper STREQUAL "MATLAB") set(_mwrap_resolved_backends MATLAB) elseif(_mwrap_mex_backend_upper STREQUAL "OCTAVE") set(_mwrap_resolved_backends OCTAVE) else() message(FATAL_ERROR "Invalid MWRAP_MEX_BACKEND value '${MWRAP_MEX_BACKEND}'. " "Allowed values are MATLAB, OCTAVE, or ALL.") endif() set(MWRAP_MEX_BACKENDS "${_mwrap_resolved_backends}" CACHE INTERNAL "Resolved list of MEX backends to configure" FORCE) set(_mwrap_enable_matlab OFF) set(_mwrap_enable_octave OFF) foreach(_mwrap_backend IN LISTS _mwrap_resolved_backends) if(_mwrap_backend STREQUAL "MATLAB") set(_mwrap_enable_matlab ON) elseif(_mwrap_backend STREQUAL "OCTAVE") set(_mwrap_enable_octave ON) endif() endforeach() if(_mwrap_enable_matlab) find_package(Matlab COMPONENTS MEX_COMPILER MX_LIBRARY REQUIRED) endif() if(_mwrap_enable_octave) set(_mwrap_octave_mkoctfile "") set(_mwrap_octave_executable "") find_package(Octave QUIET COMPONENTS Octave_MKOCTFILE) if(Octave_FOUND) foreach(_mwrap_candidate_var IN ITEMS Octave_OCTAVE_MKOCTFILE_EXECUTABLE Octave_MKOCTFILE_EXECUTABLE Octave_MKOCTFILE) if(NOT _mwrap_octave_mkoctfile AND DEFINED ${_mwrap_candidate_var} AND ${_mwrap_candidate_var}) set(_mwrap_octave_mkoctfile "${${_mwrap_candidate_var}}") endif() endforeach() foreach(_mwrap_candidate_var IN ITEMS Octave_OCTAVE_EXECUTABLE Octave_EXECUTABLE Octave_OCTAVECLI_EXECUTABLE Octave_OCTAVE_CLI_EXECUTABLE) if(NOT _mwrap_octave_executable AND DEFINED ${_mwrap_candidate_var} AND ${_mwrap_candidate_var}) set(_mwrap_octave_executable "${${_mwrap_candidate_var}}") endif() endforeach() endif() if(NOT _mwrap_octave_mkoctfile) unset(_mwrap_octave_mkoctfile CACHE) unset(_mwrap_octave_mkoctfile) find_program(_mwrap_octave_mkoctfile mkoctfile) endif() if(NOT _mwrap_octave_mkoctfile) message(FATAL_ERROR "MWRAP_MEX_BACKEND requested Octave support but 'mkoctfile' was not found.") endif() set(MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE "${_mwrap_octave_mkoctfile}" CACHE FILEPATH "Path to the Octave mkoctfile executable" FORCE) if(NOT _mwrap_octave_executable) unset(_mwrap_octave_executable CACHE) unset(_mwrap_octave_executable) find_program(_mwrap_octave_executable NAMES octave-cli octave) endif() if(_mwrap_octave_executable) set(MWRAP_OCTAVE_EXECUTABLE "${_mwrap_octave_executable}" CACHE FILEPATH "Path to the Octave interpreter" FORCE) else() unset(MWRAP_OCTAVE_EXECUTABLE CACHE) endif() else() unset(MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE CACHE) unset(MWRAP_OCTAVE_EXECUTABLE CACHE) endif() else() set(MWRAP_MEX_BACKENDS "" CACHE INTERNAL "Resolved list of MEX backends to configure" FORCE) unset(MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE CACHE) unset(MWRAP_OCTAVE_EXECUTABLE CACHE) endif() add_subdirectory(src) if(MWRAP_BUILD_EXAMPLES) add_subdirectory(example) endif() if(BUILD_TESTING) add_subdirectory(testing) endif() zgimbutas-mwrap-25008ce/COPYING000066400000000000000000000025271515063637600162500ustar00rootroot00000000000000mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel MIT License, with an additional clause permitting redistribution of mwrap-generated source code under any license of your choice. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zgimbutas-mwrap-25008ce/Makefile000066400000000000000000000003771515063637600166560ustar00rootroot00000000000000include make.inc bin: (cd src; make) doc: (cd doc; make) test: (cd testing; make) demo: (cd example; make) clean: rm -f mwrap (cd src; make clean) (cd example; make clean) (cd testing; make clean) realclean: clean (cd src; make realclean) zgimbutas-mwrap-25008ce/NEWS000066400000000000000000000057531515063637600157200ustar00rootroot00000000000000Recent updates: Version 1.3 (Feb 23, 2026): Added CMake build system and GitHub Actions CI Validate input files before processing to prevent data loss Optimized MEX dispatch with integer ID + function pointer table Added #include for int64_t/uint64_t on Windows msys2/mingw64 Added Python mwrap implementation Version 1.2 (Apr 10, 2025): Cope with error verbose directive in both versions 2 and 3 of Bison Added support for gpuArray Added support for char scalar Version 1.1 (Jun 7, 2022): Added support for gfortran -fno-underscoring flag Version 1.0 (Aug 4, 2020): Added support for 64-bit Matlab and gcc-4.6 Added support for gcc 7.3+ Added support for Matlab R2018a complex interleaved API Added support for C99 int32_t, int64_t, uint32_t, uint64_t Allow single precision Matlab inputs and outputs Version 0.32 (Nov 5, 2008): Added support for new single-class style MATLAB objects; an example is in the manual, as well as in examples/eventq. Version 0.31 (Jun 19, 2008): Added line to license to clarify that code generated by MWrap may be redistributed under terms of the user's choice. Version 0.30 (Apr 29, 2008): Added more complete support for auto-converted objects, allowing them to be used as inout or output parameters and updating the documentation accordingly. Corrected bug in C call line checking feature (added in 0.28); corrected missing virtual destructor for Quad2d in FEM example. Version 0.29 (Apr 27, 2008): Reworked internal error handling logic. Added typedef mxArray support to allow automatic conversion of mxArrays to temporary objects on input. Version 0.28 (Mar 4, 2008): Added a check against ending a block of C call lines without finishing a statement (e.g. missing a semicolon on an isolated call line). Added support for C++ end-of-line comments inside C call lines. Added partial recovery on syntax errors. Version 0.27 (Feb 19, 2008): Added const arguments. Version 0.26 (Feb 18, 2008): Updated demos. Version 0.25 (Feb 8, 2008): Corrected code to add bounds checks on complex arrays. Added nonzero return codes on error. Version 0.24 (Feb 7, 2008): Added comment lines. Version 0.23 (Feb 6, 2008): Added logging support for profiling / coverage testing. Version 0.22 (Jan 29, 2008): Added @include support. Version 0.21 (Jan 7, 2008): Added support for string literal arguments. Added support for @function redirections. Corrected line number counting in presence of $[ $] code blocks. Version 0.20 (Sep 20, 2007): Added $[ $] delimiters for C code blocks. Version 0.19 (Sep 4, 2007): Added array references. Version 0.18 (August 15, 2007): Added interpretation of empty input array arguments as NULL. Version 0.17 (July 31, 2007): Added scoped names for access to static methods, namespaces. Version 0.16 (July 9, 2007): Added flags to set default complex support to C++ or C99 complex types Version 0.15 (July 5, 2007): Corrected complex support (needs setz macro) Version 0.14 (July 3, 2007): Added complex support Version 0.13 (June 30, 2007): Added FORTRAN bindings zgimbutas-mwrap-25008ce/README.md000066400000000000000000000127511515063637600164740ustar00rootroot00000000000000MWrap ===== MWrap is an interface generation system in the spirit of SWIG or matwrap. From a set of augmented MATLAB script files, it generates a MEX gateway to desired C/C++/Fortran function calls and MATLAB function files to access that gateway, hiding the details of converting to and from MATLAB's data structures and of allocating and freeing temporary storage. It is also compatible with modern Octave via `mkoctfile --mex`. It makes wrapping C/C++/Fortran from MATLAB almost pleasant! MWrap was created by David Bindel, who hosts his old version at https://www.cs.cornell.edu/~bindel/sw/mwrap Dependencies ------------ Building MWrap requires the following tools: * A C compiler with C99 support and a C++ compiler with C++11 support * [Bison](https://www.gnu.org/software/bison/) and [Flex](https://github.com/westes/flex) * (Optional) [CMake](https://cmake.org/) 3.16 or newer (for the CMake build path) * (Optional) [MATLAB](https://www.mathworks.com/products/matlab.html) with MEX build tooling when compiling wrappers with CMake If you are using a Debian or Ubuntu based system, the required packages can be installed via ``` sudo apt-get install build-essential bison flex cmake ``` Makefile build -------------- Edit `make.inc` and then run `make`. The output will be a standalone executable (`mwrap`) in the main directory. Bison and Flex are required for this build path. CMake build ----------- Alternatively, create a build directory and run CMake: ``` mkdir -p build cd build cmake .. cmake --build . ``` Cache options mirror the `make.inc` file. For example, to enable MATLAB `classdef` support and the C99 complex helpers: ``` cmake -DMWRAP_ENABLE_MATLAB_CLASSDEF=ON -DMWRAP_ENABLE_C99_COMPLEX=ON .. ``` ### Building the MATLAB/Octave examples The example wrappers under `example/` can be generated through CMake by turning on the `MWRAP_BUILD_EXAMPLES` option. This configuration runs `mwrap` to produce the C++ gateway sources (and any requested MATLAB scaffolding). By default the build stops after source generation, mirroring the legacy Makefiles. The resulting files live under the build tree in per-example subdirectories. ``` cmake -DMWRAP_BUILD_EXAMPLES=ON .. cmake --build . --target mwrap_examples ``` To have CMake invoke MATLAB's compiler and produce loadable MEX binaries, add `-DMWRAP_COMPILE_MEX=ON` when configuring. CMake will build the generated sources into MEX targets, attach them to the `mwrap_examples` aggregate target, and skip executing the binaries during the build. When running the MATLAB smoke tests locally (for example, `ctest -R matlab-`), build the `mwrap_examples` target beforehand so that the generated wrappers and MEX binaries are available to the test runner. The `MWRAP_MEX_BACKEND` cache entry selects which toolchain to use. MATLAB backends require CMake's `FindMatlab` module to locate MATLAB's development components, while Octave backends require the `mkoctfile` executable to be available. Choosing `ALL` emits binaries for both environments (and therefore requires both toolchains). ``` cmake -DMWRAP_BUILD_EXAMPLES=ON -DMWRAP_COMPILE_MEX=ON -DMWRAP_MEX_BACKEND=MATLAB .. cmake -DMWRAP_BUILD_EXAMPLES=ON -DMWRAP_COMPILE_MEX=ON -DMWRAP_MEX_BACKEND=OCTAVE .. cmake -DMWRAP_BUILD_EXAMPLES=ON -DMWRAP_COMPILE_MEX=ON -DMWRAP_MEX_BACKEND=ALL .. ``` If you leave `MWRAP_COMPILE_MEX` disabled, you can still invoke MATLAB or Octave's `mex` tool manually using the produced `.cc` file and any support sources that your project requires. Optional flags such as `MWRAP_ENABLE_MATLAB_CLASSDEF` remain available while configuring the examples. Example usage ------------- David Bindel's user's guide (`mwrap.pdf`) describes MWrap in detail; you can also look at the example subdirectories and the testing subdirectory to get some idea of how MWrap is used. Alex Barnett also maintains a set of minimally complete tutorial examples of calling C/Fortran libraries (including OpenMP) from MATLAB/Octave, using MWrap, at https://github.com/ahbarnett/mwrapdemo The `mwrap.1` man page was written by Nicolas Bourdaud. Contributors and version history -------------------------------- MWrap was originally written by David Bindel, c. 2009. It was moved to github in c. 2015 in order to add new features, and is now maintained by Zydrunas Gimbutas, Alex Barnett, Libin Lu, Manas Rachh, Rafael Laboissière, and Marco Barbone. **Version 0.33** (c. 2009) Author: David Bindel - Initial revision, clone David's repository (c. 2015) **Version 1.0** (c. 2020) Contributors: Zydrunas Gimbutas, Alex Barnett, Libin Lu. - Add support for 64-bit Matlab and gcc-4.6 - Add support for gcc 7.3+ - Add support for Matlab R2018a complex interleaved API - Add support for C99 int32_t, int64_t, uint32_t, uint64_t - Allow single precision Matlab inputs and outputs **Version 1.1** (2022) Contributors: Manas Rachh, Zydrunas Gimbutas. - Add support for gfortran -fno-underscoring flag **Version 1.2** (2025) Contributors: Libin Lu, Rafael Laboissière, Zydrunas Gimbutas. - Cope with error verbose directive in both versions 2 and 3 of Bison - Add support for Matlab gpuArray - Add support for char scalar **Version 1.3** (2026) Contributors: Marco Barbone, Zydrunas Gimbutas. - Add CMake build system and GitHub Actions CI - Validate input files before processing to prevent data loss - Optimize MEX dispatch with integer ID + function pointer table - Add `#include ` for int64_t/uint64_t on Windows msys2/mingw64 - Add Python mwrap implementation Also see https://github.com/zgimbutas/mwrap/tags zgimbutas-mwrap-25008ce/cmake/000077500000000000000000000000001515063637600162675ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/cmake/MwrapAddMex.cmake000066400000000000000000000251641515063637600214520ustar00rootroot00000000000000# mwrap_add_mex.cmake - helper to generate MATLAB/Octave wrapper sources with mwrap # # Usage: # mwrap_add_mex( # MW_FILES [...] # [MEX_NAME ] # [CC_FILENAME ] # [M_FILENAME ] # [CLASSDEF_NAME ] # [MWRAP_FLAGS [...]] # [WORK_DIR ] # [EXTRA_DEPENDS [...]] # [COMPILE_DEFINITIONS [...]] # [OUTPUT_VAR ] # ) # # The function wraps the mwrap executable produced by the current build to # generate a C/C++ source file (and optional MATLAB scaffolding). It creates a # custom target named after that depends on the generated source file. # Downstream projects can request the absolute path to the generated source via # OUTPUT_VAR and add it to their own targets. set(_MWRAP_ADD_MEX_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR}) function(mwrap_add_mex target_name) if(NOT target_name) message(FATAL_ERROR "mwrap_add_mex requires a target name") endif() set(options) set(oneValueArgs MEX_NAME CC_FILENAME M_FILENAME CLASSDEF_NAME WORK_DIR OUTPUT_VAR) set(multiValueArgs MW_FILES MWRAP_FLAGS EXTRA_DEPENDS EXTRA_SOURCES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS) cmake_parse_arguments(MAM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(MWRAP_ENABLE_MATLAB_CLASSDEF) list(APPEND MAM_COMPILE_DEFINITIONS R2008OO) list(REMOVE_DUPLICATES MAM_COMPILE_DEFINITIONS) endif() if(NOT MAM_MW_FILES) message(FATAL_ERROR "mwrap_add_mex(${target_name}) requires MW_FILES to be specified") endif() if(NOT TARGET mwrap) message(FATAL_ERROR "mwrap_add_mex requires the mwrap executable target to exist") endif() if(NOT MAM_MEX_NAME) set(MAM_MEX_NAME "${target_name}") endif() if(NOT MAM_CC_FILENAME) if(MAM_MEX_NAME MATCHES "\\.(c|cc|cpp)$") set(MAM_CC_FILENAME "${MAM_MEX_NAME}") else() set(MAM_CC_FILENAME "${MAM_MEX_NAME}.cc") endif() endif() if(MAM_WORK_DIR) set(mwrap_binary_dir "${MAM_WORK_DIR}") else() set(mwrap_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/${target_name}") endif() file(MAKE_DIRECTORY "${mwrap_binary_dir}") set(cc_output "${mwrap_binary_dir}/${MAM_CC_FILENAME}") get_filename_component(cc_basename "${cc_output}" NAME) set(mwrap_command $ -mex ${MAM_MEX_NAME} -c "${cc_output}") set(mwrap_depends ${MAM_EXTRA_DEPENDS}) set(mwrap_working_dir "${mwrap_binary_dir}") set(mwrap_inputs) set(mw_absolute_inputs) set(mw_parent_dirs) set(mwrap_stage_commands) foreach(mw IN LISTS MAM_MW_FILES) if(IS_ABSOLUTE "${mw}") set(mw_abs "${mw}") else() set(mw_abs "${CMAKE_CURRENT_SOURCE_DIR}/${mw}") endif() list(APPEND mw_absolute_inputs "${mw_abs}") get_filename_component(mw_parent "${mw_abs}" DIRECTORY) list(APPEND mw_parent_dirs "${mw_parent}") endforeach() list(REMOVE_DUPLICATES mw_parent_dirs) if(mw_parent_dirs) list(LENGTH mw_parent_dirs mw_parent_dir_count) if(mw_parent_dir_count EQUAL 1) foreach(mw_abs IN LISTS mw_absolute_inputs) get_filename_component(mw_basename "${mw_abs}" NAME) list(APPEND mwrap_inputs "${mw_basename}") list(APPEND mwrap_stage_commands COMMAND ${CMAKE_COMMAND} -E copy_if_different "${mw_abs}" "${mwrap_binary_dir}/${mw_basename}") endforeach() else() foreach(mw_abs IN LISTS mw_absolute_inputs) file(RELATIVE_PATH mw_rel "${mwrap_binary_dir}" "${mw_abs}") list(APPEND mwrap_inputs "${mw_rel}") endforeach() endif() endif() if(MAM_CLASSDEF_NAME) set(classdef_dir "${mwrap_binary_dir}/@${MAM_CLASSDEF_NAME}") endif() if(NOT mwrap_inputs) set(mwrap_inputs ${MAM_MW_FILES}) endif() if(MAM_M_FILENAME) list(APPEND mwrap_command -m "${mwrap_binary_dir}/${MAM_M_FILENAME}") endif() if(MAM_MWRAP_FLAGS) list(APPEND mwrap_command ${MAM_MWRAP_FLAGS}) endif() foreach(mw IN LISTS mwrap_inputs) list(APPEND mwrap_command "${mw}") endforeach() list(APPEND mwrap_depends ${mw_absolute_inputs}) list(APPEND mwrap_depends mwrap) set(pre_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${mwrap_binary_dir}") if(classdef_dir) list(APPEND pre_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${classdef_dir}") endif() list(APPEND pre_commands ${mwrap_stage_commands}) add_custom_command( OUTPUT "${cc_output}" ${pre_commands} COMMAND ${mwrap_command} WORKING_DIRECTORY "${mwrap_working_dir}" DEPENDS ${mwrap_depends} COMMENT "Generating ${cc_basename} with mwrap" VERBATIM COMMAND_EXPAND_LISTS ) set_source_files_properties("${cc_output}" PROPERTIES GENERATED TRUE) add_custom_target(${target_name} DEPENDS "${cc_output}") add_dependencies(${target_name} mwrap) if(MAM_OUTPUT_VAR) set(${MAM_OUTPUT_VAR} "${cc_output}" PARENT_SCOPE) endif() set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_SOURCE "${cc_output}") set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_DIRECTORY "${mwrap_binary_dir}") set_property(TARGET ${target_name} PROPERTY MWRAP_MEX_NAME "${MAM_MEX_NAME}") if(MAM_EXTRA_SOURCES) set_property(TARGET ${target_name} PROPERTY MWRAP_EXTRA_SOURCES "${MAM_EXTRA_SOURCES}") endif() if(MAM_INCLUDE_DIRECTORIES) set_property(TARGET ${target_name} PROPERTY MWRAP_INCLUDE_DIRECTORIES "${MAM_INCLUDE_DIRECTORIES}") endif() if(MAM_COMPILE_DEFINITIONS) set_property(TARGET ${target_name} PROPERTY MWRAP_COMPILE_DEFINITIONS "${MAM_COMPILE_DEFINITIONS}") endif() if(MAM_M_FILENAME) set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_M_FILE "${mwrap_binary_dir}/${MAM_M_FILENAME}") endif() if(classdef_dir) set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_CLASSDEF_DIR "${classdef_dir}") endif() endfunction() function(_mwrap_compile_mex target_name) set(options) set(oneValueArgs OUTPUT_VAR) set(multiValueArgs) cmake_parse_arguments(MCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT TARGET ${target_name}) message(FATAL_ERROR "_mwrap_compile_mex was asked to process unknown target '${target_name}'") endif() if(NOT MWRAP_MEX_BACKENDS) message(FATAL_ERROR "_mwrap_compile_mex requires at least one configured backend") endif() get_target_property(cc_output ${target_name} MWRAP_OUTPUT_SOURCE) if(NOT cc_output) message(FATAL_ERROR "Target '${target_name}' does not have generated source metadata") endif() get_target_property(mwrap_binary_dir ${target_name} MWRAP_OUTPUT_DIRECTORY) if(NOT mwrap_binary_dir OR mwrap_binary_dir STREQUAL "NOTFOUND") message(FATAL_ERROR "Target '${target_name}' is missing its output directory metadata") endif() get_target_property(mex_name ${target_name} MWRAP_MEX_NAME) if(NOT mex_name) set(mex_name ${target_name}) endif() get_target_property(extra_sources ${target_name} MWRAP_EXTRA_SOURCES) if(NOT extra_sources OR extra_sources STREQUAL "NOTFOUND") unset(extra_sources) endif() set(mex_sources "${cc_output}") if(extra_sources) list(APPEND mex_sources ${extra_sources}) endif() get_target_property(include_dirs ${target_name} MWRAP_INCLUDE_DIRECTORIES) if(include_dirs STREQUAL "NOTFOUND") unset(include_dirs) endif() get_target_property(compile_defs ${target_name} MWRAP_COMPILE_DEFINITIONS) if(compile_defs STREQUAL "NOTFOUND") unset(compile_defs) endif() set(_mwrap_mex_targets) set(_mwrap_mex_paths) foreach(_mwrap_backend IN LISTS MWRAP_MEX_BACKENDS) if(_mwrap_backend STREQUAL "MATLAB") if(NOT COMMAND matlab_add_mex) message(FATAL_ERROR "MATLAB backend requested, but matlab_add_mex() is unavailable") endif() set(mex_target "${target_name}_mex") matlab_add_mex(NAME ${mex_target} SRC ${mex_sources} OUTPUT_NAME "${mex_name}") add_dependencies(${mex_target} ${target_name}) if(include_dirs) target_include_directories(${mex_target} PRIVATE ${include_dirs}) endif() if(compile_defs) target_compile_definitions(${mex_target} PRIVATE ${compile_defs}) endif() list(APPEND _mwrap_mex_targets "${mex_target}") list(APPEND _mwrap_mex_paths "$") elseif(_mwrap_backend STREQUAL "OCTAVE") if(NOT MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE) message(FATAL_ERROR "Octave backend requested, but no mkoctfile executable was configured") endif() set(mex_target "${target_name}_mex_octave") set(octave_output "${mwrap_binary_dir}/${mex_name}.mex") set(octave_sources) foreach(oct_src IN LISTS mex_sources) if(IS_ABSOLUTE "${oct_src}") set(oct_src_abs "${oct_src}") else() get_filename_component(oct_src_abs "${oct_src}" ABSOLUTE) endif() list(APPEND octave_sources "${oct_src_abs}") endforeach() set(octave_include_args) if(include_dirs) foreach(inc_dir IN LISTS include_dirs) if(NOT IS_ABSOLUTE "${inc_dir}") get_filename_component(inc_dir "${inc_dir}" ABSOLUTE) endif() list(APPEND octave_include_args "-I${inc_dir}") endforeach() endif() set(octave_define_args) if(compile_defs) foreach(definition IN LISTS compile_defs) list(APPEND octave_define_args "-D${definition}") endforeach() endif() add_custom_command( OUTPUT "${octave_output}" COMMAND ${CMAKE_COMMAND} -E make_directory "${mwrap_binary_dir}" COMMAND ${MWRAP_OCTAVE_MKOCTFILE_EXECUTABLE} --mex -o "${octave_output}" ${octave_include_args} ${octave_define_args} ${octave_sources} DEPENDS ${octave_sources} ${target_name} COMMENT "Building Octave MEX ${mex_name}" VERBATIM COMMAND_EXPAND_LISTS ) add_custom_target(${mex_target} DEPENDS "${octave_output}") add_dependencies(${mex_target} ${target_name}) list(APPEND _mwrap_mex_targets "${mex_target}") list(APPEND _mwrap_mex_paths "${octave_output}") else() message(FATAL_ERROR "Unknown MEX backend '${_mwrap_backend}' requested") endif() endforeach() if(_mwrap_mex_targets) list(GET _mwrap_mex_targets 0 _mwrap_primary_target) list(GET _mwrap_mex_paths 0 _mwrap_primary_path) set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_TARGET "${_mwrap_primary_target}") set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_PATH "${_mwrap_primary_path}") set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_TARGETS "${_mwrap_mex_targets}") set_property(TARGET ${target_name} PROPERTY MWRAP_OUTPUT_MEX_PATHS "${_mwrap_mex_paths}") endif() if(MCC_OUTPUT_VAR) set(${MCC_OUTPUT_VAR} "${_mwrap_mex_targets}" PARENT_SCOPE) endif() endfunction() zgimbutas-mwrap-25008ce/cmake/run_stringify.cmake000066400000000000000000000011351515063637600221730ustar00rootroot00000000000000if(NOT DEFINED STRINGIFY) message(FATAL_ERROR "STRINGIFY executable location is required") endif() if(NOT DEFINED INPUT) message(FATAL_ERROR "INPUT file is required") endif() if(NOT DEFINED OUTPUT) message(FATAL_ERROR "OUTPUT file is required") endif() if(NOT DEFINED NAME) message(FATAL_ERROR "String symbol NAME is required") endif() execute_process( COMMAND "${STRINGIFY}" "${NAME}" INPUT_FILE "${INPUT}" OUTPUT_FILE "${OUTPUT}" RESULT_VARIABLE _stringify_result ) if(NOT _stringify_result EQUAL 0) message(FATAL_ERROR "stringify failed with exit code ${_stringify_result}") endif() zgimbutas-mwrap-25008ce/doc/000077500000000000000000000000001515063637600157545ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/doc/Makefile000066400000000000000000000004551515063637600174200ustar00rootroot00000000000000all: mwrap.pdf RELEASE_DATE = $(shell grep "^Version " ../NEWS | head -n1 | sed "s/^Version .*(\(.*\)):/\1/") mwrap.tex: mwrap.tex.in sed "s/@RELEASE_DATE@/$(RELEASE_DATE)/" < mwrap.tex.in > mwrap.tex mwrap.pdf: mwrap.tex pdflatex mwrap.tex clean: rm -f mwrap.aux mwrap.log mwrap.tex mwrap.pdf zgimbutas-mwrap-25008ce/doc/mwrap.1000066400000000000000000000050501515063637600171640ustar00rootroot00000000000000.TH MWRAP 1 2012 "mwrap" "MWRAP manpage" .SH NAME mwrap - Octave/MATLAB mex generator .SH SYNOPSIS .SY mwrap .OP \-mex \fIoutputmex\fP .OP \-m \fIoutput.m\fP .OP \-c \fIoutputmex.c\fP .OP \-mb .OP \-list .OP \-catch .OP \-i8 .OP \-c99complex .OP \-cppcomplex .OP \-gpu \fIinfile1\fP \fIinfile2\fP ... .br .SH DESCRIPTION .LP \fBmwrap\fP is an interface generation system in the spirit of SWIG or matwrap. From a set of augmented Octave/MATLAB script files, \fBmwrap\fP will generate a MEX gateway to desired C/C++ function calls and \.m function files to access that gateway. The details of converting to and from Octave's or MATLAB's data structures, and of allocating and freeing temporary storage, are hidden from the user. .SH OPTIONS .TP .B \-mex specifies the name of the MEX function that the generated functions will call. This name will generally be the same as the prefix for the C/C++ output file name. . .TP .B \-m specifies the name of the Octave/MATLAB script to be generated. . .TP .B \-c specifies the name of the C MEX file to be generated. The MEX file may contain stubs corresponding to several different generated files. . .TP .B \-mb redirect Octave/MATLAB function output to files named in the input. In this mode, the processor will change Octave/MATLAB function output files whenever it encounters a line beginning with @. If @ occurs alone on a line, the output will be turned off; if the line begins with @function, the line will be treated as the first line of a function, and the m-file name will be deduced from the function name; and otherwise, the characters after @ (up to the next set of white space) will be treated as a filename, and \fBmwrap\fP will try to write to that file. . .TP .B \-list print to the standard output the names of all files that would be generated from redirect output by the \-mb flag. . .TP .B \-catch surround library calls in try/catch blocks in order to intercept C++ exceptions. . .TP .B \-i8 convert \fBint\fP, \fBlong\fP, \fBuint\fP, \fBulong\fP types to \fBint64_t\fP, \fBuint64_t\fP. This provides a convenient way to interface with \fB-fdefault-integer-8\fP and \fB-i8\fP flags used by Fortran compilers. . .TP .B \-c99complex use the C99 complex floating point types as the default \fBdcomplex\fP and \fBfcomplex\fP types. . .TP .B \-cppcomplex use the C++ complex floating point types as the default \fBdcomplex\fP and \fBfcomplex\fP types. . .TP .B \-gpu add support code for MATLAB gpuArray. .SH AUTHORS .LP \fBmwrap\fP is written by David Bindel and Zydrunas Gimbutas. This manual page was written by Nicolas Bourdaud. zgimbutas-mwrap-25008ce/doc/mwrap.tex.in000066400000000000000000001013021515063637600202260ustar00rootroot00000000000000\documentclass[12pt]{article} \usepackage{amsmath} \usepackage{fancyheadings} \setlength{\oddsidemargin}{0.0in} \setlength{\textwidth}{6.5in} \setlength{\topmargin}{-0.5in} \setlength{\textheight}{9.0in} \bibliographystyle{unsrt} \renewcommand{\baselinestretch}{1.0} \newcommand{\mwrap}{\textsc{MWrap}} \newcommand{\gOR}{ $|$ } \title{\mwrap\ User Guide\\ Version 1.3} \author{D.~Bindel, A.~Barnett, Z.~Gimbutas, M.~Rachh, L.~Lu, R.~Laboissi\`ere} \date{@RELEASE_DATE@} \pagestyle{fancy} %%\headrulewidth 1.5pt %%\footrulewidth 1.5pt \chead{\mwrap} \lhead{} \rhead{} \cfoot{\thepage} \begin{document} \maketitle \section{Introduction} \mwrap\ is an interface generation system in the spirit of SWIG or matwrap. From a set of augmented MATLAB script files, \mwrap\ will generate a MEX gateway to desired C/C++ function calls and MATLAB function files to access that gateway. The details of converting to and from MATLAB's data structures, and of allocating and freeing temporary storage, are hidden from the user. \mwrap\ files look like MATLAB scripts with specially formatted extra lines that describe calls to C/C++. For example, the following code is converted into a call to the C {\tt strncat} function: \begin{verbatim} $ #include function foobar; s1 = 'foo'; s2 = 'bar'; # strncat(inout cstring[128] s1, cstring s2, int 127); fprintf('Should be foobar: %s\n', s1); \end{verbatim} There are two structured comments in this file. The line beginning with \verb|$| tells \mwrap\ that this line is C/C++ support code, and the line beginning with \verb|#| describes a call to the C {\tt strncat} function. The call description includes information about the C type to be used for the input arguments, and also describes which parameters are used for input and for output. From this input file, \mwrap\ produces two output files: a C file which will be compiled with the MATLAB {\tt mex} script, and a MATLAB script which calls that MEX file. If the above file is {\tt foobar.mw}, for example, we would generate an interface file {\tt foobar.m} and a MEX script {\tt fbmex.mex} with the lines \begin{verbatim} mwrap -mex fbmex -m foobar.m foobar.mw mwrap -mex fbmex -c fbmex.c foobar.mw mex fbmex.c \end{verbatim} At this point, we can run the {\tt foobar} script from the MATLAB prompt: \begin{verbatim} >> foobar Should be foobar: foobar \end{verbatim} Versions of GNU Octave released after mid-2006 support much of MATLAB's MEX interface. Simple {\mwrap}-generated code should work with GNU Octave. To compile for GNU Octave, use \texttt{mkoctfile --mex} instead of invoking \texttt{mex}. GNU Octave does not implement MATLAB's object model, so code that uses MATLAB's object-oriented facilities will not function with GNU Octave. \section{\mwrap\ command line} The {\tt mwrap} command line has the following form: \begin{verbatim} mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb] [-list] [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu] infile1 infile2 ... \end{verbatim} where \begin{itemize} \item {\tt -mex} specifies the name of the MEX function that the generated MATLAB functions will call. This name will generally be the same as the prefix for the C/C++ output file name. \item {\tt -m} specifies the name of the MATLAB script to be generated. \item {\tt -c} specifies the name of the C MEX file to be generated. The MEX file may contain stubs corresponding to several different generated MATLAB files. \item {\tt -mb} tells \mwrap\ to redirect MATLAB function output to files named in the input. In this mode, the processor will change MATLAB function output files whenever it encounters a line beginning with \verb|@|. If \verb|@| occurs alone on a line, MATLAB output will be turned off; if the line begins with \verb|@function|, the line will be treated as the first line of a function, and the m-file name will be deduced from the function name; and otherwise, the characters after \verb|@| (up to the next set of white space) will be treated as a filename, and \mwrap\ will try to write to that file. \item {\tt -list} tells \mwrap\ to print to the standard output the names of all files that would be generated from redirect output by the {\tt -mb} flag. \item {\tt -catch} tells \mwrap\ to surround library calls in try/catch blocks in order to intercept C++ exceptions. \item {\tt -i8} tells \mwrap\ to convert {\tt int}, {\tt long}, {\tt uint}, {\tt ulong} types to {\tt int64\_t}, {\tt uint64\_t}. This provides a convenient way to interface with {\tt -fdefault-integer-8} and {\tt -i8} flags used by Fortran compilers. \item {\tt -c99complex} tells \mwrap\ to use the C99 complex floating point types as the default {\tt dcomplex} and {\tt fcomplex} types. \item {\tt -cppcomplex} tells \mwrap\ to use the C++ complex floating point types as the default {\tt dcomplex} and {\tt fcomplex} types. \item {\tt -gpu} tells \mwrap\ to add support code for MATLAB gpuArray. \end{itemize} \section{Interface syntax} \subsection{Input line types} \mwrap\ recognizes six types of lines, based on the first non-space characters at the start of the line: \begin{itemize} \item C support lines begin with \verb|$|. These lines are copied into the C code that makes up the MEX file. Typically, such support lines are used to include any necessary header files; they can also be used to embed short functions. \item Blocks of C support can be opened by the line \verb|$[| and closed by the line \verb|$]|. Like lines beginning with \verb|$|, lines that fall between the opening and closing markers are copied into the C code that makes up the MEX file. \item C call lines begin with \verb|#|. These lines are parsed in order to generate an interface function as part of the MEX file and a MATLAB call line to invoke that interface function. C call lines can refer to variables declared in the local MATLAB environment. \item Input redirection lines (include lines) begin with \verb|@include|. The input file name should not be quoted in any way. \item Output redirection lines begin with \verb|@|. % Output redirection is used to specify several generated MATLAB scripts with a single input file. \item Comment lines begin with \verb|//|. Comment lines are not included in any output file. \item All other lines are treated as ordinary MATLAB code, and are passed through to a MATLAB output file without further processing. \end{itemize} \subsection{C call syntax} The complete syntax for \mwrap\ call statements is given in Figure~\ref{mwrap-syntax-fig}. Each statement makes a function or method call, and optionally assigns the output to a variable. For each argument or return variable, we specify the type and also say whether the variable is being used for input, for output, or for both. Variables are given by names which should be valid identifiers in the local MATLAB environment where the call is to be made. Input arguments can also be given numeric values, though it is still necessary to provide type information. There are three types of call specifications. Ordinary functions not attached to a class can be called by name: \begin{verbatim} # do_something(); \end{verbatim} To create a new C++ object instance, we use the {\tt new} command \begin{verbatim} # Thermometer* therm = new Thermometer(double temperature0); \end{verbatim} And once we have a handle to an object, we can invoke methods on it \begin{verbatim} # double temperature = therm->Thermometer.get_temperature(); \end{verbatim} Object deletion is handled just like an ordinary function call \begin{verbatim} # delete(Thermometer* therm); \end{verbatim} Intrinsic operators like {\tt sizeof} can also be invoked in this manner. The type specifications are \emph{only} used to determine how \mwrap\ should handle passing data between MATLAB and a C/C++ statement; the types specified in the call sequence should be compatible with a corresponding C/C++ definition, but they need not be identical to the types in a specific function or method declaration. An \mwrap\ type specification consists of three parts. The first (optional) part says whether the given variable will be used for input ({\tt input}), for output ({\tt output}), or for both. The second part gives the basic type name for the variable; this may be an intrinsic type like {\tt int} or {\tt double}, a string, an object type, or a MATLAB intrinsic (see Section~\ref{type-section}). Finally, there may be modifiers to specify that this is a pointer, a reference, or an array. Array and string arguments may also have explicitly provided size information. In the example from the introduction, for example the argument declaration \begin{verbatim} inout cstring[128] s1 \end{verbatim} tells \mwrap\ that {\tt s1} is a C string which is used for input and output, and that the buffer used should be at least 128 characters long. Identifiers in \mwrap\ may include C++ scope specifications to indicate that a function or method belongs to some namespace or that it is a static member of a class. That is, it is valid to write something like \begin{verbatim} std::ostream* os = foo->get_ostream(); \end{verbatim} Scoped names may be used for types or for method names, but it is an unchecked error to use a scoped name for a parameter or return variable. \begin{figure} \begin{center} \begin{tabular}{l@{ := }l} statement & returnvar {\tt = } func {\tt (} args {\tt );} \\ & func {\tt (} args {\tt );} \\ & {\tt typedef numeric} {\it type-id} {\tt ;} \\ & {\tt typedef dcomplex} {\it type-id} {\tt ;} \\ & {\tt typedef fcomplex} {\it type-id} {\tt ;} \\ & {\tt class} {\it child-id} {\tt :} {\it parent-id} {\tt ,} {\it parent-id} {\tt ,} $\ldots$ \vspace{5mm} \\ func & {\it function-id} \\ & {\tt FORTRAN} {\it function-id} \\ & {\it this-id} {\tt .} {\it class-id} {\tt ->} {\it method-id}\\ & {\tt new} {\it class-id} \vspace{5mm} \\ args & arg {\tt ,} arg {\tt ,} $\ldots$ \gOR\ $\epsilon$ \\ arg & devicespec iospec type {\it var-id} \\ & devicespec ispec type {\it value} \\ returnvar & type {\it var-id} \vspace{5mm} \\ devicespec & {\tt cpu} \gOR\ {\tt gpu} \gOR\ $\epsilon$ \\ iospec & {\tt input} \gOR\ {\tt output} \gOR\ {\tt inout} \gOR\ $\epsilon$ \\ ispec & {\tt input} \gOR\ $\epsilon$ \\ type & {\it type-id} \gOR {\it type-id} {\tt *} \gOR\ {\it type-id} {\tt \&} \gOR\ {\it type-id} {\tt [} dims {\tt]} \gOR\ {\it type-id} {\tt [} dims {\tt] \&} \\ dims & dim {\tt ,} dim {\tt ,} $\ldots$ \gOR\ $\epsilon$ \\ dim & {\it var-id} \gOR\ {\it number} \end{tabular} \caption{\mwrap\ call syntax} \label{mwrap-syntax-fig} \end{center} \end{figure} \section{Variable types} \label{type-section} \mwrap\ recognizes several different general types of variables as well as constant expressions: \subsection{Numeric types} {\it Scalars} are intrinsic numeric types in C/C++: {\tt double}, {\tt float}, {\tt long}, {\tt int}, {\tt char}, {\tt ulong}, {\tt uint}, {\tt uchar}, {\tt bool}, {\tt int32\_t}, {\tt uint32\_t}, {\tt int64\_t}, {\tt uint64\_t}, {\tt ptrdiff\_t} and {\tt size\_t}. These are the numeric types that \mwrap\ knows about by default, but if necessary, new numeric types can be declared using {\tt typedef} commands. For example, if we wanted to use {\tt float64\_t} as a numeric type, we would need the line \begin{verbatim} # typedef numeric float64_t; \end{verbatim} Ordinary scalars cannot be used as output arguments. {\it Scalar pointers} are pointers to the recognized numeric intrinsics. They are assumed to refer to {\em one} variable; that is, a {\tt double*} in \mwrap\ is a pointer to one double in memory, which is different from a double array ({\tt double[]}). {\it Scalar references} are references to the recognized numeric intrinsics. {\it Arrays} store arrays of recognized numeric intrinsics. They may have explicitly specified dimensions (in the case of pure return arrays and pure output arguments, they \emph{must} have explicitly specified dimensions), but the dimensions can also be automatically determined from the input data. If only one dimension is provided, return and output arrays are allocated as column vectors. If a function is declared to return an array or a scalar pointer and the C return value is NULL, \mwrap\ will pass an empty array back to MATLAB. If an empty array is passed to a function as an input array argument, \mwrap\ will interpret that argument as NULL. {\it Array references} are references to numeric arrays, such as in a function whose C++ prototype looks like \begin{verbatim} void output_array(const double*& data); \end{verbatim} Array references may only be used as output arguments, and the array must have explicitly specified dimensions. If the value of the data pointer returned from the C++ function is NULL, \mwrap\ will pass an empty array back to MATLAB. {\it Complex} scalars pose a special challenge. C++ and C99 provide distinct complex types, and some C89 libraries define complex numbers via structures. If the {\tt -cppcomplex} or {\tt -c99complex} flags are specified, {\tt mwrap} will automatically define complex double and single precision types {\tt dcomplex} and {\tt fcomplex} which are bound to the C++ or C99 double-precision and single-precision complex types. More generally, we allow complex numbers which are conceptually pairs of floats or doubles to be defined using {\tt typedef fcomplex} and {\tt typedef dcomplex} commands. For example, in C++, we might use the following commands to set up a double complex type {\tt cmplx} (which is equivalent to the {\tt dcomplex} type when the {\tt -cppcomplex} flag is used): \begin{verbatim} $ #include $ typedef std::complex cmplx; // Define a complex type $ #define real_cmplx(z) (z).real() // Accessors for real, imag $ #define imag_cmplx(z) (z).imag() // (req'd for complex types) $ #define setz_cmplx(z,r,i) *z = dcomplex(r,i) # typedef dcomplex cmplx; \end{verbatim} The macro definitions {\tt real\_cmplx}, {\tt imag\_cmplx}, and {\tt setz\_cmplz} are used by \mwrap\ to read or write the real and imaginary parts of a number of type {\tt cmplx}. Similar macro definitions must be provided for any other complex type to be used. Other than any setup required to define what will be used as a complex type, complex scalars can be used in all the same ways that real and integer scalars are used. \subsection{Strings} {\it Strings} are C-style null-terminated character strings. They are specified by the \mwrap\ type {\tt cstring}. A {\tt cstring} type is not equivalent to a {\tt char[]} type, since the latter is treated as an array of numbers (represented by a double vector in MATLAB) in which zero is given no particular significance. The dimensions can be of a {\tt cstring} can explicitly specified or they can be implicit. When a C string is used for output, the size of the corresponding character buffer \emph{must} be given; and when a C string is used for input, the size of the corresponding character buffer should not be given. If a function is declared to return a C string and the return value is NULL, \mwrap\ will pass back the scalar 0. \subsection{Objects} {\it Objects} are variables with any base type other than one of the recognized intrinsics (or the {\tt mxArray} pass-through -- see below). This can lead to somewhat startling results when, for example, \mwrap\ decides a {\tt size\_t} is a dynamic object type (this will only give surprises if one tries to pass in a numeric value). If a function or method returns an object, \mwrap\ will make a copy of the return object on the heap and pass back that copy. {\it Object references} are treated the same as objects, except that when a function returns an object reference, \mwrap\ will return the address associated with that reference, rather than making a new copy of the object. {\it Object pointers} may either point to a valid object of the appropriate type or to NULL (represented by zero). This is different from the treatment of objects and object references. When a NULL value is specified for a {\tt this} argument, an object argument, or an object reference argument, \mwrap\ will generate a MATLAB error message. If the wrapped code uses an object hierarchy, you can use \mwrap\ class declarations so that valid casts to parent types will be performed automatically. For example, the declaration \begin{verbatim} # class Child : Parent1, Parent2; \end{verbatim} tells \mwrap\ that an object of type {\tt Child} may be passed in where an object of type {\tt Parent1} is required. The generated code works correctly with C++ multiple inheritance. Objects cannot be declared as output or inout parameters, but that just means that the identity of an object parameter does not change during a call. There's nothing wrong with changing the internal state of the object. By default, \mwrap\ stores non-NULL object references in strings. However, for MATLAB 2008a and onward, \mwrap\ will also interpret as objects any classes with a readable property {\tt mwptr}. This can be used, for example, to implement class wrappers using the new {\tt classdef} keyword. In order to use this feature, the macro {\tt R2008OO} must be defined by adding the argument {\tt -DR2008OO} to the {\tt mex} compile line. \subsection{{\tt mxArray}} The {\it mxArray} type in \mwrap\ refers to MATLAB's basic object type (also called {\tt mxArray}). {\tt mxArray} arguments can be used as input or output arguments (but not as inout arguments), or as return values. On input, {\tt mxArray} is mapped to C type {\tt const mxArray*}; on output, it is mapped to {\tt mxArray**}; and on return, it is mapped to {\tt mxArray*}. For example, the line \begin{verbatim} # mxArray do_something(mxArray in_arg, output mxArray out_arg); \end{verbatim} is compatible with a function defined as \begin{verbatim} mxArray* do_something(const mxArray* in_arg, mxArray** out_arg); \end{verbatim} Note that the header file {\tt mex.h} must be included for this function declaration to make any sense. The primary purpose for the mxArray pass through is to allow specialized routines to read the internal storage of MATLAB sparse matrices (and possibly other structures) for a few routines without giving up the convenience of the \mwrap\ framework elsewhere. \subsection{Auto-converted objects} If there is a natural mapping from some MATLAB data structure to a C/C++ object type, you can use a typedef to tell \mwrap\ to perform automatic conversion. For example, if we wanted {\tt Foo} to be automatically converted from some MATLAB data structure on input, then we would add the line \begin{verbatim} # typedef mxArray Foo; \end{verbatim} With this declaration, {\tt Foo} objects are automatically converted from {\tt mxArray} to the corresponding C++ type on input, and back to {\tt mxArray} objects on output. It is assumed that \mwrap\ {\em owns the argument objects} and {\em does not own the return objects}. This feature should not be used when the C++ side keeps a pointer or reference to a passed object, or when the caller is responsible for deleting a dynamically allocated return object. Auto-converted objects rely on the following user-defined functions: \begin{verbatim} Foo* mxWrapGet_Foo(const mxArray* a, const char** e); mxArray* mxWrapSet_Foo(Foo* o); Foo* mxWrapAlloc_Foo(); void mxWrapFree_Foo(Foo* o); \end{verbatim} Not all functions are needed for all uses of an auto-converted type. The functions play the following roles: \begin{enumerate} \item The \verb|mxWrapGet_Foo| function is used to convert an input argument to the corresponding C++ representation. If an error occurs during conversion, the second argument should be pointed toward an error message string. It is assumed that this conversion function will catch any thrown exceptions. \item The \verb|mxWrapSet_Foo| function is used to convert an output argument or return value to the corresponding C++ representation. \item The \verb|mxWrapAlloc_Foo| function is used to allocate a new temporary for use as an output argument. \item The \verb|mxWrapFree_Foo| function is used to deallocate a temporary created by \verb|mxWrapGet_Foo| or \verb|mxWrapAlloc_Foo|. \end{enumerate} The point of auto-converted objects is to simplify wrapper design for codes that make heavy use of things like C++ vector classes (for example). The system does {\em not} provide the same flexibility as the {\tt mxArray} object, nor is it as flexible as a sequence of \mwrap\ calls to explicitly create and manage temporaries and their conversion to and from MATLAB objects. At present, the behavior when you try to involve an auto-converted object in an inheritance relation is undefined. Don't try it at home. \subsection{Constants} The {\it const} type in \mwrap\ refers to a C/C++ symbolic constant or global variable. The name of the variable is output directly into the compiled code. For example, to print a string to {\tt stderr}, we can write \begin{verbatim} # fprintf(const stderr, cstring s); \end{verbatim} \subsection{{\tt mxSINGLE\_CLASS} and {\tt mxDOUBLE\_CLASS}} By default, {\tt mwrap 0.33} expected all input and output numeric MATLAB variables to be of {\tt mxDOUBLE\_CLASS}. The newest version of {\tt mwrap (0.33.12+)} allows {\tt mxSINGLE\_CLASS} for {\tt float} and {\tt fcomplex} types. An error {\tt 'Invalid array argument, mxSINGLE/DOUBLE\_CLASS expected'} will be issued if a mismatched Matlab variable is detected during runtime. The user is expected to perform the required type conversions manually using {\tt single} or {\tt double} MATLAB commands. \subsection{{\tt mxCHAR\_CLASS}} {\tt mwrap (1.2+)} allows character constants of {\tt mxCHAR\_CLASS} for {\tt char} types and forces type checking. An error {\tt 'Invalid array argument, mxCHAR\_CLASS expected'} will be issued if a mismatched Matlab variable is detected during runtime. The user is expected to perform the required type conversions manually using {\tt char} MATLAB command. \subsection{GPU array passing} \label{gpu-section} When the {\tt -gpu} flag is specified, \mwrap\ adds support for MATLAB {\tt gpuArray} objects. The {\tt gpu} device specifier can be placed before the usual {\tt input}, {\tt output}, or {\tt inout} keywords to indicate that an array argument resides on the GPU: \begin{verbatim} # func(gpu input double[n] x, gpu output double[n] y, int n); \end{verbatim} For GPU input arrays, \mwrap\ verifies that the argument is a {\tt gpuArray}, then obtains a read-only device pointer via {\tt mxGPUGetDataReadOnly}. For GPU output arrays, \mwrap\ creates a new {\tt mxGPUArray} with {\tt mxGPUCreateGPUArray} and obtains a writable device pointer via {\tt mxGPUGetData}. For GPU inout arrays, the input device pointer is reused and the same {\tt mxGPUArray} is returned as output. The {\tt gpu} specifier may be freely combined with ordinary (CPU) arguments in the same function call, allowing mixed host/device interfaces. The {\tt -gpu} flag causes \mwrap\ to emit {\tt \#include } and a call to {\tt mxInitGPU()} in the MEX initialization code. The MEX file must be compiled with MATLAB's GPU-enabled {\tt mex} compiler ({\tt nvmex} or {\tt mex} with CUDA support). The default device specifier is {\tt cpu}, which can be omitted. \section{Example} An event queue stores pairs $(i, t)$ pairs, $i$ is an identifier for some event and $t$ is a time associated with the event. Events can be added to the queue in whatever order, but they are removed in increasing order by time. In this example, we bind to a C++ event queue implementation based on the C++ standard template library priority queue. The example code is in {\tt example/eventq/eventq\_class.mw} and {\tt example/eventq/eventq\_handle.mw}; an alternate version of the code in {\tt example/eventq/eventq\_plain.mw} illustrates a different way of organizing the same interface. The {\tt example/eventq2} subdirectory provides yet another implementation, this one capable of storing arbitrary MATLAB arrays rather than just integers. \subsection{Event queue using old MATLAB OO} We begin by defining an event as a pair (double, int), and an event queue as an STL priority queue of such pairs, sorted in descending order: \begin{verbatim} $ #include $ $ typedef std::pair Event; $ typedef std::priority_queue< Event, $ std::vector, $ std::greater > EventQueue; \end{verbatim} Now we specify the code to wrap the individual methods. For this example, we will take advantage of the object oriented features in MATLAB, and map the methods of the C++ event queue class onto methods of a MATLAB wrapper class called {\tt eventq}. We begin with bindings for the constructor and destructor. We will compile the MATLAB functions for the interface using the {\tt -mb} flag, so that we can specify these functions (and all the others) in the same file: \begin{verbatim} @ @eventq/eventq.m ------------------------------------- function [qobj] = eventq(); qobj = []; # EventQueue* q = new EventQueue(); qobj.q = q; qobj = class(qobj, 'eventq'); @ @eventq/destroy.m ------------------------------------- function destroy(qobj); q = qobj.q; # delete(EventQueue* q); \end{verbatim} The {\tt empty} method returns a {\tt bool}, but \mwrap\ does not know about {\tt bool} variables. A {\tt bool} result can be saved as an integer, though, so we will simply do that: \begin{verbatim} @ @eventq/empty.m ------------------------------------- function [e] = empty(qobj) q = qobj.q; # int e = q->EventQueue.empty(); \end{verbatim} Because {\tt pop\_event} needs to return two values (the event identifier and the time), we use reference arguments to pass out the information. \begin{verbatim} @ @eventq/pop_event.m ------------------------------------- function [id, t] = pop_event(qobj) $ void pop_event(EventQueue* q, int& id, double& t) { $ t = q->top().first; $ id = q->top().second; $ q->pop(); $ } $ q = qobj.q; # pop_event(EventQueue* q, output int& id, output double& t); \end{verbatim} In MATLAB, it may make sense to simultaneously push several events. However, our event queue class only provides basic interfaces to push one event at a time. We could write a MATLAB loop to add events to the queue one at a time, but for illustrating how to use \mwrap, it is better to write the loop in C: \begin{verbatim} @ @eventq/push_event.m ------------------------------------- function push_event(qobj, id, t) $ void push_events(EventQueue* q, int* id, double* t, int m) $ { $ for (int i = 0; i < m; ++i) $ q->push(Event(t[i], id[i])); $ } $ q = qobj.q; m = length(id); # push_events(EventQueue* q, int[m] id, double[m] t, int m); \end{verbatim} \subsection{Event queue using new MATLAB OO} Starting with MATLAB 7.6 (release 2008A), MATLAB supports a new single-file OO programming style. Particularly convenient for writing wrappers is the {\em handle} class system, which allows the user to define destructors that are called automatically when an instance is destroyed by the system (because all references to the instance have gone out of scope). As a programming convenience, \mwrap\ automatically interprets a class with the property {\tt mwptr} as a container for an \mwrap\ object\footnote{This functionality is only enabled when {\tt -DR2008OO} is specified as an argument on the MEX command line. This restriction is in place so that the files generated by \mwrap\ can remain compatible with Octave and with older versions of MATLAB.}. For example, the following file provides an alternate implementation of the event queue class described in the previous section. \begin{verbatim} $ #include $ $ typedef std::pair Event; $ typedef std::priority_queue< Event, $ std::vector, $ std::greater > EventQueue; @ eventqh.m ---------------------------------------------- classdef eventqh < handle properties mwptr end methods function [qobj] = eventqh(obj) # EventQueue* q = new EventQueue(); qobj.mwptr = q; end function delete(q) #delete(EventQueue* q); end function e = empty(q) # int e = q->EventQueue.empty(); end function [id, t] = pop(q) $ void pop_event(EventQueue* q, int& id, double& t) { $ t = q->top().first; $ id = q->top().second; $ q->pop(); $ } # pop_event(EventQueue* q, output int& id, output double& t); end function push(q, id, t) $ void push_events(EventQueue* q, int* id, double* t, int m) $ { $ for (int i = 0; i < m; ++i) $ q->push(Event(t[i], id[i])); $ } m = length(id); # push_events(EventQueue* q, int[m] id, double[m] t, int m); end end end \end{verbatim} This implementation of the event queue class allows for automatic cleanup: \begin{verbatim} q = eventqh(); % Construct a new queue clear q; % The C++ object gets correctly deleted here \end{verbatim} {\bf Warning}: When using MATLAB handle classes for automatic cleanup, be sure to avoid situations where multiple MATLAB handle objects have been given responsible for deleting a single C/C++ object. If you need to have more than one MATLAB handle for a single C/C++ object, I recommend using a reference counted pointer class as an intermediate\footnote{ For more information on reference counted pointer classes, I recommend reading {\em More Effective C++} by Scott Meyers. }. \section{FORTRAN bindings} It is possible to use \mwrap\ to bind FORTRAN functions (though the generated MEX file is still a C/C++ file). FORTRAN bindings can be specified using the {\tt FORTRAN} keyword immediately before a function name; for example: \begin{verbatim} # double sum = FORTRAN dasum(int n, double[n] x, int 1); \end{verbatim} FORTRAN parameters are treated differently from C parameters in the following ways: \begin{enumerate} \item \mwrap\ does not allow objects to be passed into FORTRAN functions. \item Scalar and reference arguments are automatically converted to pointer arguments from the C side to match FORTRAN call-by-reference semantics. \item A warning is generated when passing C strings into FORTRAN. The generated code will work with compilers that produce f2c-compatible code (including g77/g95), but it will not work with all FORTRAN compilers. \item Only simple numeric values can be returned from FORTRAN. A warning is generated when returning complex values, as different FORTRAN compilers follow different protocols when returning complex numbers. The generated code for complex return types will work with some f2c-compatible compilers, but by no means all. \end{enumerate} Internally, \mwrap\ defines macros for different FORTRAN name-mangling conventions, and it declares appropriate prototypes (and protects them from C++ compiler name mangling). By default, \mwrap\ assumes that the f2c name mangling convention is being used (this convention is followed by Sun FORTRAN, g77, and g95); however, the following flags can be passed to the {\tt mex} script to change this behavior: \begin{itemize} \item {\tt -DMWF77\_CAPS} -- Assume the FORTRAN compiler uses all-caps names and no extra underscores. Used by Compaq FORTRAN, and Intel fortran compiler on windows (I think). \item {\tt -DMWF77\_UNDERSCORE1} -- Append a single underscore to an all-lower-case name. Used by the GNU FORTRAN compiler and the Intel fortran compiler on UNIX systems (I think). \item {\tt -DMWF77\_UNDERSCORE0} -- Append no underscore to an all-lower-case name. Used by the GNU fortran with the -fno-underscoring flag \end{itemize} It is possible to use the {\tt typedef numeric} construct to introduce new types corresponding to FORTRAN data types. For example, if the header file {\tt f2c.h} is available (and the types defined therein are appropriate for the compiler) we might have \begin{verbatim} % Use the f2c integer type... $ #include "f2c.h" # typedef numeric integer; # double sum = FORTRAN dasum(integer n, double[n] x, integer 1); \end{verbatim} No attempt is made to automatically produce these type maps, though. \section{Logging} For profiling and coverage testing, it is sometimes useful to track the number of calls that are made through \mwrap. If {\tt mymex} is the name of the generated MEX file, then we can access profile information as follows: \begin{verbatim} % Enable profiler mymex('*profile on*'); % Run some tests here... % Print to screen and to a log file mymex('*profile report*'); mymex('*profile log*', 'log.txt'); % Disable profiler mymex('*profile off*'); \end{verbatim} The MEX file will be locked in memory as long as profiling is active. \end{document} zgimbutas-mwrap-25008ce/example/000077500000000000000000000000001515063637600166425ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/CMakeLists.txt000066400000000000000000000255511515063637600214120ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.16) include(${CMAKE_SOURCE_DIR}/cmake/MwrapAddMex.cmake) add_custom_target(mwrap_examples) set(example_source_dir "${CMAKE_CURRENT_SOURCE_DIR}") set(_mwrap_example_targets foobar eventq_plain eventq_handle eventq_class eventq2 zlib fem_interface ) set(fem_interface_support_sources "${example_source_dir}/fem/src/assembler.cc" "${example_source_dir}/fem/src/gauss2by2.cc" "${example_source_dir}/fem/src/mesh.cc" "${example_source_dir}/fem/src/quad2d1.cc" "${example_source_dir}/fem/src/scalar1d.cc" "${example_source_dir}/fem/src/scalar2d.cc" "${example_source_dir}/fem/src/elastic2d1.cc" ) mwrap_add_mex(foobar MEX_NAME fbmex CC_FILENAME fbmex.cc M_FILENAME foobar.m MW_FILES "${example_source_dir}/foobar/foobar.mw" ) mwrap_add_mex(eventq_plain MEX_NAME eventqpmex CC_FILENAME eventqpmex.cc MW_FILES "${example_source_dir}/eventq/eventq_plain.mw" MWRAP_FLAGS -mb ) mwrap_add_mex(eventq_handle MEX_NAME eventqhmex CC_FILENAME eventqhmex.cc MW_FILES "${example_source_dir}/eventq/eventq_handle.mw" MWRAP_FLAGS -mb COMPILE_DEFINITIONS R2008OO ) mwrap_add_mex(eventq_class MEX_NAME eventqcmex CC_FILENAME eventqcmex.cc MW_FILES "${example_source_dir}/eventq/eventq_class.mw" MWRAP_FLAGS -mb CLASSDEF_NAME eventq ) mwrap_add_mex(eventq2 MEX_NAME eventq2mex CC_FILENAME eventq2mex.cc MW_FILES "${example_source_dir}/eventq2/eventq2.mw" MWRAP_FLAGS -mb ) mwrap_add_mex(zlib MEX_NAME gzmex CC_FILENAME gzmex.cc MW_FILES "${example_source_dir}/zlib/gzfile.mw" MWRAP_FLAGS -mb ) mwrap_add_mex(fem_interface MEX_NAME femex CC_FILENAME femex.cc MW_FILES "${example_source_dir}/fem/interface/assembler.mw" "${example_source_dir}/fem/interface/mesh.mw" "${example_source_dir}/fem/interface/elements.mw" MWRAP_FLAGS -mb EXTRA_SOURCES ${fem_interface_support_sources} INCLUDE_DIRECTORIES "${example_source_dir}/fem/src" ) foreach(example_target IN LISTS _mwrap_example_targets) add_dependencies(mwrap_examples ${example_target}) endforeach() if(MWRAP_COMPILE_MEX AND MWRAP_MEX_BACKENDS) foreach(example_target IN LISTS _mwrap_example_targets) _mwrap_compile_mex(${example_target} OUTPUT_VAR _mwrap_mex_targets) get_target_property(_mex_output_dir ${example_target} MWRAP_OUTPUT_DIRECTORY) get_target_property(_mex_target_list ${example_target} MWRAP_OUTPUT_MEX_TARGETS) get_target_property(_mex_path_list ${example_target} MWRAP_OUTPUT_MEX_PATHS) if(NOT _mex_target_list OR _mex_target_list STREQUAL "NOTFOUND") continue() endif() if(NOT _mex_path_list OR _mex_path_list STREQUAL "NOTFOUND") set(_mex_path_list) endif() list(LENGTH _mex_target_list _mex_target_count) list(LENGTH _mex_path_list _mex_path_count) if(NOT _mex_target_count EQUAL _mex_path_count) message(FATAL_ERROR "Mismatch between recorded MEX targets and paths for ${example_target}") endif() math(EXPR _mex_index "0") foreach(_mex_target IN LISTS _mex_target_list) list(GET _mex_path_list ${_mex_index} _mex_path) add_dependencies(mwrap_examples ${_mex_target}) if(_mex_output_dir AND NOT _mex_output_dir STREQUAL "NOTFOUND") set(_mex_should_copy TRUE) if(_mex_path MATCHES "\\$") set(_mex_dest_path "${_mex_output_dir}/${_mex_dest_name}") else() set(_mex_source_path "${_mex_path}") if(NOT IS_ABSOLUTE "${_mex_source_path}") get_filename_component(_mex_source_path "${_mex_source_path}" ABSOLUTE) endif() get_filename_component(_mex_dest_name "${_mex_path}" NAME) set(_mex_dest_path "${_mex_output_dir}/${_mex_dest_name}") if(NOT IS_ABSOLUTE "${_mex_dest_path}") get_filename_component(_mex_dest_path "${_mex_dest_path}" ABSOLUTE) endif() if(_mex_source_path STREQUAL _mex_dest_path) set(_mex_should_copy FALSE) endif() endif() if(_mex_should_copy) add_custom_command(TARGET ${_mex_target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${_mex_output_dir}" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_mex_source_path}" "${_mex_dest_path}" ) endif() endif() math(EXPR _mex_index "${_mex_index} + 1") endforeach() endforeach() endif() if(BUILD_TESTING AND MWRAP_COMPILE_MEX) if(MWRAP_MEX_BACKENDS) list(FIND MWRAP_MEX_BACKENDS "OCTAVE" _mwrap_octave_index) list(FIND MWRAP_MEX_BACKENDS "MATLAB" _mwrap_matlab_index) else() set(_mwrap_octave_index -1) set(_mwrap_matlab_index -1) endif() function(_mwrap_prepare_smoke_test_runner target_name runner_var workdir_var script_basename_var runner_escape_var) set(options) set(oneValueArgs SCRIPT WORKSPACE) set(multiValueArgs EXTRA_PATHS) cmake_parse_arguments(MTEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT TARGET ${target_name}) message(FATAL_ERROR "Unknown target '${target_name}' requested for smoke test") endif() if(NOT MTEST_SCRIPT) message(FATAL_ERROR "SCRIPT must be provided for smoke test on target '${target_name}'") endif() get_target_property(wrapper_dir ${target_name} MWRAP_OUTPUT_DIRECTORY) if(NOT wrapper_dir OR wrapper_dir STREQUAL "NOTFOUND") message(FATAL_ERROR "Target '${target_name}' is missing wrapper directory metadata") endif() get_target_property(classdef_dir ${target_name} MWRAP_OUTPUT_CLASSDEF_DIR) if(NOT classdef_dir OR classdef_dir STREQUAL "NOTFOUND") unset(classdef_dir) endif() set(test_paths ${MTEST_EXTRA_PATHS} "${wrapper_dir}") if(classdef_dir) list(APPEND test_paths "${classdef_dir}") endif() list(REMOVE_DUPLICATES test_paths) set(path_commands "") foreach(test_path IN LISTS test_paths) if(test_path) file(TO_CMAKE_PATH "${test_path}" test_path_cmake) string(REPLACE "'" "''" test_path_escaped "${test_path_cmake}") string(APPEND path_commands "addpath('${test_path_escaped}');\n") endif() endforeach() if(path_commands STREQUAL "") set(path_commands "% No additional paths required\n") endif() if(MTEST_WORKSPACE) set(work_dir "${MTEST_WORKSPACE}") file(MAKE_DIRECTORY "${work_dir}") file(TO_CMAKE_PATH "${work_dir}" work_dir_cmake) string(REPLACE "'" "''" work_dir_escaped "${work_dir_cmake}") set(work_dir_command "cd('${work_dir_escaped}');\n") else() set(work_dir "${CMAKE_CURRENT_BINARY_DIR}") set(work_dir_command "% No staging directory requested\n") file(TO_CMAKE_PATH "${work_dir}" work_dir_cmake) endif() get_filename_component(script_basename "${MTEST_SCRIPT}" NAME_WE) set(runner_file "${CMAKE_CURRENT_BINARY_DIR}/${script_basename}_runner.m") file(TO_CMAKE_PATH "${MTEST_SCRIPT}" script_path_cmake) string(REPLACE "'" "''" script_path_escaped "${script_path_cmake}") set(PATHS "${path_commands}") set(WORK_DIR "${work_dir_command}") set(CALL "${script_path_escaped}") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/run_example.m.in" "${runner_file}" @ONLY ) unset(PATHS) unset(WORK_DIR) unset(CALL) file(TO_CMAKE_PATH "${runner_file}" runner_path_cmake) string(REPLACE "'" "''" runner_path_escaped "${runner_path_cmake}") set(${runner_var} "${runner_file}" PARENT_SCOPE) set(${workdir_var} "${work_dir}" PARENT_SCOPE) set(${script_basename_var} "${script_basename}" PARENT_SCOPE) set(${runner_escape_var} "${runner_path_escaped}" PARENT_SCOPE) endfunction() set(_mwrap_enable_octave_tests FALSE) if(_mwrap_octave_index GREATER -1 AND DEFINED MWRAP_OCTAVE_EXECUTABLE AND MWRAP_OCTAVE_EXECUTABLE) set(_mwrap_enable_octave_tests TRUE) function(_mwrap_add_octave_smoke_test target_name) _mwrap_prepare_smoke_test_runner(${target_name} runner_file work_dir script_basename runner_path_escaped ${ARGN}) set(test_name "octave-${script_basename}") add_test( NAME ${test_name} COMMAND ${MWRAP_OCTAVE_EXECUTABLE} --no-gui --quiet --eval "run('${runner_path_escaped}')" WORKING_DIRECTORY "${work_dir}" ) endfunction() endif() set(_mwrap_enable_matlab_tests FALSE) if(_mwrap_matlab_index GREATER -1 AND DEFINED Matlab_MAIN_PROGRAM AND Matlab_MAIN_PROGRAM) set(_mwrap_enable_matlab_tests TRUE) function(_mwrap_add_matlab_smoke_test target_name) _mwrap_prepare_smoke_test_runner(${target_name} runner_file work_dir script_basename runner_path_escaped ${ARGN}) set(test_name "matlab-${script_basename}") add_test( NAME ${test_name} COMMAND "${Matlab_MAIN_PROGRAM}" -batch "run('${runner_path_escaped}')" WORKING_DIRECTORY "${work_dir}" ) endfunction() endif() if(_mwrap_enable_octave_tests OR _mwrap_enable_matlab_tests) set(fem_workspace "${CMAKE_CURRENT_BINARY_DIR}/fem_workspace") file(MAKE_DIRECTORY "${fem_workspace}/mwfem") macro(_mwrap_register_example_smoke_tests add_func) cmake_language(CALL "${add_func}" eventq_plain SCRIPT "${example_source_dir}/eventq/testq_plain.m" EXTRA_PATHS "${example_source_dir}/eventq" ) cmake_language(CALL "${add_func}" eventq_handle SCRIPT "${example_source_dir}/eventq/testq_handle.m" EXTRA_PATHS "${example_source_dir}/eventq" ) cmake_language(CALL "${add_func}" eventq_class SCRIPT "${example_source_dir}/eventq/testq_class.m" EXTRA_PATHS "${example_source_dir}/eventq" ) cmake_language(CALL "${add_func}" eventq2 SCRIPT "${example_source_dir}/eventq2/testq2.m" EXTRA_PATHS "${example_source_dir}/eventq2" ) cmake_language(CALL "${add_func}" zlib SCRIPT "${example_source_dir}/zlib/testgz.m" EXTRA_PATHS "${example_source_dir}/zlib" ) cmake_language(CALL "${add_func}" fem_interface SCRIPT "${example_source_dir}/fem/test_simple.m" WORKSPACE "${fem_workspace}" EXTRA_PATHS "${example_source_dir}/fem" "${fem_workspace}/mwfem" ) cmake_language(CALL "${add_func}" fem_interface SCRIPT "${example_source_dir}/fem/test_patch.m" WORKSPACE "${fem_workspace}" EXTRA_PATHS "${example_source_dir}/fem" "${fem_workspace}/mwfem" ) cmake_language(CALL "${add_func}" fem_interface SCRIPT "${example_source_dir}/fem/test_assembler.m" WORKSPACE "${fem_workspace}" EXTRA_PATHS "${example_source_dir}/fem" "${fem_workspace}/mwfem" ) endmacro() endif() if(_mwrap_enable_octave_tests) _mwrap_register_example_smoke_tests(_mwrap_add_octave_smoke_test) endif() if(_mwrap_enable_matlab_tests) _mwrap_register_example_smoke_tests(_mwrap_add_matlab_smoke_test) endif() endif() zgimbutas-mwrap-25008ce/example/Makefile000066400000000000000000000003411515063637600203000ustar00rootroot00000000000000all: (cd foobar; make) (cd eventq; make) (cd eventq2; make) (cd zlib; make) (cd fem; make) clean: (cd foobar; make clean) (cd eventq; make clean) (cd eventq2; make clean) (cd zlib; make clean) (cd fem; make clean) zgimbutas-mwrap-25008ce/example/eventq/000077500000000000000000000000001515063637600201445ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/eventq/Makefile000066400000000000000000000007061515063637600216070ustar00rootroot00000000000000include ../../make.inc MW=../../mwrap all: pmex cmex hmex pmex: $(MW) -mex eventqpmex -c eventqpmex.cc -mb eventq_plain.mw $(MEX) eventqpmex.cc hmex: $(MW) -mex eventqhmex -c eventqhmex.cc -mb eventq_handle.mw $(MEX) eventqhmex.cc cmex: mkdir -p \@eventq $(MW) -mex eventqcmex -c eventqcmex.cc -mb eventq_class.mw $(MEX) eventqcmex.cc clean: rm -rf \@eventq/ rm -f EventQ_*.m eventqh.m rm -f eventqcmex.* eventqpmex.* eventqhmex.* *.o *~ zgimbutas-mwrap-25008ce/example/eventq/README000066400000000000000000000013621515063637600210260ustar00rootroot00000000000000Example of bindings to encapsulate a C++ class. In this case, we bind the methods for an event queue of (id, time) pairs based on the STL priority queue class. This directory contains two different versions of the example. The "plain" version uses the prefix "EventQ_" to disambiguate references to class methods. For example, "EventQ_empty" would refer to the "empty" method of the event queue class. The "class" version uses the object-oriented features in MATLAB to wrap the C++ class in a MATLAB class, so that the "empty" method in C++ can be mapped to the "empty" method in MATLAB without fear of conflict with any other methods of the same name. Because Octave does not support MATLAB-style OO, this latter version does not work with Octave. zgimbutas-mwrap-25008ce/example/eventq/eventq_class.mw000066400000000000000000000027561515063637600232120ustar00rootroot00000000000000% eventq_class.mw % Simple event queue for use in MATLAB event-driven simulations. % Uses the MATLAB OO system for encapsulating the event queue. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $ #include $ $ typedef std::pair Event; $ typedef std::priority_queue< Event, $ std::vector, $ std::greater > EventQueue; @ @eventq/eventq.m ------------------------------------- function [qobj] = eventq(); qobj = []; # EventQueue* q = new EventQueue(); qobj.q = q; qobj = class(qobj, 'eventq'); @ @eventq/destroy.m ------------------------------------- function destroy(qobj); q = qobj.q; # delete(EventQueue* q); @ @eventq/empty.m ------------------------------------- function [e] = empty(qobj) q = qobj.q; # int e = q->EventQueue.empty(); @ @eventq/pop.m ------------------------------------- function [id, t] = pop(qobj) $ void pop_event(EventQueue* q, int& id, double& t) { $ t = q->top().first; $ id = q->top().second; $ q->pop(); $ } $ q = qobj.q; # pop_event(EventQueue* q, output int& id, output double& t); @ @eventq/push.m ------------------------------------- function push(qobj, id, t) $ void push_events(EventQueue* q, int* id, double* t, int m) $ { $ for (int i = 0; i < m; ++i) $ q->push(Event(t[i], id[i])); $ } $ q = qobj.q; m = length(id); # push_events(EventQueue* q, int[m] id, double[m] t, int m); zgimbutas-mwrap-25008ce/example/eventq/eventq_handle.mw000066400000000000000000000026201515063637600233260ustar00rootroot00000000000000% eventq_handle.mw % Simple event queue for use in MATLAB event-driven simulations. % Uses the MATLAB 2008+ OO system for encapsulating the event queue. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $ #include $ $ typedef std::pair Event; $ typedef std::priority_queue< Event, $ std::vector, $ std::greater > EventQueue; @ eventqh.m -------------------------------------------- classdef eventqh < handle properties mwptr end methods function [qobj] = eventqh() # EventQueue* q = new EventQueue(); qobj.mwptr = q; end function delete(q) #delete(EventQueue* q); end function e = empty(q) # int e = q->EventQueue.empty(); end function [id, t] = pop(q) $ void pop_event(EventQueue* q, int& id, double& t) { $ t = q->top().first; $ id = q->top().second; $ q->pop(); $ } # pop_event(EventQueue* q, output int& id, output double& t); end function push(q, id, t) $ void push_events(EventQueue* q, int* id, double* t, int m) $ { $ for (int i = 0; i < m; ++i) $ q->push(Event(t[i], id[i])); $ } m = length(id); # push_events(EventQueue* q, int[m] id, double[m] t, int m); end end end zgimbutas-mwrap-25008ce/example/eventq/eventq_plain.mw000066400000000000000000000020671515063637600232030ustar00rootroot00000000000000% eventq_plain.mw % Simple event queue for use in MATLAB event-driven simulations. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $[ #include typedef std::pair Event; typedef std::priority_queue< Event, std::vector, std::greater > EventQueue; $] @function [q] = EventQ_new(); # EventQueue* q = new EventQueue(); @function EventQ_destroy(q); # delete(EventQueue* q); @function [e] = EventQ_empty(q) # int e = q->EventQueue.empty(); @function [id, t] = EventQ_pop(q) $ void pop_event(EventQueue* q, int& id, double& t) { $ t = q->top().first; $ id = q->top().second; $ q->pop(); $ } $ # pop_event(EventQueue* q, output int& id, output double& t); @function EventQ_push(q, id, t) $ void push_events(EventQueue* q, int* id, double* t, int m) $ { $ for (int i = 0; i < m; ++i) $ q->push(Event(t[i], id[i])); $ } $ m = length(id); # push_events(EventQueue* q, int[m] id, double[m] t, int m); zgimbutas-mwrap-25008ce/example/eventq/testq_class.m000066400000000000000000000006671515063637600226600ustar00rootroot00000000000000% testq_class.m % Test case / demo of MWrap bindings to a C++ event queue class. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions if ~exist('isobject') fprintf('MATLAB object system not supported\n'); return; end q = eventq(); push(q, 1, 1.5); push(q, 2, 0.4); push(q, 3, 10); push(q, [4, 5], [8, 11]); while ~empty(q) [id,t] = pop(q); fprintf('Time %g: Saw %d\n', t, id); end destroy(q); zgimbutas-mwrap-25008ce/example/eventq/testq_handle.m000066400000000000000000000007111515063637600227740ustar00rootroot00000000000000% testq_class.m % Test case / demo of MWrap bindings to a C++ event queue class. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions if ~exist('ishandle') | ~exist('isobject') fprintf('MATLAB object system not supported\n'); return; end q = eventqh(); push(q, 1, 1.5); push(q, 2, 0.4); push(q, 3, 10); push(q, [4, 5], [8, 11]); while ~empty(q) [id,t] = pop(q); fprintf('Time %g: Saw %d\n', t, id); end clear q zgimbutas-mwrap-25008ce/example/eventq/testq_plain.m000066400000000000000000000006241515063637600226470ustar00rootroot00000000000000% testq_plain.m % Test case / demo of MWrap bindings to a C++ event queue class. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions q = EventQ_new(); EventQ_push(q, 1, 1.5); EventQ_push(q, 2, 0.4); EventQ_push(q, 3, 10); EventQ_push(q, [4, 5], [8, 11]); while ~EventQ_empty(q) [id,t] = EventQ_pop(q); fprintf('Time %g: Saw %d\n', t, id); end EventQ_destroy(q); zgimbutas-mwrap-25008ce/example/eventq2/000077500000000000000000000000001515063637600202265ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/eventq2/Makefile000066400000000000000000000002571515063637600216720ustar00rootroot00000000000000include ../../make.inc MW=../../mwrap mex: $(MW) -mex eventq2mex -c eventq2mex.cc -mb eventq2.mw $(MEX) eventq2mex.cc clean: rm -f EventQ_*.m rm -f eventq2mex.* *.o *~ zgimbutas-mwrap-25008ce/example/eventq2/README000066400000000000000000000004631515063637600211110ustar00rootroot00000000000000Example of bindings using the mxArray wrapper. In this case, we wrap an STL priority queue of (mxArray, time) pairs. This is a variant of the event queue example in the example/eventq subdirectory, except in this version we can store arbitrary MATLAB data objects in the queue, rather than just integers. zgimbutas-mwrap-25008ce/example/eventq2/eventq2.mw000066400000000000000000000023531515063637600221620ustar00rootroot00000000000000% eventq_plain.mw % Simple event queue for use in MATLAB event-driven simulations. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $[ #include #include typedef std::pair Event; typedef std::priority_queue< Event, std::vector, std::greater > EventQueue; $] // ---- @function [q] = EventQ_new(); # EventQueue* q = new EventQueue(); // ---- @function EventQ_destroy(q); while ~EventQ_empty(q) EventQ_pop(q) end # delete(EventQueue* q); // ---- @function [e] = EventQ_empty(q) # int e = q->EventQueue.empty(); // ---- @function [data, t] = EventQ_pop(q) $[ mxArray* pop_event(EventQueue* q, double& t) { t = q->top().first; mxArray* data = mxDuplicateArray(q->top().second); mxDestroyArray(q->top().second); q->pop(); return data; } $] # mxArray data = pop_event(EventQueue* q, output double& t); // ---- @function EventQ_push(q, data, t) $[ void push_event(EventQueue* q, const mxArray* a, double t) { mxArray* data = mxDuplicateArray(a); mexMakeArrayPersistent(data); q->push(Event(t, data)); } $] # push_event(EventQueue* q, mxArray data, double t); zgimbutas-mwrap-25008ce/example/eventq2/testq2.m000066400000000000000000000006501515063637600216270ustar00rootroot00000000000000% testq_plain.m % Test case / demo of MWrap bindings to a C++ event queue class. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions q = EventQ_new(); EventQ_push(q, 1, 1.5); EventQ_push(q, 2, 0.4); EventQ_push(q, 3, 10); EventQ_push(q, 'Mary had a little lamb', 8); while ~EventQ_empty(q) [data,t] = EventQ_pop(q); fprintf('Time %g: Saw ', t); disp(data); end EventQ_destroy(q); zgimbutas-mwrap-25008ce/example/fem/000077500000000000000000000000001515063637600174115ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/fem/Makefile000066400000000000000000000002571515063637600210550ustar00rootroot00000000000000all: mkdir -p mwfem (cd src; make) (cd interface; make) clean: (cd src; make clean) (cd interface; make clean) rm -rf mwfem realclean: clean (cd src; make realclean) zgimbutas-mwrap-25008ce/example/fem/README000066400000000000000000000007071515063637600202750ustar00rootroot00000000000000This example illustrates several features of MWrap: - The binding to the finite element assembly class uses mxArrays directly (for sparse matrices). - The binding to element types uses inheritance. - The bindings to the mesh methods illustrate using zero-based to one-based construction. The finite element source files are in src; the MWrap input files are in interface. The MEX file and generated .m files build into the mwfem subdirectory. zgimbutas-mwrap-25008ce/example/fem/init.m000066400000000000000000000000621515063637600205300ustar00rootroot00000000000000if ~exist('femex'), addpath([pwd, '/mwfem']); end zgimbutas-mwrap-25008ce/example/fem/interface/000077500000000000000000000000001515063637600213515ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/fem/interface/Makefile000066400000000000000000000003301515063637600230050ustar00rootroot00000000000000include ../../../make.inc MW=../../../mwrap mex: wrap $(MEX) -I../src femex.cc ../src/*.o mv femex.* *.m ../mwfem wrap: $(MW) -mex femex -c femex.cc \ -mb assembler.mw mesh.mw elements.mw clean: rm -f *~ zgimbutas-mwrap-25008ce/example/fem/interface/assembler.mw000066400000000000000000000041521515063637600236750ustar00rootroot00000000000000% assembler.mw % MWrap bindings for MatrixAssembler (CSC matrix assembly). % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $[ #include "assembler.h" #include #include mxArray* export_matrix(MatrixAssembler* matrix) { matrix->compress(); int m = matrix->get_m(); int n = matrix->get_n(); int nnz = matrix->csc_nnz(); mxArray* result = mxCreateSparse(m, n, nnz, mxREAL); std::copy(matrix->get_jc(), matrix->get_jc()+n+1, mxGetJc(result)); std::copy(matrix->get_ir(), matrix->get_ir()+nnz, mxGetIr(result)); std::copy(matrix->get_pr(), matrix->get_pr()+nnz, mxGetPr(result)); return result; } $] @function aobj = Assembler_create(m, n, nnz) % aobj = Assembler_create(m, n) % % Create an assembly object for m-by-n matrices. if nargin < 2, m = n; end if nargin < 3 # MatrixAssembler* aobj = new MatrixAssembler(int m, int n); else # MatrixAssembler* aobj = new MatrixAssembler(int m, int n, int nnz); end @function Assembler_delete(aobj) % Assembler_delete(aobj) % % Delete a matrix assembler object # delete(MatrixAssembler* aobj); @function Assembler_add(aobj, ii, jj, Aelt) % Assembler_create(aobj, ii, jj, Aelt) % % Perform A(ii,jj) += Aelt. [m,n] = size(Aelt); ii = ii-1; jj = jj-1; # aobj->MatrixAssembler.add_entry(int[m] ii, int[n] jj, double[m,n] Aelt, # int m, int n); @function K = Assembler_get(aobj) % K = Assembler_get(aobj) % % Retrieve a sparse matrix from a matrix assembler. # mxArray K = export_matrix(MatrixAssembler* aobj); @function Assembler_clear(aobj) % Assembler_clear(aobj) % % Clear the matrix assembler in preparation for building a new matrix. # aobj->MatrixAssembler.wipe(); @function [structure_nnz, cached_nnz] = Assembler_stats(aobj) % [structure_nnz, cached_nnz] = Assembler_stats(aobj) % % Get statistics about the nonzeros in the assembler. # int structure_nnz = aobj->MatrixAssembler.csc_nnz(); # int cached_nnz = aobj->MatrixAssembler.cache_nnz(); if nargout == 0 fprintf('NNZ in structure: %d\n', structure_nnz); fprintf('NNZ in cache: %d\n', cached_nnz); end zgimbutas-mwrap-25008ce/example/fem/interface/elements.mw000066400000000000000000000020271515063637600235330ustar00rootroot00000000000000% elements.mw % MWrap bindings for element types. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $[ #include "mesh.h" #include "scalar1d.h" #include "scalar2d.h" #include "elastic2d.h" $] # class Scalar1D : EType; # class Scalar2D : EType; # class Elastic2D : EType; @function etype = Mesh_add_scalar1d(mobj, k) % material = Mesh_add_scalar1d(mobj, k) % % Add a simple scalar element type to the mesh object. # Scalar1D* etype = new Scalar1D(double k); # mobj->Mesh.add_material(EType* etype); @function etype = Mesh_add_scalar2d(mobj, k) % material = Mesh_add_scalar2d(mobj, k) % % Add a simple scalar element type to the mesh object. # Scalar2D* etype = new Scalar2D(double k); # mobj->Mesh.add_material(EType* etype); @function etype = Mesh_add_elastic2d(mobj, E, nu, which) % material = Mesh_add_elastic2d(mobj, E, nu, which) % % Add a plane strain elastic element type to the mesh. # Elastic2D* etype = new Elastic2D(double E, double nu, cstring which); # mobj->Mesh.add_material(EType* etype); zgimbutas-mwrap-25008ce/example/fem/interface/mesh.mw000066400000000000000000000202511515063637600226520ustar00rootroot00000000000000% mesh.mw % MWrap bindings for Mesh. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $ #include "mesh.h" // ---- @function mobj = Mesh_create(ndm, maxndf, maxnen) % mobj = Mesh_create(ndm, maxndf, maxnen) % % Create a new mesh object. % ndm - Number of spatial dimensions % maxndf - Maximum number of dofs per node % maxnen - Maximum number of elements per node # Mesh* mobj = new Mesh(int ndm, int maxndf, int maxnen); // ---- @function Mesh_delete(mobj) % Mesh_delete(mobj) % % Delete an existing mesh object. # delete(Mesh* mobj); // ---- @function ndm = Mesh_ndm(mobj) % ndm = Mesh_ndm(mobj) % % Get the number of spatial dimensions for the mesh # int ndm = mobj->Mesh.ndm(); // ---- @function maxndf = Mesh_maxndf(mobj) % maxndf = Mesh_maxndf(mobj) % % Get the maximum number of nodal dofs for the mesh # int maxndf = mobj->Mesh.maxndf(); // ---- @function maxnen = Mesh_maxnen(mobj) % maxnen = Mesh_maxnen(mobj) % % Get the maximum number of nodes per element for the mesh # int maxnen = mobj->Mesh.maxnen(); // ---- @function numelt = Mesh_numelt(mobj) % numelt = Mesh_numelt(mobj) % % Get the number of elements in the mesh. # int numelt = mobj->Mesh.numelt(); // ---- @function numnp = Mesh_numnp(mobj) % numnp = Mesh_numnp(mobj) % % Get the number of nodes in the mesh # int numnp = mobj->Mesh.numnp(); // ---- @function numid = Mesh_numid(mobj) % numid = Mesh_numid(mobj) % % Get the number of active dofs in the mesh # int numid = mobj->Mesh.numid(); // ---- @function x = Mesh_x(mobj, i) % Mesh_x(mobj, i) % % Get the coordinates of mesh node i. If the node number is omitted, % get the coordinates for all nodes in the mesh. if nargin == 2 i = i-1; # int ndm = mobj->Mesh.ndm(); # double[ndm] x = mobj->Mesh.x(int i); else # int numnp = mobj->Mesh.numnp(); # int ndm = mobj->Mesh.ndm(); # double[ndm,numnp] x = mobj->Mesh.x(); end // ---- @function ix = Mesh_ix(mobj, i) % Mesh_ix(mobj, i) % % Get the connectivity of element i. If the element number is omitted, % get the connectivity for all elements in the mesh. if nargin == 2 i = i-1; # int maxnen = mobj->Mesh.maxndf(); # int[maxnen] ix = mobj->Mesh.ix(int i); else # int numelt = mobj->Mesh.numelt(); # int maxnen = mobj->Mesh.maxnen(); # int[maxnen,numelt] ix = mobj->Mesh.ix(); end ix = ix+1; // ---- @function id = Mesh_id(mobj, i) % Mesh_id(mobj, i) % % Get the degrees of freedom for element i. If the element number is omitted, % get the degrees of freedom for all elements in the mesh. if nargin == 2 i = i - 1; # int maxndf = mobj->Mesh.maxndf(); # int[maxndf] id = mobj->Mesh.id(int i); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # int[maxndf,numnp] id = mobj->Mesh.id(); end id = id + 1; // ---- @function u = Mesh_u(mobj, i) % Mesh_u(mobj, i) % % Get the displacement of mesh node i. If the node number is omitted, % get the displacements for all nodes in the mesh. if nargin == 2 i = i-1; # int maxndf = mobj->Mesh.maxndf(); # double[maxndf] u = mobj->Mesh.u(int i); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # double[maxndf,numnp] u = mobj->Mesh.u(); end // ---- @function f = Mesh_f(mobj, i) % Mesh_f(mobj, i) % % Get the forces for mesh node i. If the node number is omitted, % get the forces for all nodes in the mesh. if nargin == 2 i = i-1; # int maxndf = mobj->Mesh.maxndf(); # double[maxndf] f = mobj->Mesh.f(int i); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # double[maxndf,numnp] f = mobj->Mesh.f(); end // ---- @function bc = Mesh_bc(mobj, i) % Mesh_bc(mobj, i) % % Get the boundary codes of mesh node i. If the node number is omitted, % get the boundary codes for all nodes in the mesh. if nargin == 2 i = i-1; # int maxndf = mobj->Mesh.maxndf(); # char[maxndf] bc = mobj->Mesh.bc(int i); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # char[maxndf,numnp] bc = mobj->Mesh.bc(); end // ---- @function bv = Mesh_bv(mobj, i) % Mesh_bv(mobj, i) % % Get the boundary values of mesh node i. If the node number is omitted, % get the boundary values for all nodes in the mesh. if nargin == 2 i = i-1; # int maxndf = mobj->Mesh.maxndf(); # double[maxndf] bv = mobj->Mesh.bv(int i); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # double[maxndf,numnp] bv = mobj->Mesh.bv(); end // ---- @function Mesh_set_ur(mobj, ur) % Mesh_set_ur(mobj, ur) % % Set reduced displacement vector numid = Mesh_numid(mobj); # mobj->Mesh.set_ur(input double[numid] ur); // ---- @function ur = Mesh_get_ur(mobj) % ur = Mesh_get_ur(mobj) % % Get reduced displacement vector numid = Mesh_numid(mobj); # mobj->Mesh.get_ur(output double[numid] ur); // ---- @function Mesh_set_bc(mobj, bc, i, j) % Mesh_set_bc(mobj, bc, i, j) % % Set the boundary codes of mesh node i. If the node number is omitted, % set the boundary codes for all nodes in the mesh. $[ void set_bc(Mesh* mesh, char bc, int i, int j) { mesh->bc(i,j) = bc; } void set_bc(Mesh* mesh, char* bc) { int numnp = mesh->numnp(); int maxndf = mesh->maxndf(); for (int j = 0; j < numnp; ++j) for (int i = 0; i < maxndf; ++i) mesh->bc(i,j) = bc[i+j*maxndf]; } $] if nargin == 4 i = i-1; j = j-1; # int maxndf = mobj->Mesh.maxndf(); # set_bc(Mesh* mobj, char bc, int i, int j); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # set_bc(Mesh* mobj, char[maxndf,numnp] bc); end // ---- @function Mesh_set_bv(mobj, bv, i, j) % Mesh_set_bv(mobj, bv, i, j) % % Set the boundary codes of mesh node i. If the node number is omitted, % set the boundary codes for all nodes in the mesh. $[ void set_bv(Mesh* mesh, double bv, int i, int j) { mesh->bv(i,j) = bv; } void set_bv(Mesh* mesh, double* bv) { int numnp = mesh->numnp(); int maxndf = mesh->maxndf(); for (int j = 0; j < numnp; ++j) for (int i = 0; i < maxndf; ++i) mesh->bv(i,j) = bv[i+j*maxndf]; } $] if nargin == 4 i = i-1; j = j-1; # int maxndf = mobj->Mesh.maxndf(); # set_bv(Mesh* mobj, double bv, int i, int j); else # int numnp = mobj->Mesh.numnp(); # int maxndf = mobj->Mesh.maxndf(); # set_bv(Mesh* mobj, double[maxndf,numnp] bv); end // ---- @function numid = Mesh_initialize(mobj) % numid = Mesh_initialize(mobj) % % Initialize the mesh object after completion of X/IX arrays. # int numid = mobj->Mesh.initialize(); // ---- @function numid = Mesh_assign_ids(mobj) % numid = Mesh_assign_ids(mobj) % % Assign identifiers to active degrees of freedom in the mesh. # int numid = mobj->Mesh.assign_ids(); // ---- @function F = Mesh_assemble_F(mobj) % F = Mesh_assemble_F(mobj) % % Assemble system residual force vector. numid = Mesh_numid(mobj); # mobj->Mesh.assemble_F(); # mobj->Mesh.get_fr(output double[numid] F); // ---- @function K = Mesh_assemble_K(mobj) % K = Mesh_assemble_K(mobj) % % Assemble system stiffness matrix. numid = Mesh_numid(mobj); Ka = Assembler_create(numid, numid); # mobj->Mesh.assemble_K(MatrixAssembler* Ka); K = Assembler_get(Ka); Assembler_delete(Ka); // ---- @function id = Mesh_add_node(mobj, x) % id = Mesh_add_node(mobj, x) % % Build a new node at position x and return the index. # int ndm = mobj->Mesh.ndm(); # int id = mobj->Mesh.add_node(double[ndm] x); id = id + 1; // ---- @function id = Mesh_add_element(mobj, etype, nodes) % id = Mesh_add_element(mobj, etype, nodes) % % Build a new element of type etype connected to the indicated nodes, % and return the index. numnp = length(nodes); nodes = nodes-1; # int id = mobj->Mesh.add_element(EType* etype, int[numnp] nodes, int numnp); id = id + 1; // ---- @function Mesh_load(mobj, etype, x, ix) % Mesh_load(mobj, material, x, ix) % % Add a new batch of elements % material - Material type % x - Coordinates of nodes in new elements % ix - Connectivity array for new elements # int ndm = mobj->Mesh.ndm(); ids = zeros(1,size(x,2)); for j = 1:size(x,2) xj = x(:,j); # int id = mobj->Mesh.add_node(double[ndm] xj); ids(j) = id; end numnp = size(ix,1); for j = 1:size(ix,2) ixj = ids(ix(:,j)); # int id = mobj->Mesh.add_element(EType* etype, int[numnp] ixj, int numnp); end zgimbutas-mwrap-25008ce/example/fem/src/000077500000000000000000000000001515063637600202005ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/fem/src/Makefile000066400000000000000000000006761515063637600216510ustar00rootroot00000000000000# Targets for object files (we compile with MEX to avoid headaches # about -fPIC and other flag compatibility issues) include ../../../make.inc OBJS= \ assembler.o mesh.o \ gauss2by2.o quad2d1.o \ scalar1d.o scalar2d.o elastic2d1.o all: $(OBJS) .cc.o: $(MEX) -c $*.cc elastic2d1.cc: matexpr elastic2d.cc > elastic2d1.cc quad2d1.cc: matexpr quad2d.cc > quad2d1.cc clean: rm -f *.o *~ realclean: rm -f *.o elastic2d1.cc quad2d1.cc zgimbutas-mwrap-25008ce/example/fem/src/assembler.cc000066400000000000000000000060071515063637600224670ustar00rootroot00000000000000/* * assembler.cc * Compressed sparse column matrix assembler implementation. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "assembler.h" #include #include #define ME MatrixAssembler using std::sort; using std::fill; /* * Add A(i,j) += Aij. If there's space in the existing compressed * sparse column data structure, add it there; otherwise, stash it in * the coords cache vector. */ void ME::add_entry(int i, int j, double Aij) { if (i < 0 || i >= m || j < 0 || j >= n) return; for (int ii = jc[j]; ii < jc[j+1]; ++ii) { if (ir[ii] == i) { pr[ii] += Aij; return; } } coords.push_back(Coord(i,j,Aij)); } /* * Add an element submatrix. */ void ME::add_entry(const int* i, const int* j, double* Aij, int m_elt, int n_elt) { for (int jj = 0; jj < n_elt; ++jj) for (int ii = 0; ii < m_elt; ++ii) add_entry(i[ii], j[jj], Aij[jj*m_elt+ii]); } /* * Wipe the input matrix. Note that the compressed sparse column index * structure remains intact, so we can re-assemble without doing too much * work. */ void ME::wipe() { coords.resize(0); fill(get_pr(), get_pr()+jc[n], 0); } /* * Sort the entries in the coords cache, and merge (by summing) contributions * to the same position. */ void ME::pack_cache() { if (coords.size() > 0) { sort(coords.begin(), coords.end()); int i_merge = 0; for (int i_coord = 1; i_coord < coords.size(); ++i_coord) { if (coords[i_merge] < coords[i_coord]) coords[++i_merge] = coords[i_coord]; else coords[i_merge].Aij += coords[i_coord].Aij; } coords.resize(i_merge+1); } } /* * Pack the coordinate cache, then merge sort the contents of the compressed * sparse column data structure with the contents of the entry cache. */ void ME::compress() { pack_cache(); ir.resize(ir.size() + coords.size()); pr.resize(pr.size() + coords.size()); int i_coord = coords.size()-1; // Next input coord to process int i_csc = jc[n]-1; // Next input CSC entry to process int i_merge = pr.size()-1; // Next output CSC entry to process jc[n] = pr.size(); for (int j = n; j > 0; --j) { // Merge column from cache with column from previous CSC while (i_coord >= 0 && coords[i_coord].j == j-1 && i_csc >= 0 && i_csc >= jc[j-1]) { if (coords[i_coord].i > ir[i_csc]) { ir[i_merge] = coords[i_coord].i; pr[i_merge] = coords[i_coord].Aij; --i_coord; } else { ir[i_merge] = ir[i_csc]; pr[i_merge] = pr[i_csc]; --i_csc; } --i_merge; } // Copy stragglers from coord list while (i_coord >= 0 && coords[i_coord].j == j-1) { ir[i_merge] = coords[i_coord].i; pr[i_merge] = coords[i_coord].Aij; --i_coord; --i_merge; } // Copy stragglers from CSC list while (i_csc >= 0 && i_csc >= jc[j-1]) { ir[i_merge] = ir[i_csc]; pr[i_merge] = pr[i_csc]; --i_csc; --i_merge; } // Update the column count jc[j-1] = i_merge+1; } coords.resize(0); } zgimbutas-mwrap-25008ce/example/fem/src/assembler.h000066400000000000000000000051071515063637600223310ustar00rootroot00000000000000/* * assembler.h * Compressed sparse column matrix assembler interface. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef ASSEMBLER_H #define ASSEMBLER_H #include using std::vector; /* * The MatrixAssembler class is responsible for assembling a finite element * matrix. In pure MATLAB, the assembly operation looks something like * * for i = 1:num_elements * [Ke, idx] = element_stiffness(i); * Ivalid = find(idx > 0 & idx < N); * idx = idx(Ivalid); * Ke = Ke(Ivalid,Ivalid); * K(idx,idx) = K(idx,idx) + Ke; * end * * The method add_entry is equivalent to most of the body of this loop -- * it removes out-of-range indices and accumulates the rest of the element * contribution. * * Elements in the matrix can be stored in one of two ways. First, * there are elements that go into the current compressed sparse * column matrix structure. Then there are elements that correspond * to indices that were not in the matrix the last time we built the * compressed sparse column structure. When it is time to assemble * the matrix, we use the compress method to take all these extra * elements and merge them into the compressed sparse column indexing * structure. This means that after K is assembled once, any we can * assemble other matrices with the same structure using a little less * time and memory. */ class MatrixAssembler { public: MatrixAssembler(int m, int n) : m(m), n(n), jc(n+1) {} MatrixAssembler(int m, int n, int coord_nnz) : m(m), n(n), jc(n+1), coords(coord_nnz) {} void add_entry(int i, int j, double Aij); void add_entry(const int* i, const int* j, double* Aij, int m_elt, int n_elt); void wipe(); void pack_cache(); void compress(); int get_m() { return m; } int get_n() { return n; } int* get_jc() { return &(jc[0]); } int* get_ir() { return &(ir[0]); } double* get_pr() { return &(pr[0]); } int cache_nnz() { return coords.size(); } int csc_nnz() { return pr.size(); } private: struct Coord { Coord() {} Coord(int i, int j, double Aij) : i(i), j(j), Aij(Aij) {} bool operator<(const Coord& coord) const { return ((j < coord.j) || (j == coord.j && i < coord.i)); } int i, j; double Aij; }; int m, n; // Things that fit in the compressed sparse representation vector jc; vector ir; vector pr; // Cache of entries that didn't fit in the compressed sparse form vector coords; }; #endif /* ASSEMBLER_H */ zgimbutas-mwrap-25008ce/example/fem/src/assembler2.cc000066400000000000000000000060101515063637600225430ustar00rootroot00000000000000/* * assembler.cc * Compressed sparse column matrix assembler implementation. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "assembler.h" #include #include #define ME MatrixAssembler2 using std::sort; using std::fill; /* * Add A(i,j) += Aij. If there's space in the existing compressed * sparse column data structure, add it there; otherwise, stash it in * the coords cache vector. */ void ME::add_entry(int i, int j, double Aij) { if (i < 0 || i >= m || j < 0 || j >= n) return; for (int ii = jc[j]; ii < jc[j+1]; ++ii) { if (ir[ii] == i) { pr[ii] += Aij; return; } } coords.push_back(Coord(i,j,Aij)); } /* * Add an element submatrix. */ void ME::add_entry(const int* i, const int* j, double* Aij, int m_elt, int n_elt) { for (int jj = 0; jj < n_elt; ++jj) for (int ii = 0; ii < m_elt; ++ii) add_entry(i[ii], j[jj], Aij[jj*m_elt+ii]); } /* * Wipe the input matrix. Note that the compressed sparse column index * structure remains intact, so we can re-assemble without doing too much * work. */ void ME::wipe() { coords.resize(0); fill(get_pr(), get_pr()+jc[n], 0); } /* * Sort the entries in the coords cache, and merge (by summing) contributions * to the same position. */ void ME::pack_cache() { if (coords.size() > 0) { sort(coords.begin(), coords.end()); int i_merge = 0; for (int i_coord = 1; i_coord < coords.size(); ++i_coord) { if (coords[i_merge] < coords[i_coord]) coords[++i_merge] = coords[i_coord]; else coords[i_merge].Aij += coords[i_coord].Aij; } coords.resize(i_merge+1); } } /* * Pack the coordinate cache, then merge sort the contents of the compressed * sparse column data structure with the contents of the entry cache. */ void ME::compress() { pack_cache(); ir.resize(ir.size() + coords.size()); pr.resize(pr.size() + coords.size()); int i_coord = coords.size()-1; // Next input coord to process int i_csc = jc[n]-1; // Next input CSC entry to process int i_merge = pr.size()-1; // Next output CSC entry to process jc[n] = pr.size(); for (int j = n; j > 0; --j) { // Merge column from cache with column from previous CSC while (i_coord >= 0 && coords[i_coord].j == j-1 && i_csc >= 0 && i_csc >= jc[j-1]) { if (coords[i_coord].i > ir[i_csc]) { ir[i_merge] = coords[i_coord].i; pr[i_merge] = coords[i_coord].Aij; --i_coord; } else { ir[i_merge] = ir[i_csc]; pr[i_merge] = pr[i_csc]; --i_csc; } --i_merge; } // Copy stragglers from coord list while (i_coord >= 0 && coords[i_coord].j == j-1) { ir[i_merge] = coords[i_coord].i; pr[i_merge] = coords[i_coord].Aij; --i_coord; --i_merge; } // Copy stragglers from CSC list while (i_csc >= 0 && i_csc >= jc[j-1]) { ir[i_merge] = ir[i_csc]; pr[i_merge] = pr[i_csc]; --i_csc; --i_merge; } // Update the column count jc[j-1] = i_merge+1; } coords.resize(0); } zgimbutas-mwrap-25008ce/example/fem/src/assembler2.h000066400000000000000000000051121515063637600224070ustar00rootroot00000000000000/* * assembler.h * Compressed sparse column matrix assembler interface. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef ASSEMBLER2_H #define ASSEMBLER2_H #include using std::vector; /* * The MatrixAssembler2 class is responsible for assembling a finite element * matrix. In pure MATLAB, the assembly operation looks something like * * for i = 1:num_elements * [Ke, idx] = element_stiffness(i); * Ivalid = find(idx > 0 & idx < N); * idx = idx(Ivalid); * Ke = Ke(Ivalid,Ivalid); * K(idx,idx) = K(idx,idx) + Ke; * end * * The method add_entry is equivalent to most of the body of this loop -- * it removes out-of-range indices and accumulates the rest of the element * contribution. * * Elements in the matrix can be stored in one of two ways. First, * there are elements that go into the current compressed sparse * column matrix structure. Then there are elements that correspond * to indices that were not in the matrix the last time we built the * compressed sparse column structure. When it is time to assemble * the matrix, we use the compress method to take all these extra * elements and merge them into the compressed sparse column indexing * structure. This means that after K is assembled once, we can * assemble other matrices with the same structure using a little less * time and memory. */ class MatrixAssembler2 { public: MatrixAssembler2(int m, int n) : m(m), n(n), jc(n+1) {} MatrixAssembler2(int m, int n, int coord_nnz) : m(m), n(n), jc(n+1), coords(coord_nnz) {} void add_entry(int i, int j, double Aij); void add_entry(const int* i, const int* j, double* Aij, int m_elt, int n_elt); void wipe(); void pack_cache(); void compress(); int get_m() { return m; } int get_n() { return n; } int* get_jc() { return &(jc[0]); } int* get_ir() { return &(ir[0]); } double* get_pr() { return &(pr[0]); } int cache_nnz() { return coords.size(); } int csc_nnz() { return pr.size(); } private: struct Coord { Coord() {} Coord(int i, int j, double Aij) : i(i), j(j), Aij(Aij) {} bool operator<(const Coord& coord) const { return ((j < coord.j) || (j == coord.j && i < coord.i)); } int i, j; double Aij; }; int m, n; // Things that fit in the compressed sparse representation vector jc; vector ir; vector pr; // Cache of entries that didn't fit in the compressed sparse form vector coords; }; #endif /* ASSEMBLER2_H */ zgimbutas-mwrap-25008ce/example/fem/src/elastic2d.cc000066400000000000000000000073051515063637600223660ustar00rootroot00000000000000/* * elastic2d.cc * Element type for 2D elasticity (4 node quad only). * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "etype.h" #include "mesh.h" #include "elastic2d.h" #include "quad2d.h" #include "gauss2by2.h" #include #define ME Elastic2D ME::ME(double E, double nu, const char* type) { if (strcmp(type, "plane stress") == 0) plane_stress(E, nu); else plane_strain(E, nu); } void ME::plane_strain(double E, double nu) { /* input E, nu; output D(3,3); D = E/(1+nu)/(1-2*nu) * [ 1-nu, nu, 0; nu, 1-nu, 0; 0, 0, (1-2*nu)/2 ]; */ } void ME::plane_stress(double E, double nu) { /* input E, nu; output D(3,3); D = E/(1-nu*nu) * [ 1, nu, 0; nu, 1, 0; 0, 0, (1-nu)/2 ]; */ } void ME::assign_ids(Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) { int ni = mesh->ix(i,eltid); mesh->id(0,ni) = 1; mesh->id(1,ni) = 1; } } void ME::assemble_f(Mesh* mesh, int eltid) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(4*4); for (xi.start(); !xi.done(); ++xi) { double eps[3] = {0, 0, 0}; for (int j = 0; j < 4; ++j) { const double* u = mesh->u(mesh->ix(j,eltid)); double Nj_x = xi.dN(j,0); double Nj_y = xi.dN(j,1); /* // Contribute strain at quadrature point input Nj_x, Nj_y, D(3,3); inout eps(3); input u(2); Bj = [Nj_x, 0; 0, Nj_y; Nj_y, Nj_x]; eps += Bj*u; */ } for (int i = 0; i < 4; ++i) { double* f = mesh->f(mesh->ix(i,eltid)); double Ni_x = xi.dN(i,0); double Ni_y = xi.dN(i,1); double w = xi.wt(); /* // Contribute B_i'*D*B(u) * w input Ni_x, Ni_y, D(3,3), w; input eps(3); inout f(2); Bi = [Ni_x, 0; 0, Ni_y; Ni_y, Ni_x]; f += Bi'*D*eps*w; */ } } } void ME::assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(8*8); for (xi.start(); !xi.done(); ++xi) { double w = xi.wt(); for (int j = 0; j < 4; ++j) { double Nj_x = xi.dN(j,0); double Nj_y = xi.dN(j,1); for (int i = 0; i < 4; ++i) { double Ni_x = xi.dN(i,0); double Ni_y = xi.dN(i,1); double* Knodal = &(K[16*j +2*i+ 0]); /* // B-matrix based displacement formulation // Isotropic plane strain constitutive tensor input D(3,3), w; input Ni_x, Ni_y, Nj_x, Nj_y; inout Knodal[8](2,2); Bi = [Ni_x, 0; 0, Ni_y; Ni_y, Ni_x]; Bj = [Nj_x, 0; 0, Nj_y; Nj_y, Nj_x]; Knodal += Bi'*D*Bj * w; */ } } } K_assembler->add_entry(id, id, &(K[0]), 8, 8); } void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) { int n = mesh->ix(i,eltid); quad.set_node(i, mesh->x(n)); id[2*i+0] = mesh->id(0,n); id[2*i+1] = mesh->id(1,n); } } zgimbutas-mwrap-25008ce/example/fem/src/elastic2d.h000066400000000000000000000013701515063637600222240ustar00rootroot00000000000000/* * elastic2d.h * Element type for 2D elasticity * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef ELASTIC2D_H #define ELASTIC2D_H #include "etype.h" #include "mesh.h" #include "feshapes.h" class Elastic2D : public EType { public: Elastic2D(double E, double nu, const char* type = "plane strain"); void assign_ids(Mesh* mesh, int eltid); void assemble_f(Mesh* mesh, int eltid); void assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler); private: double D[9]; int id[8]; void plane_strain(double E, double nu); void plane_stress(double E, double nu); void get_quad(FEShapes& quad, Mesh* mesh, int eltid); }; #endif /* ELASTIC2D_H */ zgimbutas-mwrap-25008ce/example/fem/src/elastic2d1.cc000066400000000000000000000250111515063637600224410ustar00rootroot00000000000000/* * elastic2d.cc * Element type for 2D elasticity (4 node quad only). * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "etype.h" #include "mesh.h" #include "elastic2d.h" #include "quad2d.h" #include "gauss2by2.h" #include #define ME Elastic2D ME::ME(double E, double nu, const char* type) { if (strcmp(type, "plane stress") == 0) plane_stress(E, nu); else plane_strain(E, nu); } void ME::plane_strain(double E, double nu) { /* input E, nu; output D(3,3); D = E/(1+nu)/(1-2*nu) * [ 1-nu, nu, 0; nu, 1-nu, 0; 0, 0, (1-2*nu)/2 ]; */ /* */ { double tmp1_ = E; double tmp2_ = nu; double tmp4_ = 1.0 + tmp2_; double tmp5_ = tmp1_ / tmp4_; double tmp7_ = 2.0 * tmp2_; double tmp8_ = 1.0 - tmp7_; double tmp9_ = tmp5_ / tmp8_; double tmp10_ = 1.0 - tmp2_; double tmp12_ = tmp8_ / 2.0; double tmp13_ = tmp9_ * tmp10_; double tmp14_ = tmp9_ * tmp2_; double tmp15_ = tmp9_ * tmp12_; D[0*3+0] = tmp13_; D[0*3+1] = tmp14_; D[0*3+2] = 0; D[1*3+0] = tmp14_; D[1*3+1] = tmp13_; D[1*3+2] = 0; D[2*3+0] = 0; D[2*3+1] = 0; D[2*3+2] = tmp15_; } /* */ } void ME::plane_stress(double E, double nu) { /* input E, nu; output D(3,3); D = E/(1-nu*nu) * [ 1, nu, 0; nu, 1, 0; 0, 0, (1-nu)/2 ]; */ /* */ { double tmp1_ = E; double tmp2_ = nu; double tmp4_ = tmp2_ * tmp2_; double tmp5_ = 1.0 - tmp4_; double tmp6_ = tmp1_ / tmp5_; double tmp8_ = 1.0 - tmp2_; double tmp10_ = tmp8_ / 2.0; double tmp11_ = tmp6_ * tmp2_; double tmp12_ = tmp6_ * tmp10_; D[0*3+0] = tmp6_; D[0*3+1] = tmp11_; D[0*3+2] = 0; D[1*3+0] = tmp11_; D[1*3+1] = tmp6_; D[1*3+2] = 0; D[2*3+0] = 0; D[2*3+1] = 0; D[2*3+2] = tmp12_; } /* */ } void ME::assign_ids(Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) { int ni = mesh->ix(i,eltid); mesh->id(0,ni) = 1; mesh->id(1,ni) = 1; } } void ME::assemble_f(Mesh* mesh, int eltid) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(4*4); for (xi.start(); !xi.done(); ++xi) { double eps[3] = {0, 0, 0}; for (int j = 0; j < 4; ++j) { const double* u = mesh->u(mesh->ix(j,eltid)); double Nj_x = xi.dN(j,0); double Nj_y = xi.dN(j,1); /* // Contribute strain at quadrature point input Nj_x, Nj_y, D(3,3); inout eps(3); input u(2); Bj = [Nj_x, 0; 0, Nj_y; Nj_y, Nj_x]; eps += Bj*u; */ /* */ { double tmp1_ = Nj_x; double tmp2_ = Nj_y; double tmp3_ = eps[0*3+0]; double tmp4_ = eps[0*3+1]; double tmp5_ = eps[0*3+2]; double tmp6_ = u[0*2+0]; double tmp7_ = u[0*2+1]; double tmp8_ = tmp1_ * tmp6_; double tmp9_ = tmp2_ * tmp7_; double tmp10_ = tmp2_ * tmp6_; double tmp11_ = tmp1_ * tmp7_; double tmp12_ = tmp10_ + tmp11_; double tmp13_ = tmp3_ + tmp8_; double tmp14_ = tmp4_ + tmp9_; double tmp15_ = tmp5_ + tmp12_; eps[0*3+0] = tmp13_; eps[0*3+1] = tmp14_; eps[0*3+2] = tmp15_; } /* */ } for (int i = 0; i < 4; ++i) { double* f = mesh->f(mesh->ix(i,eltid)); double Ni_x = xi.dN(i,0); double Ni_y = xi.dN(i,1); double w = xi.wt(); /* // Contribute B_i'*D*B(u) * w input Ni_x, Ni_y, D(3,3), w; input eps(3); inout f(2); Bi = [Ni_x, 0; 0, Ni_y; Ni_y, Ni_x]; f += Bi'*D*eps*w; */ /* */ { double tmp1_ = Ni_x; double tmp2_ = Ni_y; double tmp3_ = D[0*3+0]; double tmp4_ = D[0*3+1]; double tmp5_ = D[0*3+2]; double tmp6_ = D[1*3+0]; double tmp7_ = D[1*3+1]; double tmp8_ = D[1*3+2]; double tmp9_ = D[2*3+0]; double tmp10_ = D[2*3+1]; double tmp11_ = D[2*3+2]; double tmp12_ = w; double tmp13_ = eps[0*3+0]; double tmp14_ = eps[0*3+1]; double tmp15_ = eps[0*3+2]; double tmp16_ = f[0*2+0]; double tmp17_ = f[0*2+1]; double tmp18_ = tmp1_ * tmp3_; double tmp19_ = tmp2_ * tmp5_; double tmp20_ = tmp18_ + tmp19_; double tmp21_ = tmp2_ * tmp4_; double tmp22_ = tmp1_ * tmp5_; double tmp23_ = tmp21_ + tmp22_; double tmp24_ = tmp1_ * tmp6_; double tmp25_ = tmp2_ * tmp8_; double tmp26_ = tmp24_ + tmp25_; double tmp27_ = tmp2_ * tmp7_; double tmp28_ = tmp1_ * tmp8_; double tmp29_ = tmp27_ + tmp28_; double tmp30_ = tmp1_ * tmp9_; double tmp31_ = tmp2_ * tmp11_; double tmp32_ = tmp30_ + tmp31_; double tmp33_ = tmp2_ * tmp10_; double tmp34_ = tmp1_ * tmp11_; double tmp35_ = tmp33_ + tmp34_; double tmp36_ = tmp20_ * tmp13_; double tmp37_ = tmp26_ * tmp14_; double tmp38_ = tmp36_ + tmp37_; double tmp39_ = tmp32_ * tmp15_; double tmp40_ = tmp38_ + tmp39_; double tmp41_ = tmp23_ * tmp13_; double tmp42_ = tmp29_ * tmp14_; double tmp43_ = tmp41_ + tmp42_; double tmp44_ = tmp35_ * tmp15_; double tmp45_ = tmp43_ + tmp44_; double tmp46_ = tmp40_ * tmp12_; double tmp47_ = tmp45_ * tmp12_; double tmp48_ = tmp16_ + tmp46_; double tmp49_ = tmp17_ + tmp47_; f[0*2+0] = tmp48_; f[0*2+1] = tmp49_; } /* */ } } } void ME::assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(8*8); for (xi.start(); !xi.done(); ++xi) { double w = xi.wt(); for (int j = 0; j < 4; ++j) { double Nj_x = xi.dN(j,0); double Nj_y = xi.dN(j,1); for (int i = 0; i < 4; ++i) { double Ni_x = xi.dN(i,0); double Ni_y = xi.dN(i,1); double* Knodal = &(K[16*j +2*i+ 0]); /* // B-matrix based displacement formulation // Isotropic plane strain constitutive tensor input D(3,3), w; input Ni_x, Ni_y, Nj_x, Nj_y; inout Knodal[8](2,2); Bi = [Ni_x, 0; 0, Ni_y; Ni_y, Ni_x]; Bj = [Nj_x, 0; 0, Nj_y; Nj_y, Nj_x]; Knodal += Bi'*D*Bj * w; */ /* */ { double tmp1_ = D[0*3+0]; double tmp2_ = D[0*3+1]; double tmp3_ = D[0*3+2]; double tmp4_ = D[1*3+0]; double tmp5_ = D[1*3+1]; double tmp6_ = D[1*3+2]; double tmp7_ = D[2*3+0]; double tmp8_ = D[2*3+1]; double tmp9_ = D[2*3+2]; double tmp10_ = w; double tmp11_ = Ni_x; double tmp12_ = Ni_y; double tmp13_ = Nj_x; double tmp14_ = Nj_y; double tmp15_ = Knodal[0*8+0]; double tmp16_ = Knodal[0*8+1]; double tmp17_ = Knodal[1*8+0]; double tmp18_ = Knodal[1*8+1]; double tmp19_ = tmp11_ * tmp1_; double tmp20_ = tmp12_ * tmp3_; double tmp21_ = tmp19_ + tmp20_; double tmp22_ = tmp12_ * tmp2_; double tmp23_ = tmp11_ * tmp3_; double tmp24_ = tmp22_ + tmp23_; double tmp25_ = tmp11_ * tmp4_; double tmp26_ = tmp12_ * tmp6_; double tmp27_ = tmp25_ + tmp26_; double tmp28_ = tmp12_ * tmp5_; double tmp29_ = tmp11_ * tmp6_; double tmp30_ = tmp28_ + tmp29_; double tmp31_ = tmp11_ * tmp7_; double tmp32_ = tmp12_ * tmp9_; double tmp33_ = tmp31_ + tmp32_; double tmp34_ = tmp12_ * tmp8_; double tmp35_ = tmp11_ * tmp9_; double tmp36_ = tmp34_ + tmp35_; double tmp37_ = tmp21_ * tmp13_; double tmp38_ = tmp33_ * tmp14_; double tmp39_ = tmp37_ + tmp38_; double tmp40_ = tmp24_ * tmp13_; double tmp41_ = tmp36_ * tmp14_; double tmp42_ = tmp40_ + tmp41_; double tmp43_ = tmp27_ * tmp14_; double tmp44_ = tmp33_ * tmp13_; double tmp45_ = tmp43_ + tmp44_; double tmp46_ = tmp30_ * tmp14_; double tmp47_ = tmp36_ * tmp13_; double tmp48_ = tmp46_ + tmp47_; double tmp49_ = tmp39_ * tmp10_; double tmp50_ = tmp42_ * tmp10_; double tmp51_ = tmp45_ * tmp10_; double tmp52_ = tmp48_ * tmp10_; double tmp53_ = tmp15_ + tmp49_; double tmp54_ = tmp16_ + tmp50_; double tmp55_ = tmp17_ + tmp51_; double tmp56_ = tmp18_ + tmp52_; Knodal[0*8+0] = tmp53_; Knodal[0*8+1] = tmp54_; Knodal[1*8+0] = tmp55_; Knodal[1*8+1] = tmp56_; } /* */ } } } K_assembler->add_entry(id, id, &(K[0]), 8, 8); } void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) { int n = mesh->ix(i,eltid); quad.set_node(i, mesh->x(n)); id[2*i+0] = mesh->id(0,n); id[2*i+1] = mesh->id(1,n); } } zgimbutas-mwrap-25008ce/example/fem/src/etype.h000066400000000000000000000010001515063637600214660ustar00rootroot00000000000000/* * etype.h * Element type interface definition. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef ETYPE_H #define ETYPE_H #include "assembler.h" class Mesh; class EType { public: virtual ~EType(); virtual void assign_ids(Mesh* mesh, int eltid) = 0; virtual void assemble_f(Mesh* mesh, int eltid) = 0; virtual void assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler) = 0; }; #endif /* ETYPE_H */ zgimbutas-mwrap-25008ce/example/fem/src/feintegrals.h000066400000000000000000000021101515063637600226460ustar00rootroot00000000000000/* * feintegrals.h * Interface for element quadrature rules. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef FEINTEGRALS_H #define FEINTEGRALS_H #include "feshapes.h" #include using std::vector; class VolumeQuadrature { public: VolumeQuadrature(FEShapes& quad, int ndim) : quad(quad), nshape1(quad.nshape()), xx1(2), N1(quad.nshape()), dN1(ndim*quad.nshape()) {} virtual void start() = 0; virtual bool done() = 0; virtual void operator++() = 0; virtual double wt() = 0; int nshape() { return nshape1; } double* xx() { return &(xx1[0]); } double* N() { return &(N1[0]); } double* dN() { return &(dN1[0]); } double xx(int i) { return xx1[i]; } double N(int i) { return N1[i]; } double dN(int i, int j) { return dN1[i+j*nshape1]; } protected: FEShapes& quad; int nshape1; vector xx1; vector N1; vector dN1; double J; }; #endif /* FEINTEGRALS_H */ zgimbutas-mwrap-25008ce/example/fem/src/feshapes.h000066400000000000000000000010621515063637600221460ustar00rootroot00000000000000/* * feshapes.h * Interface for element shape functions. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef FESHAPES_H #define FESHAPES_H class FEShapes { public: virtual ~FEShapes() {} virtual void set_node(int nodenum, const double* x) = 0; virtual void set_nodes(const double* x) = 0; virtual void eval(const double *XX, double* xx, double* N, double* dN, double& J) const = 0; virtual int nshape() const = 0; }; #endif /* FESHAPES_H */ zgimbutas-mwrap-25008ce/example/fem/src/gauss2by2.cc000066400000000000000000000007151515063637600223330ustar00rootroot00000000000000/* * gauss2by2.cc * Parent domain node locations and weights for quadrature on a * 2-by-2 Gauss grid over [-1,1]^2. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "gauss2by2.h" const double Gauss4::X[12] = { -0.577350269189626, -0.577350269189626, 1, 0.577350269189626, -0.577350269189626, 1, 0.577350269189626, 0.577350269189626, 1, -0.577350269189626, 0.577350269189626, 1, }; zgimbutas-mwrap-25008ce/example/fem/src/gauss2by2.h000066400000000000000000000013071515063637600221730ustar00rootroot00000000000000/* * gauss2by2.h * 2-by-2 Gauss grid quadrature over [-1,1]^2. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef GAUSS2BY2_H #define GAUSS2BY2_H #include "feshapes.h" #include "feintegrals.h" class Gauss4 : public VolumeQuadrature { public: Gauss4(FEShapes& quad) : VolumeQuadrature(quad, 2) { start(); } void start() { i = 0; eval(); } bool done() { return (i > 3); } void operator++() { if (++i <= 3) eval(); } double wt() { return X[3*i+2]*J; } private: static const double X[12]; int i; void eval() { quad.eval(X+3*i, xx(), N(), dN(), J); } }; #endif /* GAUSS2BY2_H */ zgimbutas-mwrap-25008ce/example/fem/src/mesh.cc000066400000000000000000000042041515063637600214430ustar00rootroot00000000000000/* * mesh.cc * Finite element mesh implementation. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "mesh.h" #define ME Mesh EType::~EType() { } ME::~ME() { for (vector::iterator i = materials_owned.begin(); i != materials_owned.end(); ++i) { delete(*i); } } int ME::add_node(double* x) { int id = numnp(); for (int i = 0; i < ndm_; ++i) X.push_back(x[i]); return id; } int ME::add_element(EType* etype, int* nodes, int nen) { int id = numelt(); int i = 0; for (; i < nen && i < maxnen_; ++i) IX.push_back(nodes[i]); for (; i < maxnen_; ++i) IX.push_back(-1); elements.push_back(etype); return id; } void ME::add_material(EType* material) { materials_owned.push_back(material); } void ME::set_ur(const double* ur) { for (int i = 0; i < ID.size(); ++i) { if (ID[i] >= 0) U[i] = ur[ID[i]]; if (BC[i]) U[i] = BV[i]; } } void ME::get_ur(double* ur) { for (int i = 0; i < ID.size(); ++i) if (ID[i] >= 0) ur[ID[i]] = U[i]; } void ME::get_fr(double* fr) { for (int i = 0; i < ID.size(); ++i) { if (ID[i] >= 0) fr[ID[i]] = R[i]; if (!BC[i]) fr[ID[i]] -= BV[i]; } } int ME::initialize() { ID.resize(maxndf_ * numnp()); R.resize (maxndf_ * numnp()); U.resize (maxndf_ * numnp()); BC.resize(maxndf_ * numnp()); BV.resize(maxndf_ * numnp()); return assign_ids(); } int ME::assign_ids() { numid_ = 0; int n = numelt(); for (int i = 0; i < ID.size(); ++i) ID[i] = 0; for (int i = 0; i < n; ++i) if (elements[i]) elements[i]->assign_ids(this, i); for (int i = 0; i < ID.size(); ++i) ID[i] = ( (ID[i] && !BC[i]) ? numid_++ : -1 ); return numid_; } void ME::assemble_F() { int n = numelt(); for (int i = 0; i < n; ++i) if (elements[i]) elements[i]->assemble_f(this, i); } void ME::assemble_K(MatrixAssembler* K_assembler) { int n = numelt(); for (int i = 0; i < n; ++i) if (elements[i]) elements[i]->assemble_K(this, i, K_assembler); } zgimbutas-mwrap-25008ce/example/fem/src/mesh.h000066400000000000000000000065341515063637600213150ustar00rootroot00000000000000/* * mesh.h * Finite element mesh implementation. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef MESH_H #define MESH_H #include "assembler.h" #include "etype.h" #include using std::vector; class Mesh { public: Mesh(int ndm, int maxndf, int maxnen) : ndm_(ndm), maxndf_(maxndf), maxnen_(maxnen), numid_(0) {} ~Mesh(); int ndm() const { return ndm_; } int maxndf() const { return maxndf_; } int maxnen() const { return maxnen_; } int numelt() const { return elements.size(); } int numnp() const { return X.size() / ndm_; } int numid() const { return numid_; } double* x () { return &(X[0]); } int* ix() { return &(IX[0]); } int* id() { return &(ID[0]); } double* u () { return &(U[0]); } double* f () { return &(R[0]); } char* bc() { return &(BC[0]); } double* bv() { return &(BV[0]); } const double* x (int j) const { return &(X [j*ndm_]); } const int* ix(int j) const { return &(IX[j*maxnen_]); } const int* id(int j) const { return &(ID[j*maxndf_]); } const double* u (int j) const { return &(U [j*maxndf_]); } const double* f (int j) const { return &(R [j*maxndf_]); } double* f (int j) { return &(R [j*maxndf_]); } const char* bc(int j) const { return &(BC[j*maxndf_]); } const double* bv(int j) const { return &(BV[j*maxndf_]); } double x (int i, int j) const { return X [i+j*ndm_]; } int ix(int i, int j) const { return IX[i+j*maxnen_]; } int id(int i, int j) const { return ID[i+j*maxndf_]; } int& id(int i, int j) { return ID[i+j*maxndf_]; } double u (int i, int j) const { return U [i+j*maxndf_]; } double f (int i, int j) const { return R [i+j*maxndf_]; } double& f (int i, int j) { return R [i+j*maxndf_]; } char bc(int i, int j) const { return BC[i+j*maxndf_]; } char& bc(int i, int j) { return BC[i+j*maxndf_]; } double bv(int i, int j) const { return BV[i+j*maxndf_]; } double& bv(int i, int j) { return BV[i+j*maxndf_]; } void set_ur(const double* ur); void get_ur(double* ur); void get_fr(double* ur); int initialize(); int assign_ids(); void assemble_F(); void assemble_K(MatrixAssembler* K_assembler); int add_node(double* x); int add_element(EType* etype, int* nodes, int numnp); void add_material(EType* material); private: Mesh(const Mesh&); Mesh& operator=(const Mesh&); int ndm_; // Number of spatial dimensions int maxndf_; // Maximum degrees of freedom per node int maxnen_; // Maximum number of nodes per element int numid_; // Number of active degrees of freedom vector X; // Coordinate array ( ndm * numnp ) vector IX; // Element connectivity ( maxnen * numelt ) vector ID; // Identifier assignment ( maxndf * numnp ) vector R; // Full residual vector ( maxndf * numnp ) vector U; // Full solution ( maxndf * numnp ) vector BC; // Flag Dirichlet BCs ( maxndf * numnp ) vector BV; // Boundary values ( maxndf * numnp ) vector elements; // Material assignment (numelt) vector materials_owned; }; #endif /* MESH_H */ zgimbutas-mwrap-25008ce/example/fem/src/quad2d.cc000066400000000000000000000025531515063637600216740ustar00rootroot00000000000000/* * quad2d.h * Implementation for four-node quad element shapes. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "quad2d.h" #define ME Quad2d ME::~ME() { } void ME::set_node(int nodenum, const double* x) { nodex[2*nodenum+0] = x[0]; nodex[2*nodenum+1] = x[1]; } void ME::set_nodes(const double* x) { for (int i = 0; i < 8; ++i) nodex[i] = x[i]; } void ME::eval(const double *XX, double* xx, double* N, double* dN, double& J) const { double X = XX[0]; double Y = XX[1]; double FF[4]; /* // Evaluate element functions input X, Y; input nodex(2,4); output N(4); output dN(4,2); output xx(2); output FF(2,2); N1x = (1-X)/2; N1y = (1-Y)/2; N2x = (1+X)/2; N2y = (1+Y)/2; N = [ N1x*N1y; N2x*N1y; N2x*N2y; N1x*N2y]; dN = [ -N1y, N1y, N2y, -N2y; -N1x, -N2x, N2x, N1x ]'/2; xx = nodex*N; FF = nodex*dN; */ remap_gradients(FF, dN, J); } void ME::remap_gradients(double* FF, double* dN, double& J) const { J = (FF[0]*FF[3]-FF[1]*FF[2]); double invF[4] = { FF[3]/J, -FF[1]/J, -FF[2]/J, FF[0]/J }; /* // Remap gradients inout dN(4,2); input invF(2,2); dN = dN*invF; */ } zgimbutas-mwrap-25008ce/example/fem/src/quad2d.h000066400000000000000000000013011515063637600215240ustar00rootroot00000000000000/* * quad2d.h * Interface for four-node quad element shapes. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef QUAD2D_H #define QUAD2D_H #include "feshapes.h" class Quad2d : public FEShapes { public: Quad2d() {} Quad2d(const double* x) { set_nodes(x); } virtual ~Quad2d(); void set_node(int nodenum, const double* x); void set_nodes(const double* x); void eval(const double *XX, double* xx, double* N, double* dN, double& J) const; int nshape() const { return 4; } private: double nodex[2*4]; void remap_gradients(double* FF, double* dN, double& J) const; }; #endif /* QUAD2D_H */ zgimbutas-mwrap-25008ce/example/fem/src/quad2d1.cc000066400000000000000000000136061515063637600217560ustar00rootroot00000000000000/* * quad2d.h * Implementation for four-node quad element shapes. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "quad2d.h" #define ME Quad2d ME::~ME() { } void ME::set_node(int nodenum, const double* x) { nodex[2*nodenum+0] = x[0]; nodex[2*nodenum+1] = x[1]; } void ME::set_nodes(const double* x) { for (int i = 0; i < 8; ++i) nodex[i] = x[i]; } void ME::eval(const double *XX, double* xx, double* N, double* dN, double& J) const { double X = XX[0]; double Y = XX[1]; double FF[4]; /* // Evaluate element functions input X, Y; input nodex(2,4); output N(4); output dN(4,2); output xx(2); output FF(2,2); N1x = (1-X)/2; N1y = (1-Y)/2; N2x = (1+X)/2; N2y = (1+Y)/2; N = [ N1x*N1y; N2x*N1y; N2x*N2y; N1x*N2y]; dN = [ -N1y, N1y, N2y, -N2y; -N1x, -N2x, N2x, N1x ]'/2; xx = nodex*N; FF = nodex*dN; */ /* */ { double tmp1_ = X; double tmp2_ = Y; double tmp3_ = nodex[0*2+0]; double tmp4_ = nodex[0*2+1]; double tmp5_ = nodex[1*2+0]; double tmp6_ = nodex[1*2+1]; double tmp7_ = nodex[2*2+0]; double tmp8_ = nodex[2*2+1]; double tmp9_ = nodex[3*2+0]; double tmp10_ = nodex[3*2+1]; double tmp12_ = 1.0 - tmp1_; double tmp14_ = tmp12_ / 2.0; double tmp15_ = 1.0 - tmp2_; double tmp16_ = tmp15_ / 2.0; double tmp17_ = 1.0 + tmp1_; double tmp18_ = tmp17_ / 2.0; double tmp19_ = 1.0 + tmp2_; double tmp20_ = tmp19_ / 2.0; double tmp21_ = tmp14_ * tmp16_; double tmp22_ = tmp18_ * tmp16_; double tmp23_ = tmp18_ * tmp20_; double tmp24_ = tmp14_ * tmp20_; double tmp25_ = -tmp16_; double tmp26_ = -tmp20_; double tmp27_ = -tmp14_; double tmp28_ = -tmp18_; double tmp29_ = tmp25_ / 2.0; double tmp30_ = tmp16_ / 2.0; double tmp31_ = tmp20_ / 2.0; double tmp32_ = tmp26_ / 2.0; double tmp33_ = tmp27_ / 2.0; double tmp34_ = tmp28_ / 2.0; double tmp35_ = tmp18_ / 2.0; double tmp36_ = tmp14_ / 2.0; double tmp37_ = tmp3_ * tmp21_; double tmp38_ = tmp5_ * tmp22_; double tmp39_ = tmp37_ + tmp38_; double tmp40_ = tmp7_ * tmp23_; double tmp41_ = tmp39_ + tmp40_; double tmp42_ = tmp9_ * tmp24_; double tmp43_ = tmp41_ + tmp42_; double tmp44_ = tmp4_ * tmp21_; double tmp45_ = tmp6_ * tmp22_; double tmp46_ = tmp44_ + tmp45_; double tmp47_ = tmp8_ * tmp23_; double tmp48_ = tmp46_ + tmp47_; double tmp49_ = tmp10_ * tmp24_; double tmp50_ = tmp48_ + tmp49_; double tmp51_ = tmp3_ * tmp29_; double tmp52_ = tmp5_ * tmp30_; double tmp53_ = tmp51_ + tmp52_; double tmp54_ = tmp7_ * tmp31_; double tmp55_ = tmp53_ + tmp54_; double tmp56_ = tmp9_ * tmp32_; double tmp57_ = tmp55_ + tmp56_; double tmp58_ = tmp4_ * tmp29_; double tmp59_ = tmp6_ * tmp30_; double tmp60_ = tmp58_ + tmp59_; double tmp61_ = tmp8_ * tmp31_; double tmp62_ = tmp60_ + tmp61_; double tmp63_ = tmp10_ * tmp32_; double tmp64_ = tmp62_ + tmp63_; double tmp65_ = tmp3_ * tmp33_; double tmp66_ = tmp5_ * tmp34_; double tmp67_ = tmp65_ + tmp66_; double tmp68_ = tmp7_ * tmp35_; double tmp69_ = tmp67_ + tmp68_; double tmp70_ = tmp9_ * tmp36_; double tmp71_ = tmp69_ + tmp70_; double tmp72_ = tmp4_ * tmp33_; double tmp73_ = tmp6_ * tmp34_; double tmp74_ = tmp72_ + tmp73_; double tmp75_ = tmp8_ * tmp35_; double tmp76_ = tmp74_ + tmp75_; double tmp77_ = tmp10_ * tmp36_; double tmp78_ = tmp76_ + tmp77_; N[0*4+0] = tmp21_; N[0*4+1] = tmp22_; N[0*4+2] = tmp23_; N[0*4+3] = tmp24_; dN[0*4+0] = tmp29_; dN[0*4+1] = tmp30_; dN[0*4+2] = tmp31_; dN[0*4+3] = tmp32_; dN[1*4+0] = tmp33_; dN[1*4+1] = tmp34_; dN[1*4+2] = tmp35_; dN[1*4+3] = tmp36_; xx[0*2+0] = tmp43_; xx[0*2+1] = tmp50_; FF[0*2+0] = tmp57_; FF[0*2+1] = tmp64_; FF[1*2+0] = tmp71_; FF[1*2+1] = tmp78_; } /* */ remap_gradients(FF, dN, J); } void ME::remap_gradients(double* FF, double* dN, double& J) const { J = (FF[0]*FF[3]-FF[1]*FF[2]); double invF[4] = { FF[3]/J, -FF[1]/J, -FF[2]/J, FF[0]/J }; /* // Remap gradients inout dN(4,2); input invF(2,2); dN = dN*invF; */ /* */ { double tmp1_ = dN[0*4+0]; double tmp2_ = dN[0*4+1]; double tmp3_ = dN[0*4+2]; double tmp4_ = dN[0*4+3]; double tmp5_ = dN[1*4+0]; double tmp6_ = dN[1*4+1]; double tmp7_ = dN[1*4+2]; double tmp8_ = dN[1*4+3]; double tmp9_ = invF[0*2+0]; double tmp10_ = invF[0*2+1]; double tmp11_ = invF[1*2+0]; double tmp12_ = invF[1*2+1]; double tmp13_ = tmp1_ * tmp9_; double tmp14_ = tmp5_ * tmp10_; double tmp15_ = tmp13_ + tmp14_; double tmp16_ = tmp2_ * tmp9_; double tmp17_ = tmp6_ * tmp10_; double tmp18_ = tmp16_ + tmp17_; double tmp19_ = tmp3_ * tmp9_; double tmp20_ = tmp7_ * tmp10_; double tmp21_ = tmp19_ + tmp20_; double tmp22_ = tmp4_ * tmp9_; double tmp23_ = tmp8_ * tmp10_; double tmp24_ = tmp22_ + tmp23_; double tmp25_ = tmp1_ * tmp11_; double tmp26_ = tmp5_ * tmp12_; double tmp27_ = tmp25_ + tmp26_; double tmp28_ = tmp2_ * tmp11_; double tmp29_ = tmp6_ * tmp12_; double tmp30_ = tmp28_ + tmp29_; double tmp31_ = tmp3_ * tmp11_; double tmp32_ = tmp7_ * tmp12_; double tmp33_ = tmp31_ + tmp32_; double tmp34_ = tmp4_ * tmp11_; double tmp35_ = tmp8_ * tmp12_; double tmp36_ = tmp34_ + tmp35_; dN[0*4+0] = tmp15_; dN[0*4+1] = tmp18_; dN[0*4+2] = tmp21_; dN[0*4+3] = tmp24_; dN[1*4+0] = tmp27_; dN[1*4+1] = tmp30_; dN[1*4+2] = tmp33_; dN[1*4+3] = tmp36_; } /* */ } zgimbutas-mwrap-25008ce/example/fem/src/scalar1d.cc000066400000000000000000000020501515063637600221760ustar00rootroot00000000000000/* * scalar1d.cc * Element type for 1D Laplacian. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "scalar1d.h" #define ME Scalar1D void ME::assign_ids(Mesh* mesh, int eltid) { int n1 = mesh->ix(0,eltid); int n2 = mesh->ix(1,eltid); mesh->id(0,n1) = 1; mesh->id(0,n2) = 1; } void ME::assemble_f(Mesh* mesh, int eltid) { int n1 = mesh->ix(0,eltid); int n2 = mesh->ix(1,eltid); double L = mesh->x(0,n2) - mesh->x(0,n1); double kappa = k/L; double udiff = mesh->u(0,n2) - mesh->u(0,n1); mesh->f(0,n1) -= kappa*udiff; mesh->f(0,n2) += kappa*udiff; } void ME::assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler) { int n1 = mesh->ix(0,eltid); int n2 = mesh->ix(1,eltid); double L = mesh->x(0,n2) - mesh->x(0,n1); double kappa = k/L; int i[2] = {mesh->id(0,n1), mesh->id(0,n2)}; double K_elt[4] = { kappa, -kappa, -kappa, kappa }; K_assembler->add_entry(i, i, K_elt, 2, 2); } zgimbutas-mwrap-25008ce/example/fem/src/scalar1d.h000066400000000000000000000010221515063637600220360ustar00rootroot00000000000000/* * scalar1d.h * Element type for 1D Laplacian. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef SCALAR1D_H #define SCALAR1D_H #include "etype.h" #include "mesh.h" class Scalar1D : public EType { public: Scalar1D(double k) : k(k) {} void assign_ids(Mesh* mesh, int eltid); void assemble_f(Mesh* mesh, int eltid); void assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler); private: double k; }; #endif /* SCALAR1D_H */ zgimbutas-mwrap-25008ce/example/fem/src/scalar2d.cc000066400000000000000000000033531515063637600222060ustar00rootroot00000000000000/* * scalar2d.cc * Element type for 2D Laplacian (4 node quad only). * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "etype.h" #include "mesh.h" #include "scalar2d.h" #include "quad2d.h" #include "gauss2by2.h" #define ME Scalar2D void ME::assign_ids(Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) mesh->id(0, mesh->ix(i,eltid)) = 1; } void ME::assemble_f(Mesh* mesh, int eltid) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(4*4); for (xi.start(); !xi.done(); ++xi) { // Compute grad u at the quadrature point double dudx[2] = {0, 0}; for (int j = 0; j < 4; ++j) { double uj = mesh->u(0,mesh->ix(j,eltid)); dudx[0] += xi.dN(j,0) * uj; dudx[1] += xi.dN(j,1) * uj; } // Contribute k * dot(grad N_i, grad u) * wt for (int i = 0; i < 4; ++i) mesh->f(0,mesh->ix(i,eltid)) += k * (xi.dN(i,0) * dudx[0] + xi.dN(i,1) * dudx[1]) * xi.wt(); } } void ME::assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler) { Quad2d quad; Gauss4 xi(quad); get_quad(quad, mesh, eltid); vector K(4*4); for (xi.start(); !xi.done(); ++xi) for (int j = 0; j < 4; ++j) for (int i = 0; i < 4; ++i) K[4*j+i] += k * (xi.dN(i,0) * xi.dN(j,0) + xi.dN(i,1) * xi.dN(j,1)) * xi.wt(); K_assembler->add_entry(id, id, &(K[0]), 4, 4); } void ME::get_quad(FEShapes& quad, Mesh* mesh, int eltid) { for (int i = 0; i < 4; ++i) { int n = mesh->ix(i,eltid); quad.set_node(i, mesh->x(n)); id[i] = mesh->id(0,n); } } zgimbutas-mwrap-25008ce/example/fem/src/scalar2d.h000066400000000000000000000011621515063637600220440ustar00rootroot00000000000000/* * scalar2d.h * Element type for 2D Laplacian. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef SCALAR2D_H #define SCALAR2D_H #include "etype.h" #include "mesh.h" #include "feshapes.h" class Scalar2D : public EType { public: Scalar2D(double k) : k(k) {} void assign_ids(Mesh* mesh, int eltid); void assemble_f(Mesh* mesh, int eltid); void assemble_K(Mesh* mesh, int eltid, MatrixAssembler* K_assembler); private: double k; int id[4]; void get_quad(FEShapes& quad, Mesh* mesh, int eltid); }; #endif /* SCALAR2D_H */ zgimbutas-mwrap-25008ce/example/fem/test_assembler.m000066400000000000000000000022251515063637600226040ustar00rootroot00000000000000% test_assembler.m % Test MWrap interface to CSC matrix assembler. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions init; N = 1000; aobj = Assembler_create(N,N); try fprintf('\nRunning initial assembly loop\n'); tic; for j = 1:N idx = [j, j+1]; Ke = [1, -1; -1, 1]; Assembler_add(aobj, idx, idx, Ke); end toc; fprintf('Nonzeros in assembler before compression and form\n'); Assembler_stats(aobj); K = Assembler_get(aobj); fprintf('Nonzeros in assembler after compression and form\n'); Assembler_stats(aobj); fprintf('\nRe-running assembly loop\n'); Assembler_clear(aobj); tic; for j = 1:N idx = [j, j+1]; Ke = [1, -1; -1, 1]; Assembler_add(aobj, idx, idx, Ke); end toc; fprintf('Nonzeros in assembler before compression and form\n'); Assembler_stats(aobj); K = Assembler_get(aobj); fprintf('Nonzeros in assembler after compression and form\n'); Assembler_stats(aobj); fprintf('\nComparing the result matrices\n'); K2 = Assembler_get(aobj); fprintf('|K2-K1| = %g\n\n', norm(K-K2,1)); catch fprintf('Caught %s\n', lasterr); end Assembler_delete(aobj); zgimbutas-mwrap-25008ce/example/fem/test_patch.m000066400000000000000000000031441515063637600217270ustar00rootroot00000000000000% test_mesh3.m % Test MWrap interface to mesh data structure. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions init; mobj = Mesh_create(2, 2, 4); try fprintf('-- Four element elastic patch test --\n'); % Nodes: % 1 2 3 4 5 6 7 8 9 x = [ 0.0, 4.0, 10.0, 0.0, 5.5, 10.0, 0.0, 4.2, 10.0; 0.0, 0.0, 0.0, 4.5, 5.5, 5.0, 10.0, 10.0, 10.0]; % Boundary codes and values bc =[ 1, 0, 0, 1, 0, 0, 1, 0, 0; 1, 0, 0, 0, 0, 0, 0, 0, 0]; bv =[ 0, 0, 2.5, 0, 0, 5.0, 0, 0, 2.5, 0, 0, 0, 0, 0, 0, 0, 0, 0]; % Elements: % 1 2 3 4 ix = [ 1, 2, 4, 5 ; 2, 3, 5, 6 ; 5, 6, 8, 9 ; 4, 5, 7, 8 ]; % Set up problem mesh material = Mesh_add_elastic2d(mobj, 1000.0, 0.25, 'plane strain'); Mesh_load(mobj, material, x, ix); Mesh_initialize(mobj); % Set boundary conditions Mesh_set_bc(mobj, bc); Mesh_set_bv(mobj, bv); Mesh_assign_ids(mobj); % Assemble stiffness and force K = Mesh_assemble_K(mobj); F = Mesh_assemble_F(mobj); % Solve for the reduced displacement u = -K\F; % Patch test should recover linear fields -- check that it does uu = Mesh_u(mobj); resid = uu - (uu/x)*x; fprintf('Patch test residual: %g\n', norm(resid)); % Assemble residual and make sure it's zero Mesh_set_ur(mobj, u); RR = Mesh_assemble_F(mobj); fprintf('Reported residual force: %g\n', norm(RR)); catch fprintf('Error: %s\n', lasterr); end Mesh_delete(mobj); zgimbutas-mwrap-25008ce/example/fem/test_simple.m000066400000000000000000000017471515063637600221300ustar00rootroot00000000000000% test_mesh.m % Test MWrap interface to mesh data structure. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions init; mobj = Mesh_create(1, 1, 2); try % -- Set up a simple mesh i1 = Mesh_add_node(mobj, 0); i2 = Mesh_add_node(mobj, 1); i3 = Mesh_add_node(mobj, 2); i4 = Mesh_add_node(mobj, 3); s1 = Mesh_add_scalar1d(mobj, 1); e1 = Mesh_add_element(mobj, s1, [i1, i2]); e2 = Mesh_add_element(mobj, s1, [i2, i3]); e3 = Mesh_add_element(mobj, s1, [i3, i4]); Mesh_initialize(mobj); % -- Assign Dirichlet BC to first dof at node 1 Mesh_set_bc(mobj, 1, 1, 1); fprintf('-- Mesh nodes and connectivities --\n'); x = Mesh_x(mobj) ix = Mesh_ix(mobj) fprintf('-- Mesh dof assignments --\n'); numid = Mesh_initialize(mobj) id = Mesh_id(mobj) fprintf('-- Assembled stiffness (standard three-point stencil) --\n'); K = Mesh_assemble_K(mobj); K = full(K) catch fprintf('Error: %s\n', lasterr); end Mesh_delete(mobj); zgimbutas-mwrap-25008ce/example/foobar/000077500000000000000000000000001515063637600201125ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/foobar/Makefile000066400000000000000000000002761515063637600215570ustar00rootroot00000000000000include ../../make.inc MW=../../mwrap all: $(MW) -mex fbmex -m foobar.m foobar.mw $(MW) -mex fbmex -c fbmex.c foobar.mw $(MEX) fbmex.c clean: rm -f foobar.m fbmex.c fbmex.mex* *.o* *~ zgimbutas-mwrap-25008ce/example/foobar/foobar.mw000066400000000000000000000002461515063637600217310ustar00rootroot00000000000000$ #include function foobar; s1 = 'foo'; s2 = 'bar'; # strncat(inout cstring[128] s1, cstring s2, int 127); fprintf('Should be foobar: %s\n', s1); zgimbutas-mwrap-25008ce/example/run_example.m.in000066400000000000000000000001461515063637600217450ustar00rootroot00000000000000% -*- matlab -*- % Autogenerated by CMake. Do not edit manually. @PATHS@ @WORK_DIR@ run('@CALL@'); zgimbutas-mwrap-25008ce/example/zlib/000077500000000000000000000000001515063637600176025ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/example/zlib/Makefile000066400000000000000000000003071515063637600212420ustar00rootroot00000000000000# See www.zlib.net include ../../make.inc MW=../../mwrap gzmex: $(MW) -mex gzmex -mb gzfile.mw $(MW) -mex gzmex -c gzmex.cc gzfile.mw $(MEX) gzmex.cc -lz clean: rm -f gz*.m gzmex.* *.o* eye.gz zgimbutas-mwrap-25008ce/example/zlib/README000066400000000000000000000003111515063637600204550ustar00rootroot00000000000000This example illustrates bindings for the Zlib compression library (http://www.zlib.net/). The test illustrates how these bindings can be used to read and write MATLAB matrices in compressed storage. zgimbutas-mwrap-25008ce/example/zlib/gzfile.mw000066400000000000000000000026331515063637600214330ustar00rootroot00000000000000% gzfile.mw % MWrap wrapper to the ZLib compression library. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions $#include // ---- @function [gzf] = gzopen(path, mode) % [gzf] = gzopen(path, mode) % % Open a zlib output file. # gzFile gzf = gzopen(cstring path, cstring mode); // ---- @function gzclose(gzf) % gzclose(gzf) % % Close a zlib output file. # gzclose(gzFile gzf); // ---- @function [A] = gzread(gzf) % [A] = gzread(gzf) % % Read a matrix from a zlib file. # int isize = sizeof(int 0); # int dsize = sizeof(double 0); nbytes = 2*isize; # gzread(gzFile gzf, output int[2] dims, int nbytes); m = dims(1); n = dims(2); nbytes = m*n*dsize; # gzread(gzFile gzf, output double[m,n] A, int nbytes); % gzwrite(gzf, A) % % Write a matrix to a zlib file. // ---- @function gzwrite(gzf, A) % [A] = gzwrite(gzf, A) % % Write a matrix from a zlib file. # int isize = sizeof(int 0); # int dsize = sizeof(double 0); nbytes = 2*isize; [m,n] = size(A); dims = [m,n]; # gzwrite(gzFile gzf, int[2] dims, int nbytes); m = dims(1); n = dims(2); nbytes = m*n*dsize; # gzwrite(gzFile gzf, double[m,n] A, int nbytes); // ---- @function gzsave(path, A) % gzsave(path, A) % % Save a matrix to a zlib file. gzf = gzopen(path, 'w+'); gzwrite(gzf, A) // ---- @function [A] = gzload(path) % [A] = gzload(path) % % Read a matrix from a zlib file. gzf = gzopen(path, 'r'); A = gzread(gzf); zgimbutas-mwrap-25008ce/example/zlib/testgz.m000066400000000000000000000006511515063637600213020ustar00rootroot00000000000000% testgz.m % Test/demo a MWrap wrapper to the ZLib compression library. % % Copyright (c) 2007 David Bindel % See the file COPYING for copying permissions A = eye(100); fprintf('Writing identity to eye.gz\n'); fp = gzopen('eye.gz', 'w'); gzwrite(fp, A); gzclose(fp); fprintf('Reading identity back from eye.gz\n'); fp = gzopen('eye.gz', 'r'); B = gzread(fp); gzclose(fp); fprintf('Difference is = %g\n', norm(A-B,1)); zgimbutas-mwrap-25008ce/make.inc000066400000000000000000000010761515063637600166230ustar00rootroot00000000000000# === Compilers === # (You don't need flex and bison unless you're planning to modify the # grammar -- the default installation comes with the relevant files # already in place.) # Uncomment this line for new-style classdef support OOFLAG=-DR2008OO # Uncomment this line for C99 complex support TESTC99COMPLEX=test_c99_complex CC := $(if $(CC),$(CC),gcc) CXX := $(if $(CXX),$(CXX),g++) MEX= mex $(OOFLAG) # Use the following for 64-bit MEX # MEX= mex -largeArrayDims $(OOFLAG) # Use the following for GNU Octave. MEX= mkoctfile --mex FLEX= flex BISON= bison zgimbutas-mwrap-25008ce/mwrap.pdf000066400000000000000000006037211515063637600170410ustar00rootroot00000000000000%PDF-1.5 %ÐÔÅØ 3 0 obj << /Length 1841 /Filter /FlateDecode >> stream xÚk“Ó6ð;¿"3Ð9g¸K¶ü€¶3p†Îñ®¥SŽ:[¹xHìŒ ÷ﻫ]9ó_biµÚ÷KyuõèÙ›HÎT(’DéÙÕr¦d"T¤gi˜‰Tdz«rö9xÿ©5Ûù—«?;<ÄÎ!µž…„öWgÛù" Uðv¨J‹f‹X‰0S³…ŠE&„ø÷<ÍÛvUS¾ŠÉ«™ŒE' É/d’ ¦³E¤Eœ+ºý‡€K* ^Uui×ç¸Iƒ—hÚÚöý9íþtú¶ÚÌUÜ ½éøÂ{¾ðÁsØ®V|å’¯\s0îƽ47ó웪ë*¼u*5aARW¦ZèV©È2Íæ3ˆ{G44ÓT!ÐWšÕÎà¦P Žjç Ø ›-´ÚS‘ó…”Jïêy$ƒ¾m€Ž Ê¡èÑŒDFΤ¹ÖÎz!HÎ¥8p¢:Ä‹s‘ËÄ;±êÐ%i`œk² ªQøÞ¶KSX:ºµµmMÏÞKƒî®ëífDw°~e Ðm«¶ê Ø,éûñÓ;P&xËЖ¾Ó#«ˆ öŽU¼™g*h&m˜›íiÔ(ÂHþNs„™ávcYò|–…Áû—Híêòå+ÜË +ÚjÛÓÙu(㵅И0£LaeÞ>ß3£Î¥GÛUë5ÑfkYâjX˜×ÿð)œìPN#ìB.!DlWµ¤‚ .ž]<}JJ+%…Nóc­—C]°[df½FgÊœY Ù¸_‡£Kl Úô }MQØÎÃV¦'¢§¢ƒuÑo”WÎù€\ÚÞTk¾é¼r/HÆÿð–mûª¾u*…Ǻ8Þh0':,–-Èêb6{=Î:ج4½¡³®o!)†ÖºTÏã= 'Ò\¯—È…qìOY[/±½¥´oM{çyÀæÖžIΉfZK©¾ªÊÒÖ”îK c€RfÀb€r)¦#Nh}âÚ‡Ã.P9êFï)¬có•·ÕWgqÚî)øæ®êW &ÍmQÍî¶lZHUÊ+ØÚo}‹Q ¥i ÙK;ŠD)-’§ÚÉm!ID|¾>`#MÞ‡¯‹xŒ*¨±®¸b%@FßÌf»¶èä(c³Â•eƒÞÅBB®PA–(£ê<ØUˆ¨;¦ºÁÆ5˜Ï{ÑШ+­/È3qxälyÑXX!,kˆ·).<êd6?Ÿ"ºŽ‡á>™/´ÔÁãª.Ö˜Ò¨*~®`±ú}*ÇöõBc-hšÓ¾ >¦DÆÀ#™ï»$š¿úàŸ½˜"Û©cD :ø˜ðÐ2 4ç:ÔaU7COIÿYªì ÑêäùÑCC«º'ˆT)Ð’/¦òs¹…›ýy}\5ú¤;7l3²ÃsþÒ]Ë(®Ï˜A'G²÷œ8Ú ý’/¨„®ä)—…Ç'þ4 VI˜E³qÍ ‚º#ˆëª9vU»p‡22#‰®·p È+N¶Ûª®) àŽKë‰XŠ2-T®Ä¿ÍÒýÛìðÏ'/ l{7‰Ï"H6ˆèË"•¹ÿsN½¾zô?BÅæ$ endstream endobj 13 0 obj << /Length 2373 /Filter /FlateDecode >> stream xÚ­koä¶ñ»Å~«9ñø”¨š;$E‚¦Aqîðùƒ,i½êi¥­¤­ïþ}g8Ôk£õÚÁÁ€—‡óž!õîöæíOJl„`‰1rs»ÛH+™µ›81,Žíæ6ßÜ¿þ«MÛûÛ_n~¼½ùïØpø›Xš`R›Mv¸¹»ç›à¿l8S‰Ý<9¬ÃFG~«Í‡›¿ß¼Ãó4ŸŸg5S\ob3+:ïûï·¡&Ø5ÍVi‹g‘Ph¦uDHöÍ©ÊQŸ°¿% Mp+È(çg&Ù„R3žÄDíŸ[+ƒ¢íʦŽã Ùáoüåoÿ ÁoYŸneüÿk‹ªH»"§Yºë‹–†‡2%çÑêNÇã6„mMÛûu$rÊðÿž Ãy¿þ°µ"¸ýëïþÔyÈÿv EÌŒI¼ 1^ÖHÎÝ¥YÁ¶¡tð¡<«ÂK¾°n3©ÐK»ž+HG`Õ+|,ê¢M{'e”YãDÉ xÐy;àÒÓÖÉøÉÏÊ~O8¤CéPŽcÜ¢úBΚñ$öQTÅ4øáÂô»µ¬…§ ƒ%Ý7DèÔy,=N€Eœ â>5Y¿Ã×„á¡ø¼¦“•?*¥¬»¾Hs:Ý™~ÉއæSY?®žÎ5³“r/&,Ó&@I±å«ÒZç‰Z9Y¥è¥nzR R–q¡– tþq(Èu`_Bn'G·“ ˆðÑÁŠÌ£ÃW `ÅUÐ5´0óœöû´'`îäæ-=3èdˆÞ\Ve_Âþ•Ø*« X‘“q°;ÕY_b¾¨ @Þ‡8Noú-ƒå¹£0¯{»ŸÌ º‡³T‚9Ð%·¡Ò@¬l`¼„*6複´ÎiR•u±fE $!’¬ÕÛýª?bŠäèObRiMhÓù  ;ßI¸ÓŽÆý¾ å]SUÍÖ©|ÒƒÚ÷kÌ@”2-}nŒæ,¹è¸sÑármsꧦ÷ãÒ|Fxv¶eÓ–‡{g_±Dˆ¥‘ïªìú{Ú|‚…YÚgû–v:!I0kTž\ÍŽÇ9±§û5o*k A;Kô œKš3ÆÖ¬êf©¨§}Ñ&^¤]LÜѲà|”‚¯g's3æÞ ùAZÙ1wT\ЬüÈ…ÆSÈþêôPÕlI¸Òâpv 6EPM âò¬¸½c¡¢¹Àš"6ô,®Åm E$­*Hk& û²# g4NFDë­ª/´ð@’ÒqÐnÜ蜾tl TÊg»Êàqý=þöý7ßÐŒ|tÍIHå ùdkv½õÐÒØÕ¼ÊÒ«uÒž±³Œ†8õIê%KSú¥y—µå“¡O áOÚ…ŸÑÜë¢Ê˜BÖ‰j^%jvATýœ¤z0ª%yôlé=ͽcÛÉnÚ‹ °ILmG1A9z$çЈ`_+Ofè *Oà÷ÈQ ’ËP±8G-ÃæÄo÷?}ñ« I²XÕ©/ªª[ë?¥aÂÈ«ý§á rïH Õb,4ÛyÙºnD™x)¯€šp} »•a¿×MÀ…À^Ny0+ý6r#ØSÖXÃȘ‰… M²L?Ã-8lÀä¥yBÝ‘Å&HØ€*Ÿ9ëØR‡”]çzW>¤8\¥[@Z?zìy°â$š^8 ÂáxÊÑ܃Oxß¡år5™uÖœ†‹*DÁå…~|/¡Œ‹h/˺&˜kªÖ|$ŒË1|ÿ¼fÔhnz†÷ü¼[íˆ8‹&󯜉hìá½v³Ó(LÕ ëßÉ‡í«²KBLP+–Áž¦Î@TÊ8ä:è½ñ<%«ƒþÔÖΗ`Ü`¬~‡ê—A¹óë{èÕ #¿ÔÛà¢n 1ªctôµÀ1LEc_€r&víp__'6<›-z¯Ï)0O»3öÑÛÚÎ_-¤ Ó³ÀðgÀÎ¥føEŃ©¶ßPÏLÍk4мC8¦X˜ù™×HI“¼ÈO™cpvms ÑHn5Åï¼\pøJX4°¹}*;ç r`Mª!BÛ4óñ‹tÙ_³—ÁÎG^s_>b|䆟Žt•€ÙÑuñ¹'PWô¢êFÜ—½ÇêŽpû:¯øû‘šWtgÞ¡^(´­/Uò»\j"×TܪP^qçiÝÂP¿(­ =:òt‰ëÛ/ËøÔzÉ"Ї~tdêB]ÓŠÅØuþ o—.^J]/mšÅÚ¾HB-JXæØ–Si×3/ÀåÍ߃òÓ6§ÙXß&_ÑÎýw>’’Žõ¬ø¹©÷%z±Árž0è¥3œu…xAšxˆ=Í ´Œf,Æ@÷Ët/]Kúpd$®·P§À&}¼ÐžjˆÂXþ±þïb¶ÓñϹ—âú+[”]t92‚P>µ-çœfUùЦ8ÁKSGClXðBç-²ëôPùrˆ°OgøM›ckà¶6ã’kÀ®mV}r'…V-kÝ“À¶ÅgÄÄËÞWï/K»jxˆkn¯kš ™\B^.çš×*yß?õk¼BjW¯eÝ_|¼3S^¡c™ò%ô*«2C@pûr:§ ü¼šÎ%†Tĸ˜Ôæî@ÇéÙTª\¡®±}š=ö‘þý×C7ƒò€èìžù¢ X”ˆç¾)èX3 ¹iEñÀíµ–ôe ^cÝ€Û%à_ƒw£@ IôJÞýME+ô={ìõï+ܸk:x™’ÒÏÂók÷k]-âVŒ÷]@vÅ J¢/´t©…ÅN16c\†»¼Ø¥§ªA¡Åcц«1/à`Ôx©{3Ú’ž\K’ ®—uÃ÷?Z0ÞÙCÕ©®Õƒä0þ ï MÛ·i=\äÝ§Š¶ûê¯AÓ‹æš8pÛ\¾¤©éõè¹:Å‹2dÝÓ= \wƒ÷IB` j…ãÍÍQMÚ»K"ÎýÃÆØÑ8*gÉaiwv‚÷ŠÕwi¡ ãç‚ògtd4Zñu牧GõÝ‹É-Å¡è‹%³üx0~=ðÉâÿ{S endstream endobj 17 0 obj << /Length 2296 /Filter /FlateDecode >> stream xÚ­YYÛF~Ÿ_A ~ ;x$/± Ø F°XaÀ1m’’S¤BRO~ýVuUS¤Ì™Œƒ@쳺ί«Z¯¶7/Þ*åÆÈ`» d&£, ÒÜDišÛ2x¾û¥·§Í‡í7o¶7¿ßˆ †ŸR ËD$µ ŠãÍûqPÂøA©< îܪc “ ¾MðŸ›ß¼Âóôâ¼,L¤&âTÑq¿Iãi°4ž/…f æVݧSÑOMõ™+9_œÆQ ¿x¬šfàeKqU”ʼn_6 zMMç‘H'bÝæ„ÏCEñÀ×ß~K Ϙëü ÓÙ±n÷Ô?Á' »ºÝÀgdؾ§™j 1;\‘/«=7ãšnn…V‘ISlDZ'Äiùˆ‚ŒŠÄE&Û–kd¥ŒÒDúE»'“[Š1iqÅq öˆé8û*ÛïOç5&d™'Ø\ƒk§isGB˹ѕLB[–ØHÃá|bCö#Më—-Øu=¿{¹Éd¸ýéå+šæ_ö½ÝÈ,¼ßd"dõ¨,i$…Ѥ%£$×Á­Ê£\iâBmn…&üW»Q$ìw¶ÀãR÷0&ÃÑ~¾Ó‘Ò‰&5ç ¶d:‘˜(Î#Qhê–iHÍŸjU‡HOF"Iÿ:p2íuØWE·oë?ÑÁU,¡þLkïDZnG_äjxŽí$üh‡ªäé¿ ïF„؆@Óý0Ò‚¶ko‡©ºªû`{[€Öø;2aÃhûqâ$ nI ,ÃÞàŽÛ"wß­¹7˜p|;¿öí¥Ž–¾ýM ¯Ý F`uA½¤¬}ÝRÿ®)ÖpA+å©?[c ‰„™=ÚÜŽ„ÛC5T|ðåTÛ»1¾~ª)`¬£R ³ ó¨€îxpZ‡…Gûiãí çi[€ºMf–@FD ß½ùÊÙº©Y¡Â-ùO]ئ¹Ç`C19(±À™í½R)ñ’Á$I3¹Ì:‰`¤n‹æ\ò´uÂÞS§­ŠjlO•-«Þ‰/ù'n‡ïÉi@š{‚‚¶ +ÍÀÆ¥yf÷t4R‘^çÑè0ÁÐîÜcݵÁ.yÛ¨û˜g¾jÈ”N§Ÿ\ iS²vü…Û‰“Çff°ƒ½¥xÆYVk¬ÙÚ1yÞ굘h&¾ž½_åÝD¹ž_oÄMÓ ëHæÌ§(yöaõLY$iø§úÓÆ Î ÐGή Û’Y²t–Kh·.gPIú`xgeæéÑÑí(s@BkÑC-æÀÁòc¾jýꊓ'IÇÐ@O£GÛ“ø=ŸG†ËBœ²@ê*y™Á Å 5^säÌ/ÛÄK!S‚•Œ`#ètµŸf<‚ü³Aìi•‡…Ó%¶XÕZÇ ÌÆ©1[ðµ)+ýæ)˜„2fÏO…¦S86N¶w¾¬xºË5QÓøÝCPöväM–²58ã ¤V"Jt¶´šGÜ%\ ‹ß“»T±…x¡ULöÀgl=xú’kð¢Y …}¯^ÁI ¶ˆá8ÍÂ?ÝŽnžw.rY1—%^#8v.'UʇJ•yíbÓÁ6új‡šÄ¦+ò`ðʬíÇÆ//«¢¿›”4PóvJò‘6ƒ¬å³PtÁ¢c¿"ñê¾kåŸöaÎ ¥IAª²†´,*ÍEtƒdâénœæ`TÐüÜÝqú!w—:‰b=þƒ§¹žNB‚<X!Ñíé€ú·w&ní±¢Q¸%Ï CŽ„ W^!oÛ+—ðïçnô×píïë) ðiiÜô æøªŒðçóèäÒ±šÙܨ¥1ëÐ\ ôD(»3ÝT?<a’D?À V3”´hL¬;ø²(êÝ=T.@h0Vâ‹4ÛCQy)¤ÄTH%áPôõi¨ãDuæ°< wPSy³Q•ó5°ÿuY{wôÑx) †…3Qª.¾Ë…‚ò5›`ÿÅ‹§¥Ê|Ð3ùRÈ-©•^Æø ѽqõ•o:¯9‘wôðåžLðeŒÁ›c/ÃØCûÈ6¿à¸·¸Ÿ/Wl›Þwh/]ëÈÁ82FÐÃ?`á ¿Ù5LŒ‹+ÂL[$¿È¤O¦4„ÀwëÅ«KPÁ7øLg²ûߢuªéX?`µðýêS¾È"ü;C§p÷ðë7ÿõÕÙ endstream endobj 20 0 obj << /Length 2738 /Filter /FlateDecode >> stream xÚµkoãÆñ»…€~¡kûàë pô€I‹âŒöÃåPÐÔÊbŽ"’:×ýõÙ™åC¦bêÀ€¸œ]ÎÎû±ëw7W¯Þk¹’RdQ¤V7»•J•HÓU’E"IÒÕÍvõ1øå_m~\ºùéê¯7W¿_ÉUr•(X&…2Ѫ8\}ü®¶ÿi ¥«{·ê°2q ÏjõáêWïÜ~jº"‰&šöºY§*hÖ­’ hmÞ[ÇANÚÞÓÜß~Kæv½‰Lð›-zš)ë®Ïë®epMû5ü0žSǃ~o‘¥WïM8ãˆÉÒHväà~nÕœj¥„ŽR¿¨h‡¼Þ.¡Û¨8¡‘0PÂ$}ð YFÁÍÞ¶@å¡9ØÞ¶ßèj84Áwq<ózXÞòú_Ã(Ü6§ÛÊò‡öp´mÞŸZœ|³DøFå¡™“óh'Y¢Ø¼ÈÒ€Çûå÷eaeìéÊ‹“u–×Ôrýeá—•5ãN‚æódp¸Œ0Úvž6Vo¿$ç[f&e”ˆmAL3);¹o¾G°€Åíÿí—øeþu²ýû¹ynmeû²ñüwSQ²~;u¼¸*?Olwm»-ë¼} 5»ÐV' ·ªž”ÑÜ‘(ÀÒ;'"˜Úä×ñý£Slß‚7–ÐetÐA¡ afƒvŒ¬3ò¸Hr(ÂÔxGëÊÿÚf·Dƒ‘"TrpH')ÀW]C›ß:c²~luÛaÂ=û}ÉÔ€Ò¼®ÁÖ“¦àƒ`4="x8N1wüV”¿†Ò9j¥C‚AJ±2Œ``„1,¦¼õ|ëY| E”Äž¦®£P"”BD6à º|Æ UPᡬ-Á¡œ&9—3Ð4n8üó#÷á°c·oNïécî{Ì»®¬ïhb›÷9Yýz¶¦™_ÞbÔ¿ùùí;•RZ˜,fQÅ,*ŒR*sÑ?¼r9‡ðÁO-™ÜÐDHñÝMδÔñlФ&Ô(ãFPY _“šq\  €K¹—ÎþŽ¡ÀºHéP±p|KXé²Â1G§*]ˆFÐ} x‘ÃðŒ5 Yâ˜ZËÔ5õÖIQƒ„˜Y\µEÊìºDëÂè*³àöÔÓJàûÖÖ™5Àê¦'ÐèðRnQbÀk ƒ@.ŠKžœ '“HÊð:—e±Äßî4Æ' _CŒV\˜O}[[TyëÜF8L2Q”Íѽ­—l|ÆÄÙsL|Wy°ÑËL3¸rÙõ½ArÏ~ßZ÷i8u·}¡"‰2—®ÝDÔbH§—(lŽˆ5¯0¤ô˜·<ß¹lûÀA#Í„BcÆþýÞb@FIÖ” ƒ»ÒÅ3[üË:Š º”ù-eh Ƈ6ŒK3Å ¸`×0NP° ŽÎ à ¾T)i9ÄܲÆ/®CÒðËeW(¿_4§þÉÝÈ1J ‘¾XÚ-™T »ùÍ.Éš~O†¶ÑYBilŸu VnAý[“²pä…ÞÑkïWßæ”õv–$Tç1i2~9ÕÛŠŽœŒ`ò@¶Á{LQº„—ºø…=¤ÝG,xç%`pªL*^¹’"UCRŽ–¹†vbXÃeë%õ 6uaSº€ù¡C¶î<¬&à¬üGÀŒ]^ŒRÆ9‡Hºt#)Ý8p9¯UäÌP wL” üÁrÃօeÓ{(È*ÈÒ¾&sÊ´³¢™¤ÑmQa:tªL*u8Q%ÎpÝëâuU@]d†çžvüq¿Ï{?¢r2£² 9=蛆ù´-º„–~“ŽÝeÓxÆ™%~_ó³m™^²l¢à­ƒ%žn€Î‹”K’°Üœs:óT­Áhïvûâk_€Øÿ«²(ûŠ×1Ôº‚æ ä±-±>¤QYƒk8l¢4ÂÔͧ9Œ9wÇŠßwmsXâ€#l<˜ ëçTøô«¼##¹€õXMzLªÜ=ç˜QÏÝsû™²n0JbÏRX?J•~¢½“Ï.Í{[UÝb5"ÕÑÓ42º3¿Åô ̇—©“±PñPܓͲUÊàz8Ä:ÍH+Èà¥`{ZAß)ŸÈ´Od8US^A¬5OR긦o¨w"Å:Ðí PÛ–«w 6‘g™ØçÎx¨ÑFoFÍûN,÷}見µk°Û¼èÉÕV5õÝåâçÇ-ÛÑ$>„Î84'"Mô“5™ÈÂAñ£O:¼EuÚ"3¡?thW4cF “ m›rË!ÚBÙó,ïvÂd,IÚ:Z›çN«2ž €ŽrëBu,„ÆeZaÎíŽyÁ¯Ó£Ò?ENu5¶%è® ×&ƒÃzÔ2ãÁjçszßî° 4`P7ãÝ5Õ “½¦‡ýJì\Ëíôd%îÛ²çÓ` Í â½ó P^j¢Ç€®ß¾~Ý@±ùáŠ)MG‘ä;zÝ5Íæ{<áU_ôña0ä$R¤Ž6/£ÃDƒG¾>ŒÔã&$ârnºhn~7x”rwÀÒ?Kp¸kMžhÝc<€)Û¶!ÍR‚ŽsÖÎŒo5Ô{Ó4Á'hPIæî eÞµ¶?µÜ-‘5´hƒX ŠÁAÉÈ øC¬^“c bJÿ\gfÒ$ÈÂÊv1„x`)T=0R1ž‘¶PßÕz±¹ëî,%î»J`ÇZR0r Âïl=.zÔ¦cc°£ç´(橜Ÿt¶[Us(¶j}>Ý êh¬;ŒK¯G¡MLL,m4€TÆ’’eù7ÈÞ­+¨/ˆq~|:Gqâamï»Åšv6CÍ‹'B¥ãGU)€Ä“‚€GBÓ|„¡ùÈàõb@€NÇŒ;>¿_ÀÖ26»ªÉ/ö€ñóñ`$_ì4ŒˆÇã§§ñ\hXd MõWS@‚~ rN—øúJñœ.5bOÓ³1±‰Iççt‰Ã§ KD(‡-o›¦ºHXú|<ÀŸV/œd¢D •§¢øo´ˆ39¿w:ó$,A\:ö•ññ±‘|’ötªœ%â•§ _†x¥ñ(ù刟 >6 ´'ØAò2´'x¤•ý9‚_"šS¡’—!^k-²øO þØ·Ûr·[ >Ø—1êgŸ‰t¼t¹p³ n<Õs÷#ÚMÕ`ô"¤C¼úÉç ~è;] â)ž«Ñ¤¢ôоÿÅÊ ì#;;÷›eZ,Ô ‰ž´¾g·)!ÈFëç4Òq6øÞçšîgyÎç“®rM°Hö%:ØÚ]~ª\›.n\îèYÛJ¼ tÇQ°ˆ/‘Ý$Ö¶#gúœ3ê¿"-”ž—¹Ã¥Úì*Î1üýÙÉÝû,•2áäÜýáh‰ÅÒ2r<)ä«õŽoßÞ»ÿhi3>jAMFÌt¸ì§qpèItí”#uùÀScÏ­fÍRTNIDÐZc§Ãóÿ1îHfî q §=Ë• ˜j<$䜵e" Y?¾RRg£ë&ÏŽGÏoæøüYFìï¦gY^(⾘…›>Œ©ï>XTÿ&l…þ endstream endobj 24 0 obj << /Length 967 /Filter /FlateDecode >> stream xÚÅXMoÛF½ëWðTHE9Ù™ýN P¤ES=¸>(³ÐW(*©ÿ}‡¤HŠôÒ–bÇ–Ù·³oæ ùv:zq!1B¯5EÓëˆs‘õ¬uÑt]ŽßÿͶ“«é»ÑoÓÑçF‚Yb3R:š¯F—W"Zðú»H€ô.úZZ­"e_—Ñ_£?GoËxtÏi m"ƒÌ!Ü.ŸåÉ*YOÈŽóI,ÉŒ_¾®®Y’ï³òÆ—‰VãYV zq¡Ä±K$!ˆ£–î^W6ݰh€„©M®÷ëyÈiåj«„A_„VµÕ,û´ úReB[_ø*ä,F¥@šâ J™ÊºÞþNÅ•y^œÖ”v}œ¡óà\ëÆc~»MÉõ$Ö¨Æëý*ÉÒzOòø)o=5ÑbœÄé"BZð¶ÙÚ@bµ…ò‘ˆóÍj»Lþ AFA ¥|RÌ´ÑÄ|ý1ëÓ1Ï—³Ý.„Q*0¦©çùMº\ àãBЦ!ÍËà†d[ån¹{^çC^=S±IÑ/á4×Ö#¼š;^e»­.¦Þ\/ùÄei,·r`е7¾Eº=‡zËÍ—:Ý0O7ëwÿ€«S;›“|˜~øõ÷eÀ›“ Dj€¼§(nÒݱ5«^C1$Žîõ$Æo†µ´Jò›MA—Å`Ò‰•–‹à쬯“¯¡ø¬‘²WzC¡=wªK©R=xEàAœl±BãXgz4@˜‚º$Û¤—‹º·\”ïøäƒRM}ýô‰€¤[9D;P,õÄ¥ØI,ѹFÀÓÍn[Tâ8™W y1ËÜÖ‚<‘Žf~™eCÇd-(­ÂƒCÚ kkŒÀ6êrŸ ÐRsåún³ïLiºh„±¶¶ó`p_t}–†fvRŒ^»*éö¼t½Ýç!ŠHǵ¬úÃÙìóW<ØYÔg¸J×›s@} o‰ÏÏ©kŽÙBJ}— ~S‘qØ›†ºlŠÉXMÕsÝÙ;Iây4'Õú±„ôš“åöGg°ˆßX?–4ÊB`yªªI‚ö5¼H?í³¤’>¬§öÎ7Í£]›ÿækKß9¿¿b‹u>[.+§»ÛêSɬ|Áãà„/Zºçs­ŒuýõæÍ1- endstream endobj 29 0 obj << /Length 2840 /Filter /FlateDecode >> stream xÚ­YëoÜÆÿ®¿â€-/ÑÑÜk§l·Ø «èÇ0(’'¾#Ï$O²ü×w^|(Y)âîìkv¿™Ù{uqöì£VJù. õêb»Ò‰ö“d»Ðãdu‘¯Þ{oÿÛ¤‡õ‡‹_ÏþqqöùL­øS«XÃ4åk®²ýÙûÁ*ú¯«À7.YÝÒ¬ýÊF |w«wgÿ>{…çÙ`z^b}ØUÆ~>ï»õ&T¡×ÝеòòbËýê¸/š2ÃŽõ¶»:í"û±{ŒÁ-ôt×Ò´íF[ߎ·ý­ÉË*mîÖ£#¯ÍÒ]ڴ؉½,…ƒªªî¸{¹ÞÀÿ‚'Û"grÚ2¥>v‡cÇí´¹¶ª5 w­Ï¼X3åEÅ~:` XQ+ï²uxÈìâ"ï€Ýº¬º8Z¸Oø.AŽ´:mµ8†eÈ'¬£ã ºMy]ÍÃݵÌkЬ¾ªÊ¯t˜@ó{iâÙ¡)«¶Ìà›0‰¼‹ë⎇å@¸mÛ²\¶¯‘ÕÕÆ%~h¬\0b›b[àÝl$ÓN¥bØ×p£º*–®­5Å0éfZ`¥U¥—»âlâ%ÓŽ*Ûs$i/•g†\Z÷{åõ¶øaéPû:É𜙗(ã'nØlðÓ­Bp…D [µÌgŠŸûʤE_”McNå†÷ž;N”wÎ*бñãh®‚ÛkÐ.l}͆ZŠñæåï2E#6ËÄmSïÅÆeV*™x“â\qœßƒ0X°”‘³O$üþâˆ¯Õ bØP-zÎFã}bZ3ßVƒ]27üV4Z,{kÌÜ‹àBd«°°0 ݇&LÜGŸºŽî¹ÏÒ]äðÙU^®uè5Äxz·È²I|•èžå¶«‰i«G¥Q)¯Þ2}Æ+ôç¼yM¦®nÝ»: ïS–Î5q³0Jñå°+³²ÛÝñ±-ZqâZ•%¸f‹ !~X5¿n^R¶e]!ÏQL–D&õX!·ÔJøJ@9kŠîØÈ‚™°_å§Óœ¦éœ>ðñn›¬ŸÄƒ{ïm·¨›ÀLÔϚɊD`­õ2säŸ Ð%,Àx`ÎÔQRèÀ®U‘wIwQ–•s8 $>ÊHYZñ¤t×ÖÜ£’]½O»¢_ÏB^úì˪`Õs¥14èÞ4XlY‘X‘–§]Š6(ïŸ[&ÕnÌ-Y0\‡éEø=óMMb+ó"‡kj JÆ–sÙM´©HJHùÜ/¤±ÛÕtÝ,í–ïÓñ¬Þ÷{üÍšl¼‹w³e!ÞÏCi 9VYGWB"¡+Pó"`"5•¾ƒÝÂŒTVLQºu#ÃÜåì„Ûìbµ8nÑO¬úCÈ€òúô0#!sw,.É2—®÷¯ÿ¼ys¾난ûf¨H ÿ¶Üí€g0­$ ØŠéÚH)ö‡N®ÝA‘ܽL)d}âŠ×¾}‰¡îâÍËW>ÈÔpõÒ¦ñT´8Jæ&Ì fpJŸ»$‰ŸB"àD¿“Ô´Gˆ/`<½wh€ÿEyêÀø‘rOI”Õs™N‚MÑ@Ó}¤J»Éé„ Ct™G?h#HzôªfÑ |<ÿ@¬u¤[É,ÖÚHÏb-öQÅø…)$ŒðŽè)r{ì³–õ>¨ÏŸQiØ»½®[9÷õ?Šé±ï’x®òCSw5[Ðašú –ÔŸ$3Ø•Ÿ)–ÒŸ¥Šã¦.s®]jÐ á×G¼ØF¾ 0»ãQÉFÿÂ¥ b*Âþ*)Ð^N°D™yBýýtá[c\€ŽT9ÐJeÕ=‘v=U$¤zRsHÃcQV;¡gAq¶ÏÒ ˜2‰† P}?6Ú ˜ÄF@ƒ(d4Àâ# ^(¨‡ôzËdHÀܺŸƒ#•´?àl´&í z¯ÁSÕùfLGÇu[É¿”&0¸·ØJQóZÄV-غ„ 1´!UŸÝèu½?ìŠ/OÆ ÌŽ56€Èš²;Å>£ŽÓSØÍ!ÕU¹…Q,pZÅFÁÎ9ÙvÌ ˜—mW‚Zd7á•:á´¤¬­ÔNdiáùèë´×Öû‚[¯°_Çí]yÙ@Jݼ@ó¬dâp uª‡µõø¦ÐÈ¢›2•#ºæ˜½hÎÎp…hm 8cëv0›Mv8dëêBlõev³´ãƆ¸%o2çÛн@%œ Ó+2G×V÷sÛóź<‚l‡\ûö/0ÖwêNòYÐ͘ÒuT öø0狌Å­ƒBfËêj'™;†è ±§A.Ò'±§¶´t³|a àù#„ú7½YZª¯•š¡hÞ>y»É;€Ö¦O•­d}äüÚr¶…_Nó ;R07Å/ùް7£DDjÚNÓJ–¯3"ßÉ¢Žî ¹HÝMè½å’†¯ŠªhHÇ€XTÞ-ÇcÇ<T¼#4¸]Ø}ÙqdúRâXB 8ñ:+ÝQ¬ <õ–´…Ñ\«Â¡†d *chøË"ky!×zÍ#9Ï9¢ÀíÀ9?VC݉¯¤òDjµ ê1.ú–•i?Ñöts®g!åpæä•éQ³†ùÁPFÃÄ=ŠzMëý‚9=JÇÆ¹¾¤° æ­ç|Êë`l(5M¢Bê¾¼º–ü»ÇVè ¡±­wb(D"õÇËLÉÿ…Åú·”V»Ð;ø›òg€ hO,+ôæ™ãRnºékgkfBß&vò.ÌL3ä2¾Åçc)YΘé#'µ|—c‡²j¹èI3Í€·§¹1q{]T†¾ä+gOÃÊãñ @.6ó°2}¿Œ)QÅìøùâ™ h¹yþ='ÙßAR€qÄD ? ?/yû÷Ë¿A´]þü¹¬û‰ âg¶XRê‹õF…ÖzÏž1ñïŶ¬ä¸”?–b<à SÂ9×x´ò†]š"Ý}¤³Ð<¾¢$ø¨¡ëãìñ˜ ’dàçeEA[#jáf[ô?¤ã’s¦•ûôêœòƒÓ¿ÁNYàðÈѬ¦øü×\ð‹šøRQDôöø'þ:áë¼9/GÞ~øÊ“þ&—œFÌÈ<9I'Jõ£?Kå3^Å žZ¹]Pí”8¨Ñ²¦æ¦‚²£W½%7V‰?â*êîþsZ–@”PILžðÈ/tÆ([xð7:­œu3í¥Õ·0,À_"„·ÅŒ˜3¹ÞÜN¸O ÈJÿ9Ü'€žù¿¸‡².|(R€ªña ííþ=L i+0ûgÜÃĉæqï_Š$jþKX–ùкäÂp¡*År(ˆžR•ŽJì£éb!ö‰ÕTì$Ú;ï¶)»‚›±[1µ¸ø‚š†ü`‹ÝCÚt­l´•©üYÈìæó¾ u¾³OÐSóÀDÒÅw徤·Z<‰Ý˜„a˜œcîÛ؈o~&Á*³_)ñ'¯ãò*Iù$?DŽ¥} blä—ìZ©/òcÖýW­þ÷­ÙQh¿}ÿ&DøBÏ øæVõÏžÐû§t f4˜ð¸¼ð!uR’Aï–_,ñ‘ŽK9 Ù0ÅTLïQüćÝ1óBf¦·£_uo’]œ¼t‡§¯ø3@Z=ú›)o+iÿì"¿ Æ^›ÒC+w(;~’ ÁË›l$¦ÍJw¥·ü«^m3ž†_&G¥h@› ¶hU¾Nb¾HÔÎÿਪ© endstream endobj 32 0 obj << /Length 3108 /Filter /FlateDecode >> stream xÚ­ZK“㶾ϯPU¦Ê+š>âÓî&®ØµÎ&ñ¤|°}ÀHЈ¶DÊ åÙqþ|úERäpvÇ©”x¿¯¿nêÍíÍ_¥j¥T\Z«W·û•.t\«¼´qž«ÛÝê‡èÛïƒ;¯ºýææ¯·7¿Þ¨U?µÊ5tS±6vµ=ÝüðS²ÚAý7«$NËbõ@½N+“WßÝüóæ ­W¬”‰S“Ñz8‰Íã$Oy-ëõF)m£ïºPÕ÷-®ûÅW&½Þd²Úh«,ç1“ž©¾îi’8Ó%  Ž.øõÆ(½Ý´ÝZçÑãQ*êµ.¢Ëñ¸é|8Uµëü޶Øíà‚ÛB Wµ¼\¼ÞdEÝü#׳·çõFùmõc¢L?Ó-Èùîàe·á§…ŠUªúírŸŸjc´ŠólµA“qo>,-RK&Wkã“où‹BKã$KûŽpN£uôzqÊ$6Å‹¦Ìb“ç}ÇéV7ºÈ¢j rãlÝtœñ¿^ªßÖÖFîèkBõ6ênwK[R©3[ {‚»ûá§gT#ÕÙâ–^ARš¨­ê­—%²Ï£ëH°²’ wÁ“ÂÀ"«M Kvv7z¦*‰\-iNÔ‹ÍÓ^ OØrÇ; -·ü˜Ø$øs)ùV„Š…£ï®frÜ}×\îPµ±ê·5éb×.W²‡o_¯ ݾ{ý&W<®o{8T¬ø\ü݇FËAî+ž¶¦C'ÓÓÖØYgÑÙ…®Ú^ŽW†Þmu_ÃèUlÈ6¦Ñ*­-e ËSÜ¢¼“T'_·US·XÖÑEˆ w½ö`- +—5Âê8¿Òˆhi¸4ªs¿”ÿp>VÛª;>òj ïz¡|±µc@€šÉ^‹HNTx6>üF«‚ôu"ÁïoºPHÞb’ ôp]¤—–r{ºbèÖ\ºó¥{……‚U›ÛêwÉ‘¾A*Mi´mBðr¬¦Þ kÌЫî.pèõ0,A³ÑY¬Õ§ 키u W2<¾»´Û¬Ë¬œ dз/q%<$:³MeI)–”fI©+I)‘”$¥zIiPø^P¶—†¥DPzlZ”FAAiKiþBÚCs9îø•Ü¥ã“çÚáÀ oD&ùzjE*‚ÉþRo;x(\bl2ÑÎoáýá¹±ÄÈi¢à»K¨'Ãßb’"ƒy‚ëeñQ‡ºÍ 8 ]Ž?]÷ïÿ~÷îÕ²Ó±-óOÚ8SÆYjûnÕñ(ê @;¦pqvmËr»s¤³¿p‰ï ¡g놲(‰e½ JÓ¸ÈLÏCRá!ïá^²4ú ô%däýÝÏ~m“hèýÄêY1!$øYŠ¡rÛ-W=TÝA0€ì£¼?×ʘ™¥‡  èdl êɳOÇgü¶¹¯AÛ@*Z_N[m^Ðò4a¸°9ÔD;O^ƒ‘{\”A qм»MwÍåÏ›éè?˜€*zÏeyÇü€Ö 8‰…ýÜèiC_‚Zì{ônÇU¨ëXÓ6'ÿpp”:0JG~·J ½»–ÛK rV7Þëähþƒ ÷‹ê ÚisûIí¶Ilõ`ià‘V;ºw[,Û0è?°X‚§'l\“ñÒ+ œLåêc”<³RMIùœ)ê8IÓ•Ue\Â\ÂΡ€¦¦ßY5’ÝcíN@$¨ÐÀ-•ÃgÄ)õ¹7X…ºÖúYèÍóØM/æzXäR{ çPµ¾å»R%ì&›]VµŽU õöÂb:a5WäÈq"„Ì:‘)A;ÑB£Ëèk„L\%)ûq#ÓÒ¼N¾;4¤ËÂÜGgÜeHPËÆÜÿùö F Oî—õhm£ä¶9÷Hƒöm?QbŸŒüÔ>n”;6Ò ²èàao¼Ùkh{©ÌB›@B[¨(^Ü%[8¢.ÜIÖ ~ï9­·”,2y°ù§Çóî¤|†Ö(§˜ÔCÍ•Z„<ùaëÏ]?ØIîá€sÖ\pœ\) ÌÚëktRÄE2w&„N_”A³ †Ã.#“J p.ýhJGj&cF£ÏT Áy·ÛŠŠµ€Ûe ßVìCc°dÐýÐuO·Kœ.8²^|p pø™‡Ë&µ—!VrB£üÃLX'÷3¼º­ÿI»H£3šªîÐ?[!¸ñ¹ðú4¸z9 ]%&:Çiû±ºXW2$å ¡ÞT;.N¯+öœòñ`¼;ŸC Ò—–KÀAaºr5{YÆ©šI½w=§~§6£ß $ =ÄSÓfÍ>2¦»ŠÙðàÈã ûМ¸Y®Çò»;áû;Z¹E;yj\#À2 ÐpѰ6ž°p{íeapÃa¢XT!adµXÄS`‡ÏZÉ›Àf·#fô*ɾ-{D™¹"†÷`vX¯Ðo´ôìq‘ÉAiÕ§}yCzq {©m1SóáA fOæ}QóDQ£FtïkXQÇw<†%¸Ú‡Ðq?̸{‰lTšÇºÈžúDiÒ¿È<ÀžäÒv\³,.-±È¸$ÅÌ®AÅ¡‚m ˆ°iÒ‚–ÒGKx‘©û).ÍZ ñé2mÈ^âþ”zkðáZÙ%;t®ãÖârä)³±ÑùÌĨHOT¡‹[×âÂ,y…¯ãlø¯¡CúòíanpWi¨„«à)œ¼¬à.]s‚‚ëu$‘!8$:ú óx§ØiàÒm„j`õÕ)C::NAñ€ñÅy.¯ùOpkÊ’¨8–ˆ¥·‡ ýlÌþýÙ©W\I%èÞé/IÔÒB?ÛÅ»b¿èj“k<  JÉÍ£tòÀ©bÏé'#¼ òz wóávŽîháó„KŒ— äjt™©%bŒuà#ÿÿÚ¯NrpúÈÍ’ƒ`$nÜô$8­ê¦¯‚‡ ¬Ù¡’îúa[û#q”;yW·ófqíaë Gç”q¡ê†H„D­8.&™á¦Iúmq¬jvÍ&Xd)@FâŒ@é„VB×KÀco {¬ÁHžá5ÿΔ–8Óaèþš!‹×¸`ú‡…Ff#A¬„å„Ú‰j»ÁHÍ|¢ìZùŸW7»Ùù½Z4¦™‚§`_ÆÎ‡H@×/Ì»nê óŠù,ùÕ#64D{8.<|Ï2Eý£,䲯$,ASÓ›è( 0¨ž˜Í7\€N`Õ¤p½ªìø¾šzXÅ…Ý2»€yÕKä¡ËrÆ-`wDG×î(l'í=ruOjQßÐêziéÃq¬PDu‡áºþÙ€ÊÙ½#ÃÈX¸‚&ótDã‡s1;¹ö)ꆘ–o ˜ ñÆÛëI*Ö«ÉÐüUÂÛcW§ÒÙ+Ú~jy:ª Š|°¥ø`^Ħ´SÙÐìð /ÕÀ¥"á@Åãn­ ˆòyª¢¯‰Ú"ÕÝчYÍß1½´^*LÜ-ø¼WOô¸ä cõÉmC³h™2تÔï_:IŠ÷ïŸùf¤FÆ6¢íxúñz@}†šl#$æ–ÅÅL>àVϱ)'Jï©gåË ‰‹b`Ž›¿|dï¶Œu6èT׌«-LœÂæÆÈõÉXôb€/Ù!š²mNçª7–Ǫö‹‘w$|q‰¡* À0ã.ÆÎiçÙpº™7Òsœ¿Ž–Έ›½"D^¯Ñ¤ØÑ³ì̦Ï~Î&l]üö—…ùƒŸ>È+k§ßoF'é³–¿Eß­1 …aJ,5k‚‘•fi—èÚ3Pb Í«ß-ÿs 'üi©Ó_†ŽXübOXf/ÿdº.xÇxþ¼düÃÌÈ`¡À_ü0ç¤}ðã,¹ ˜ ¹¢nýÌÅ03 é®oçÿ&LækžŒÅ]áÑ_1!( ¸`Áž…ü¥&ïøÿ”Þ › endstream endobj 36 0 obj << /Length 2326 /Filter /FlateDecode >> stream xÚ¥Y[oÛF~÷¯Ð*µÎð¾}r‚ºh±í¢¨>´E0G‰T‡Tlï¯ßsФéÔÅ"p8œË™sýÎ9Ô»»«··±Z)–iªWw»•.tX«¼LÃ=¾‰¤yå1ßÕºõ&NËÀtðÌ¢ÀÙþìžû¼N“Àζ ×›4N‚ÿÈBÝœÎý5røö6‰ÆäU¦Â¨Ì€¢~|¼qÎ<ñÎ)#IÆ™òëŽ)Íé´Þè"°Oô-?ß3{ýZçÁÓZ²k‘ë2÷¤·mÓõÀ¿J<;o–ø)²PéáÐ7p]ž­Üž{/ñj“D)˜L­6* “$àŠ8ÊY¨ŽÀãDXYØ-T˜¨b¦±7‹<¦)è¬óB™Fȳðd^ãªú?øRˆ©Ê9c‹¶,C­£ƒ³$º n×…f÷‚+ì£9žV˜ê÷–¹9Ô ð³hÅM—aªòÕFÇaVHh|…†L‰8ˆ®EïUû¡k¶ß×ÍýïQy¿#«×Íãî¯y'[râÃnƒÓê›%7J‡q”;åÈmu>v<™¾þx@¹ÀC@í*Øó‹á=»s³ík2¼Uö÷H% ™÷t‹&_YÌì@"Ìœ=mœ(áâd´öÏD>~j{6Ö`MƒNÇ0"kÒxoMeï@Q˱GažÄƒ“ÙÇp¿ÄBœ„y|Ù†(pîz¦þœ9÷×ÖÍx8œ+Ò,LìZçÙ$kÁhd x«ìö`œñ1C,ͧµ'¬!Ìz06’<›B@g›Î†´Aåaš–Óå;rú2èÏ­Æ=ÉûÙH„¶“Ìs™J À [l Aë™®ã)ݵçû=¿×~¾eæph‘õ~í$ö·µ9ÀÁú¿¤(Ø$úº±ÜÜŠ¤ ’80-*%þ`P“vzë J3]ß:s/ËíŸyðã ‚ÂÝ¿oÞɦ“qì9šÞÕ[ºv¢33²ÅYàÕÓA„= E¸Úù›Üy g;ô`ž«cð¡ÑT€}à(ÉÌQ‹ºlðý¾þ aÅ;Ï'~²Ä°‘†æøL.ÒÔ¶ÙZÞA²¢2öâñ³„Ÿ—a” >äúgX…*òãΙ#0ZpŸø{èì(]Ž+1N2O]†ªËAè¤qÎd`¸Þ(¥ÓàæÜ·”!V üg]OžBDe:øÓnûn‰5Ц֡ʄè÷;s´ˆfÃÆ€yÈ10 €kÞw®=ò‘ŒG?÷Êô†)Æ–;ÛÑEyðþíû¯¿æÊB¶Rü²+Ùë%·x"ýž!}Áö-< JÀËà :•Ýñ"2BODÀÃaÉò*ÍÂT¿Âò *‘!›zÂr¡Ï>2#LASoy9dŽ Ñí:€3HĨ±¢DŒ‡.‰st½ã(×Qfi2Uǃ Ÿ8 ±‘ ¯–„+”ö\ß¶í’h†E> ‰®†©·@—O<;Ž<§Áw`Ï‘_Ø}àØ}p…ÝWFùø¼´«M^„y9CñÚ5q`š0`­ -ŠŠW¶‘{Ò¥*Ìú«³_ÂÇaZÎü½“4ÓTŒM™ M`ÐSêõMµ"T.À’øŒK©Åaò£Ù¢ˆŸäôb­uÂß+…Ëó4ô=+\ÜR³Vß÷Ÿl‚‚á|´ÂÕl  ë‚"'šAÔjÓ²íÀØCÓ¡† Ž·N£à.nzži?þiqî…Ü¢ ]•¥ BîEI‡{« Z¹»iýMÍŒbFÜ×ðýVyq*ìkT ujTCW¸³F ^º=!¹WœAzT3 a¾Êb wfÂ2¨>cpŽù…¹®uu%S\’ÚSǯ†×Ås‡*Œ[y:»³Ø.qB7´£ã“ž ò®”¼ :Š2žÁ¡´™çOŒs*Ê´T¡›Ñ!¬:ßùòŒÚ ƒí¥È:¥ê©1Ç5Y±„E"[Óûމº\ªá×QP¼\‚EÏ,•ÌHSç,ß/õ¥øCþ}Q});ë6³® `á¶û×b“ ¦SÜÔ}#Øg1ô¾³ý˜þbƒg¤·}îØî{#´ìÐÝÍ­6%s¤ ¹\xa§}‘ÄË7  ­§ñü`Ê?·u5;xë¬ýÒݯêËÂX‹“=‡¾çëdžr èûƒån·‘cŽ‚]å ö¸ÔÈsð¦YBKfE"rIøœ—Óahì’â¥ØZð8×,»þÑìS‰B¼*ùÚ׋s(s.õØÏ?AZPùÒ@kP¨k{(ƒ‚xΔÓÆkèC ž4Ž2טB,PH¤ÜJ(CsA'^¤Se1næ1„ð N e*{ÄsêYt.ÌÀFëÁL ÒlÏ®ãµêìH縈á<àG.uö5f“Dx…Á+¹À‹Vh03J3C:‡ôŠgA/@‰«q'sFŠX/C Ql»Žšo©yú*—RU€;ÈhxØWD¾äðˆ7$£ÊÛ‹Ë;Ä"û¡¦Âoc¦§Zh/X.ßQP;µ ¸}z[{¢èÅÂP@¿¼Ñ ´œßúo|» ³Kï<´Eß¾Ëâ¹sÇyÁy,÷y:Îå‹4ÌLÓó¤‘cþ3#ÍM¼›V?‡í9}lOéc»÷khßç™éêéGˆgQA¸n¥ö<žkU#þ²V“(ÌÔ 1˜_Òk “'ÏõšàO ×ªhÖ+ލÑÅ_"ÆÉž— ¯4øÙ†¶Ú£Èìè+.r E9Õ ÁFDt„¦wªÒÁPèš#C±št¤Â"B5•aáµð?Íüeóºé endstream endobj 39 0 obj << /Length 2972 /Filter /FlateDecode >> stream xÚ­ZßoÜ6~÷_±À=tÆŠøK”''Mz-Ú;ÜŇ{èz¥õªÕJޤãûëï%­ÖÚ:AŠ&—¤È!gæ›oȼ¾¹xùN‰•QfŒ\ÝlW2•Qš®lf"kÓÕM¾úeýó¿[wùëÍoo.>\ˆUŒbe%†‰Hj³Úì/~ù5^åhÿqG*KW~Ô~¥“eµzñ‹×~=y¼^šD*¶+kl[ÅëéèòJgñúfWЪ/ßéøøe#,óØý'î][ÿ}×4<üd…ÃÓaüöPoú²©/¯¤°ë²£2]º"çZßpO^¸ª¢º]o\_p§ã¾¾Øßûž¦uí#wmÚÃrp{‰ÎÇ%Ùe’DB$sé¿/úsÂ_)k£$NVWBGZ'üYÓ.Ít”³©¯±‰Í¹É3I› D4ëˆ4’™\]É8Ò&XiâJ¥fMûN×MY_¢è©-Y7[îs‡¾¹Úàh±ùô§hý‰P_s{yeÌú·K±.6}Ç–¡ìÑÚpµ+÷÷U¹}䯰>é¢åþ¼èÊ»š{·MhܰžÐÇýÎÑöîw/HØšŒÉæG¹+œ——VŒ U¦Pö»²¾ë¸³*Ãl¾çÍ·ßr3ïuÓ{qб©\×yYðã?±‰YPŒ,>9l¯@› ÇòÁb\÷ØÁ¬¸žó~0kYͬ?‹¡5=h­nú%ÕByq¦†A÷mã7Yæ Òï‘hoMìüL:·§qVAzaŠOåmYAEeÏfí{\Çe¿ì£gMø1ãuÛºÇ%I5”"F#ôv¢×¿á8_°2ëK·¼X-û ºº¹¤Uq,Ÿ$—¥Ÿ]ñáPԛРå²$sè“Y”ªYFÔ;•ØÄQ’™aØ8Ñ…ÃÔ&J¥ž&ŠV1tÃÞ”}õH¿E îsuΕ½«Ý]Áf(S’= E÷Ž|©lÃl£Û¥ð•Μ՜|¶m›=7ý|}™ÊõÍOׯ½ôqÛÊïeœpö}Y¼:½cۑɺ-*ÇDa¡2X ª‡:‡g ]99·2ëïšú›ž¿â=…z®ºÐ·köE -õ(®ohP‰RQ–Š!,&—€giÖošºƒH—¤ànÉDñ¥”‘€cð½%RG6í}siâ5M¼4¡Š#£G›g ÈLnÓ‘.¸”=°Éçx”MÅ0¬-¶0ažÖ›JÇÅ›—Œº6`îI 6­®Å#6áh‚]¢…£D¼¾«š[WñÇ/að*¼€²L– gDz·ˆ£'^\{H”IêƒL,75LsAµUhôÄ‚FúûCÏõÎêÃA€Äb6ü+L¾ÑìïËÊs 4ÁŒJ$ëwäµ´'ê å ÉÆ™îÛ1>ÓOÇE×£ùnæëD=K'º>/ÚvÑ4’(£½`›~¼õ ÎòЖýb´€~0‡™sŽ¿@/Q»Á±Õý–B©W/w°D/è‡^oÂì«%º’uëýJ~e'¡¦±Ø—MŽxæûþöýOoŸÒ`‘€`‚¡é,‰¤ÐÈ…#-³9ž¯)¬Š„â¹%¼ô›Ÿ®ß¿_ÚËF·!ˆ_Ú†ˆ„9 Äßýý_¯—¶âH÷glCUd&;¿9Ç•¤~‚\YÁ(_`f†¿u‡ !eÁn j?R¡=ÑE¶€8‚É(µ´¸ŒGf„¨Ì(¶aªŠÏ©¾S{×õmuèü™ú½÷öˆî<Ѝþ7Á (Óq“Ç3”!"đؿ¬GêÜrʼn׫¹ëÌþ%òDcž¨\{¢Áä·äÿK²‰XáøÆ¯}†G¸Ô-¦™È€'ï:ïÿ)¬UêO9jd½ð-ó¹Gm"3‘üírVx¥†¦sëÚV[ô ùÀ2¦éiЖVU|ZŒì"J…]ä  •p…l}rq€ùòR$<Ɉ`ßüPtU™³ÖO+¼Ï»öÎX÷!" {yÎEL Kè ¬]óUz31ô ÓZ£-9Ñt ¬ïŸéØãaç›Åƒ#ý¡ô N};’.E×ÝÁÃ:Ê-—Ž»öe·wý†|Wü³ë+°?ì›Â—yÑ“X}FÃC+ÕÛ3‹rïùH’M¼)H<Û"Òé—!>Ü8Ð|”C¦CÞÉwÈŽ[¤oe;ÈD=' ”Òîÿ§(,¹w^æÜý‘[]`BO¯–¾hXU,f­àÃÉ”µž»‰“Ñ=óæp»<åeQœžxè,˜HÏ ±‘¼û¼L!ýFóæ¯×ÿ\3i‰Ñépòu|Ƥ‘²ÂÏ•(ûÏN Š.1z–»œ@<гðnÓ Ï)ºû‹ö×:X^šŽ’…0êLØÁ™¤iöÜÑ)ä; JR˜Ç×@ŠŸ¤ˆJmŸjŠkg"H#3íaƒ£X¼9Ê<ý[DìpÏWçãܦïðàb|=A™$JOiM@$_üN—Jõ¿ K8 ;²¢¿<œÑÈ£@ˆUp>)õ×é*!® ü\±œñ]/×}F÷Fs¬§“±ž~ X/3KXÏ'œ‚r5¿¹ñ@ÌÀæâ(ˆYL-qˆbˆá›)Ö_Ù† ³p‹‰Þ€÷¨ 3â½ 9=ºfx¿”–îÆ+þ9ádi!ô ·_áNæú‰¯Ÿƒ~ ’Ï{|h$>g ú¡-| &드•Á½L°®sÞrî"L> _€c¬ ŽrÃ55}8bÙš2ã¦õ÷…h¾weªŸaçÉÜl$ôHÒÊW‹.8´óÆñ´Ì‹¥ÙµŠ¦€Z.Z?RòiDÖÕ¼—2/ã »5².jõ7ê4¬köÅÙ#™Øë|¿)Ûô‚Ô/Ëd´x"/Nä'Ð:G) af¶®ë»QÉ/BÊ"•ýŽklը̦K¨Ô®ß·u<ޝO¬=¢~øáò|˜ÛûÓñÌÁ¨Z†oveȶ|KÓæÝž¨,^ßú”–§x\rE×|ÞûfbY97ò" å†îê ×1\ÐM;­Â£nÇ×9ðGƒ?ÔÃCB®ì§K-•êé&‰¦(ë°$ïYñõ¾ o1ôíÜ ¨‰OcaSôÔTìÃØáNj¾uþ5wÍM&-*¼÷1X—kÃ8º«¯bW•·ü6H?îÛ²i§×´x™Ž^9}c1ÁÀ©¨ã% á?ƒ«/ë%$CÎ…”}ºáð³¾,>"&~ÅÓp(Ápâ„ +C¶øuY¬Dà· .„,“úW±hÿ°˜ìHL)ŸK:%²ûä ·…45²Âü)Ûð!ñómí mUœÛ—ñkAäW”|(B¶ðZ”FÖž$L®9­ÃÃPrœÌpÝ>Sé Yå±eh~ÙXb~&‘š/<;E—‘ ‚"Ñ€ð¯K)±Jcãç"¦ÊÏ’•+ësG‡C™Þâ@‰]ßâ\:Þ§ãÝçDCTÑ>¨'¬²sbä‘Ä/Ô@[˜TÒÔ«ËÿyÜ¢&>_Tø-”já¶|ÅmÈw3aÏý‰L˱|Þr1Þ¤žŒyç±>ë¡wå ïÑ3nÇ-žñ ›Vúˆ U7ØKèÝÄ{ÁT,€/jM¨àÆÝ¼Pðk8‰YŒTе·ePnþžº[>ìŽû¡½ÝÀû]ð‚œûíÐ…G±á´ï`ýüþ(‰\“¿Ð3m ²ÁlÿÑÚ¦þ endstream endobj 42 0 obj << /Length 1595 /Filter /FlateDecode >> stream xÚX[oÔ:~﯈ÙC×ÄŽ -ô„X‰‡R¥‰wÈ&»¹´gÿý™ñ8ÙÍ’Ò¶RcÇ3ã¹|c÷rqòêƒÏÎY¬”pKGD‚E‘ÆŠ…aä,2çÊýü½N6³ëÅÇ“÷‹“í w<øåN(€3!•“®O®®='úGÇc~9÷†kíÈ ‚oá|;ùzriôE—̗чBTȼÐ']ŠñÙœs¡Ü÷w3Ÿ»ºÄ¿ílî‡ÊÝvºÓ4ìš¼\Ѱ*2|~7‹¥»øôî’æ_¾ Ñ QžÐsæB0„¤ðû,.‘ïÞÀ'tõ*/q.`Ó3ýÃã²4ZqžX}‡L`¦ˆÐL“̸ÛôCôIòšF?<åeUwSèS ÄÜ]°¿…-°Ä-1)3»ÿ@Kd´„¤EôÎ0¶4cîo‹OVoWuÞâÞúΗ2 Ã÷[-ñºM—"û-ÍÐðæ”8šªnuFcô®gºIu™Q,PJéú5¹]z¿»= 8i~>›+®Ügy™pö.ÓD87&]Lû|DT#9ín¦Aº,iÞ´Ùë×hüùàlÅ%˜Ý^`zù‚C~é²=›Vô™äÑÝ¿ÆÎskD> Š+釴ùN§mUŸö‹'ð¯j´ºß@V ýžˆIçW4âl*ËyÈ”ŠÇ>ÿ§Âô¹‡Hy >˜¶8†Èn(ñÓ|¹£ÕöÖ.¥•YÊìó´¢á=‚Â@ìùsH†»<ë’‚­u{kE4l6—`ù¬¸ª¶{oó†8õÉzc"åsÍ‹zóîó¢ØkJ~‘åè½yÌC&ÙÝLI,,Éd…RŸ¾t4$@¹+åþ„ XBÛ 3i”%ø¿«uC3“ôðœ ΜÁ”+ÖÆ%‡JúóGpþìøûåË©TØ‹)yŸûC¹BÊ¥EÒ44¬è Ín×—ôMHZÏ{”²‰#w7ÆH]Óø4) ðÇDIû2bJ„`¸52r;•Œ~Àb.z>LÀôxQÇ!ð›òö–ìGŠI?ýMn  ” s Æ£8H«²ië‹&@8¼² `Eƒ¸HyFÖ›¼0d bh¼½ÕÝ•i›ƒº½)¡¤P+¯{]/“Ô’úFCd›p3ç1S!ïÝ7_ßLù =²g‚^¥’¦§BàÆ/§ƒ$-M†úÅ)6Ù£©›ñžùàÈ8ņFù“Äj¯JÓ¸uƒÝÍÖ¬Lp5v5”Àº ûP²¶ ûn¡ŸÒTÞD¾ÅLýíöå$[ÓÂüàÏm EÄ¢XìþØ„øWÛêæç5I}C$R…îÀ£ždXûpÓhÏÕõdzFLâÁ6ƒòm;Ú_êûVàÃVª³aÔòÁ¶¥ío¬ÌGÊ & l\± õúÅHô™ï‡…Ä”`µ{$&Ç!yBL¬àÞÂߣ`w]Hþ8›º[Ø0dºÐã×}Ûí2èyJ ^L—¸,†âÕëM»›ÄQÅDà÷lH÷ÝЭ54+S—ah?¡'–LɈoªª˜„°Æ‹z.‘(voºÖòŽß 1‹ƒ¡ /…c‘Êcá22ÛôU°»¬Z²ùW9ÜP€œPW¨zÅÇ¨è³ =KÌø¾õÐÅ ÎáV7ƒHRxŒûÁ8ÿßMjOR }qÀk¸>tEKPF@ ‡² Ï^¬<5µ{{¿Æ½ùZþ¾q¬°ÂëS"Bø»Õíp;§ï€ëèHº8ájw«³ªßnÚÁ$°Î%g< …WÌÔÇÐõ¸–Ÿ€®úZê•ö$¾>ZÙc€…ç€ÅîñÆùž̙9ãRŸRè—:Mºf²Ø%¼~½!%7ÕÄÓš+ŸyJ9*>€§ñÞ×P1¿°RVP{‘%CypW›„ÉxÜÛVj™§eh®—ø%Œ±4¼wš|³‹T^E§í&ôšiè" Žï³¸žgvšc×5QñùLïßе»‘e­‡òþõ‚KÖÍa±ø¸Œk½Ôµ.S[kI½êÖV«­±¶êߺ¥ äŒo#y‰W;|ÌR‚ ©Ç%ÖHÌ¢Èþ¯„{}4ÿ¤[¹ endstream endobj 45 0 obj << /Length 1926 /Filter /FlateDecode >> stream xÚ•Xmoä6þž_a ÅÁÓfTK–ürÛ+º{·E[\±×k€­dÜó[l9颸ÿ^R”<㬓E7ÀZ")’¢(>Ô¼¹ºøâ›˜œ³\)\Ý",Ë‚4W,M³àª ®Ã~‹awsõýÅÛ«‹û DðǃT€gBª l/®o¢ ú÷AÄâ< ­TÈ$ƒoütñãÅ´'£s{¨D¥,Jc²õõn¯¸ ¿ÖºÛñÐÜ1ôÃqfXK¼ýÖ?ý€ƒé½ÈX– R;w¥©û5Éðº®.I§¹¡ï߈±Øü%RÑ}ø¾|¥“¾OiÙC_W+ßâàÇYÏú3âÞ;sugþB”ŃªŸvTcíYúïÞ,—LÊd1+T‡f·ç‘ÈÉmÞï¿2ý€–!¨‚ÝÖãd^½¤Â;þ »~ÒeßU/*€ÃiÅs¢¨ûÿÛ¼s¢"âýê4ðØý¦æOHÐFöüLà• ¼ ûÙ ³yöNly~ ŠÄzFœ'0O™R9dEÌ8OÉ«ï ¿â< x½ËDxõÏ×o.‰Pú¶ÅN¤á{?ùßNd¡¦Ù¤»É MïHu‹âscŠN÷óÔØ…I8ÌÓÑ/z@ = ܼCÅfb»}"ÓðÛ‰–ó`MŽà—´ûmt÷~7ç1>éJ1á∇÷ZаlŠi"jßYÏ€8ŒÖÔC]iÇ;S]³&Mz¼-J϶[Å…´%õ&Ö†ùÂLAS·¶(Aàg ¸÷¬Ÿ›Š<޵Ñ[‰†T~vP4oÀÐÖ4µÞ©,,ªŠ+Ÿ&b’5 |€G›šõ¿NrœÇìHÒð0;îm?Ò nšy2caj,†wD<ºc\¹6OÚe窜?¹.K%šÅ2:ÒV Ý %+Xª'šlL´“#†µ Š®Òæa`#˜QQWGß¿ÿ•¬¯A`OæWwh 7>Ž@°ßªÜk$8éößWêêò¼$o@ʇ°èš>Ÿm‚€£š“Ús6êë‹Pas µ ON%è^ÚèÕU†_Ò¬}EÓÏ?¯_p@&1·X»_¶s]ß\ú}Âu|ˆêÏ"Eò'‘¢] 6º»3ÖϺz¶<¸àyî°=s¤'x¸^·7O2‡u¡›“¬‹ï9¶dxËÄßÞü‰sòG1xÏ… ß>ì Úp1༥©Zª ç©îîhØéG@…Ë¥¯p0÷n« `j Æw2ÅhH—RácmŽ4Z—K¦,¡gÔ.,„)Š(Ê^ãþ.O+ùÙÊi*µ#ÕQE¥Q:ÏQhôþ—ˆËF œ·_€™ýÖÁÝEÛZ¿¥àád,Ø6ˆ©ˆÂá7VÎM1"d¡ô9²¨°×:‘'èî V:§W@æ!”ÓÁ:=N$R»/VB*uñy„ãD°‚îJí±è°jD[çgLñØ ;¨µ{z?Ý^hˈºðÕMz<ÞÂ^ðȀʦ!ؘhN…:‰8FGê‰RiŒµE, ‚›q.M?NĆ$p “btb%Е#Φo³öžØGÝ9G:ª» Ú™RoŸEœD’ížZ%ŒqEäƒož`ìö!]DH7¦áŽ|-‹yrBà F}«GÝQÿjú•º3÷,ùXœrƒøwé‰m)ÝàÖyRö”ÓÚ¶Ð[| fENm@aŸRé§dÌ(K}¹ï©»²wæJáKëÌW›¿Qp•°(O_ú‚g)ã ²ú®U‡ ˆ ~d r YÉÕq‹(ÈYžˆ„N[BŠÇ,á.æWG[ÌTº4œES»kä$ôl÷xRˆ>Åj)°má´vTzf‡§à[Â}¦îÿñoDZê+— §q•V02¹+[Ö˜PÞZḶHãw¼›Û ÉM’t¯xã¾ý ʾmÍ(ÿ$䟀ô³GI¦¸®øL“¹JŒ…Ü>„ÆÚ5äq¬ÈOüºùжû §±9Z$r(VåwJd|Eâ9|…8I¤Kód£@¬—³,YêhY8çFÝÞQ×é€ùé> stream xÚ¥V]oÚ0}ϯ°Ôi -ñâ$&¡P4Uê*í¡Òª(6ÅùvZ¡iÿ}þJ ]B×h®ï=÷øøäÖ×sëÓ„àcÌ7À‹<E c†˜°°¿~/VÙ`9¿µnæVn!àŠ/¡'Òô Ö±µXº€ˆø-p¡?ŽÀ³ÊŠA0ŠÄï|³î¬kÙ/pûIB7ôu¯²(pPƒ`TŒ°Í÷%dÓ~.9¹¼ÌV¬˜’´zØÑ¡ 6Kølà ä{Ⱦy¢ Ÿ¼³`iÁøþ>¯hE§VA { üP?Ñ5O‹©JŸµóqWþcAWœÖš…äïzcÝóN’höàE0{è³Î¦2Kì!ßÂXGœÓ‘û2Ò¾Þ­Ê’haÝ$ßj|#Év•UµÈƒ¾¤²"ÍhÁ-[)ÇÒÅÏ/ÔªÓµLÒÅ,¦|›’²·ñ¦JÖœ¥‰f¹ÈÓ‡ŸKMüªµ™.vÅšøA½ Ït¡8 ¡š9ŒsË[˜ }nRež4UEe ‰ßéAI j Ä•Á¼Y‘öŽ ÝQ®ZçÝ{3F<;$œv®1òë÷¡G ŸÆ™´éþ±¶èâMþGPsfºP¢îÛ2ÿán¯024ƒaÙ:“,Í^§mfÊSÊÄ6ISx¯ìÖ­ò°ÙéG3½jz¦™(W}UüWÏòpèÛÜ ŽÚIÎŒ§™ Së7¬({¢‚`¤mFÑÔ—t&dÒ3Ö€¨È§†ï﮵³F7Á»W:l¤ ì´âYÅ{e<,Ç’b-éÿ<«J5Ešs$Ããë{ñ:" ôvË׬rÞiåÃ/OÜPé>…“†Ú¤f6INR`·,âNZÑ©~Š'úñâ‚ Œ|¤c„¼©Ï›/زþ‡NÄßã]~Š[³cG“G®:1ÒÀ‰Kw|)AòZãcàøâ.ƒ òê+ÐjIR‡ endstream endobj 55 0 obj << /Length 2349 /Filter /FlateDecode >> stream xÚXYoÜ8~÷¯°X@Þ¸Q¢® öÁ1 ƒÍ“ÈÙ`!«Ùníèhëˆã¿uQG[É ¸Åb‘¬ó«"_ß^¼|*G)/‹¢À¹=8Axiê$Yä%IêÜî/îûÏ]~ºüzûëśۋ‡ åøð§œ$6å:rŠúâËWßÙýWÇ÷Â,u‰«vtœÂoå|ºøíâ5ž§ýåyÊO½LÁNQâùIÈþír©È=—Êíÿ5ßL3ôÿñ#ÿ ~ý6šÑüƒY®ðW»e3|©¿2­Ü qߎw•™èÃÌË„¶T¿ bÎN^èkøÕžÖ1‹ašýz2H½4 ~0I+£Õ$7X)›xQ”Á> ™ˆXoe¹ ƒØ-ëSejÓ\‰;äCÙ6Loø ´£a‚ù†,ȘºÏ= Mx¶¨ò^vÌ«ªEÖGÚŽÙóqhk8¢°KLNÇŽ§W,÷ÚI»È ¢ä}‘ûmøO¶)¹èáˆ>b£îT¤µûwž½i›~èÆBìž3µ1âD鯀ruÌü[ê8 ì–·h \|óâSÚ»ÿ{½z¦m×¹z≽©Ì`ö="D êzàܵD6VŒ|‘üÀ?§–õ š¼6¿œ[ó=ÇʾYY§ÎbQk¤ûÁ¤Îõc½ª¸VmæÍaC¢„¶½i®æ`å~i¤ú.3Ò iWMгʶ¨…™ÜFh`s Ƨè@{À„^ Ô Ü É'¨Ù£³CD#B kÞC×Ö¼ìF )_î#âðfG±ÿ¡µÝ œ<y7Lj|ê_±CP!X›Xy›)¬á3ýÓ †b¯t`Ùö-†(Ý€0­4eSûµ€o=•Ä@ eŽ-«8tûfg¶ ÃÏñ×{RÕ#O­ý@žêÌw?yÒaGÄ܈8ø±(DïîGÛ…b#§ìIš³¨öĤ¢mæºÞ‘›‘L}ü Š"¦;;#•32Ô@¼°ÊÆ©õ½a»ôåÞÆ–ؤ*ðˆã™©ÔÂT(õîgžv¢4Ø£xêMÍM0öYpï€ÊâŠM­HË Ūװ:²qÇ "R®$ÑüHM!N Ÿ'îþ.™A·©3ç{L¥6x㘂£ro~hÒGBylÿQ9PI `úTbÄpšœ¹N0’ù`î -w¸Dªf°„ÖF5E5îYu Ý'ÉËû,B¢nÒaxq9luD"9¢­Í´GjÜH± |zSUŇtâi-žþР1ž¸œöt[cyùêT›ŽîS@øv yžW£‘bñDVú)×aЙï¸]c˵À oùæ¯yrmSß/Âà‡~—[IF‡Ë8DSTæ;f È'š@ßø¦ ŒàÏÎnIÖåá±i¼,|“…0²”»ÛrüÀ±T´n˜jB~VKuÒp¡ ÄCø_ì‡Ê¯8ƒg‘A¼~ \Üïbçûò™Ì1PÑ9ÙjðÓÀ]¤Ž$^!ªÚZpíœåµíbNéþ9OH')ÂÉ+HÙv¯6ß„•Ö^”üìIX¥‰§²dý,¬2'ö²ßN `‡Ž Ï’ÕãAà;ø®Äüv lðcÙ»  2]¼ÒؾΤØJÜÔöM5ÅGþ]>Œ¤‰<Œ¤ò0„‡‘4±¯tàt ëÝj~„¡a¾Ÿ^ ã¥Ða ˆl¾g€¸½×i(äo ‘]ý7!"t> stream xÚÍWßÛ6 ~¿¿ÂX7Ô)Íò/Ù+öpmï†+Ökw½C ´}pl%1êØ©­ôî°~¤H'vj´Ї!¦(J¢ÈŸ˜§×'¿žÒ‘R¤Qä;×KÇO|‘$ŽJ#¡Tâ\Î{÷åÛ6ÛÎ>^¿89»>ù|"~ÒQ>˜Iᇑ“oNÞôœô/OiâÜZ«Æ |+çÍÉ_'Oñ¼pt^’Š(vT¤„§:îƒ/=< L½¡)ˆÊ‹`3k5þòí¹R_»%ÃHx±²{úàã7| DœÊ#ïÆG†‰PQ2öïÙéë7ä_àBW‘½{Ïæ¡ôÜÓ®Ûm4ÉfÍÂùÌWî««Y"Ýë«ÓKRæÍf[Vº¥Ñ®ÓIYUÍólË£:Ûì'ê‚u }õi3tÌ™+p× œ¹ EÆäÑ®.tÛåM«;1›GR¹7†-‚(t3?qïI~ŽdŸI>GýÁÓǨ èdœ¾¨ñ&FW¤_6-xPÓÜá>8Õ°ö¶¬‹Ýv4ñÁ‹¼ ë´7v׬ËúÌJÁXÁfÎ`˜û°ÄK~,p¼@¤? 8°—êssùüìêͳWWgr ? Ü”j  HÜÓív6‡$hsPdôéÊzUi”ÓAfiÎ4lZÓu €êx- à*Ip°ð‘2¾çcë""$£ðÇå G@!å0"Ôñaõ>0<À竵 ko./Þ‘ÔÝwFo:üAGžˆˆp¯ðky“ òEÄCòƒHˆPa)¾Cä„^l‘ƒzÌ‚ý‘£93éxì6žXõ\‚J É÷„ç§ÇIÁüû1£Çf´·¥Y“ĆÊ/ëOÞ» à§™žŒ²UZÈPÌÙLé¬ Ì•})Mו ¬Táñ»ëz; €XØ·Œ.q¿Õ…^"‘†n ß–ùT>àõÒ´_•7ugÚ]nÆG—5–i[êÅ.‡»²3µ¾e[VÎ#ß"lÎwª ŒŠ„OÀQØ™&KµÈ Ëø¤†8…5‰ï6-Yè»ln+ïA(Ýr9¢…Ä]ë¬èK2V“õÓš‡°ÍÒÏÅz*„A(Tº‡tÙõ<×ø2ƒ7%+«lQéd=Wî™æ(x6HA/äE´y¡ÑÝÚ>‹ÀV—ŒË¬e4fÛmÛlÛ23Œã¥Ì°–½ F@`È>¤¤"ËM¹Z[ò£á:ÃÁ2˜•7Fõ/»kŽðgÏE Ä4emô S€ZĪ¢'H?IêÓN?“ѲÎ+,°‚7úÉfã§§rŒ6-§K÷50<þÉ'óú¢Ù-*Â9¡M"áwÚáüÕ¡ÓÚf0™Å˜oV?î7Cçï뤹ã™ãóñd fG1¾l8íÞ™­¡Zðaú²‚i« A±3 VEfÊXóž´[[Ò KZï!Òõâ”d¿FïqoØìVk~· –%t³2 ÙÓ iÀ/‚šõù‘ûg³Z1LÝ-~Â)<”3Ô6øhk”85Nø¡!o¨l³•&­Ñ[tS¥niHk#»uÍF›Ò6©¨R]î*š²¡Â Ú,Ç=?ñpÍÛn`àãbƒÒÒD³¤ 0°]¿(3Sà¢"Ò>C ™u ‘„Ôôä2êÒXH¹ç ý?ㆽ½¶ÏAà^,'Y »¸Þrs¿Ñw“œÏÂáÏ‚ žu•}Ƈ%¾ûpj¥kH†¡Î=u_ž½#x³[&®iýžt"Œ_Í/ešÂ­££Ðå¹îß=&–e Çè¶­¾ëɯâ¡ûmòÙôE€4;챘¿ÎêlaI’†pèÒ¶|yµDxøˆÍˆ&šúÑÃ}E“sµ«É±ÉäîH‰LŽr´þ5´à¦á¥ VÞjÍÛŠ9L†Ø¤ã°jV4¶ÿ‡kµz -ÑÑÕþÍB8ñÑC¦¾‡0æÎ|7@ÏË.ƒ .¾™ˆè;‰X.îÃ=~ùõºï Áþ¾Sà&°ªHZÐßTD§Lˆl~©ûGz£7MËä‹wêH¬jc†­êŽðÛ7“=»g¹)‰õð@D ´S@±Çà€µÜüÿpWf endstream endobj 76 0 obj << /Length1 2081 /Length2 14287 /Length3 0 /Length 15540 /Filter /FlateDecode >> stream xÚõPÚÒ ã<¸†AƒîîÁƒÛàîîîÜÝÝ’àîÁÝ îð8çJÎýþ¿ê½šª™YÝ«uwïMN¬ D'hdc³±v¤c¤gàË ©32˜é˜àÉÉ•Í-Aÿ‘Ó«‚ìÌl¬¹þÁ¶é;¾ËDô߉²6Ö)'K#3€‘‹‘‹ÀÄÀÀù¢=@DßÙÌ K²±9À“ ÛØºÙ›™˜:¾ÇùÏ_¥!€‘““öos€ ÈÞÌPß «ïh ²zh¨o P²149ºý JSGG[. ÐÅÅ…^ßÊÞÆÞ„Šàbæh P9€ìAF€¿JÈé[þ]=<9@ÙÔÌá_ %cG}{à]`if²vx7q²6ÙÞ£”$eò¶ ë‘eþE ü»9FzÆÿºû·õ_ŽÌ¬ÿ6Ö74´±²Õ·v3³6›Y‚òb2ôޮ޴}k£¿ˆú–6ïöúÎúf–úï„¿S׈ ~è¿Wøïú íÍlèÌ,ÿªø—›÷6‹Z ÛXY¬àÿÊOÄÌdøÞw7à¿×ÂÚÆÅÚã?ÈØÌÚÈø¯2Œœl*ÖfvN I‘sÞEðd& G+;'d¹šÿ  ìf ú[Éø—ø½/[[€ñ{ /3cÐû¼‡ƒ¾3àhïòòø§â<##ÀÈÌÐ`21³†ÿãý] 2þ~?{3W€&Ãûø1þúü÷Ÿöû„ÙX[ºý¡ÿ}Ä@)ai%iš—ü_¥+ÀƒŽ•@ÇÄÊ`ddæ°³2¼þׂ¾Ù¿ó`øc+imlàüWºï}úOÊÎÿžÊ/à}ÉÙ¼O.@ùgеX ß¿ÿ?ûß&ÿÿ¦ü//ÿ¯ƒþ3s²´ü[Où/Âÿ^ßÊÌÒíߌ÷Éur|ßY›÷]°þ¿T5пVWÈÆÒèÿê$õßwAÐÚÄò¿m4s3s)˜9šþk\þ%WùkÑ,ͬA 6f]-:F†ÿ£{ß.C‹÷ëÃá}&ÿVÞ—çCŠZÚýµeL¬l}{{}7x†÷Qbbex0¾¯£Èõï)é­mßMïÅyŒmìáÿ:Q6VPð/Ñ¿(ô±€Â'(ú_ÄΊýAÌ äôîEæz÷"ûq€rлOùÿ"&Pñz÷©ô±€ÊÐ{Õ?è=‚Úç;ÒÿƒÞãüAïñ ÿ‹þê7Ðèý¾·ø¯£þCxOÐøá=Ac3çXü¥¶q²ÿ‡Á;Åä¿å½×¦n¶¦ïwêÆ»Ììð=¨ù?à{ö–ÿ€ïé[ýŒïéÿÃÕû½´ùìûþòüCýžíõ{ Û÷õ³ùGýïÏÐîð½åÿ¨…ñ=S‡?µþ…@Îÿ(…õîð~iý1xñ§yï«t4µý£]ïé;ºØüÃàýäœþß‹wþ|/Èådz·þG0¦w÷nÃÿYC'{û÷Gâï ì}wþƒÿ~‘@ W!üÒ¼!w y]`Ç} ¾ Ýî8ï ù®Z Ç’}§Ó#2lUu†ÿºý­`ÒPêʶ(åÀ2Ñ‹ÇqklH[—ö'ÏgÝ8Å©ÝvøÅI¬Ç‚õß ?Ð) ìy¾ØyªúY@¶‚wK‘çØ9q +ä¡ß» ˆ»Ö/û5<¿ûe¯šMá¹lš.J%R˯x–<× s‡Æ‘ŽŽí·+ÊìÍí ZöÄ‘T ¼×Is¡‡ÆSôÜûj…2“C.®!ä Úè…‡ÐA²ö‚GIQŒTpD‘1¡Î|3_'оK-q÷OÙÈÄæΡ®ŸpÊöTpŒá—-r¡¡CK¥ì.´œzöâéFÝ|x‡/]û/Xöü?,O˜BRûã-?ÞPòÃt„$/°-âæýøÎé=ý¹!þÍG n‘É ×Q³×Cßé´ ‚ýþÂkbBÜ.KóZùë)Ÿò$Á©þ0£)q67ŒÞi–Úà*´7 >püÒ¨)ióÑÚu©nwä·~¹¬cÃþež½Dˆ;å]§ÀE£2MÐTtš9—T¯5ÔˆôS8)“R^fâñ÷L!4þÑ Yp›À:öê}ý‚ä°¼Ïx-!&×Åw „\ã S¥Ó¡‡FÕBFñžS’e“gA:.¡²(Uå R‘sÆÌrfµ„üž0úÑÉ«n)z,¶…ªYBže\Ù¡’F¾@{JÜ 9ÿŸ˜YɈ[¤é|Íæ½·¦yC4)*¯.ÕoÛðÏ d±;ý“[Z›jrôÂ…”ªÓZçr{{9}-Ì‘¡gù/-uQzKeƒšïʺ¢ÝŒ•ÜJ6ç» 6>Žõëq:ÚFÿ¸UØŒ­‘s²Ÿ§’áu2-žóŸ_ÊmëU˜Ð)öÂin!‚îé™…ß¡+wW¡ûõ‰¹bßûv[¢Ð;À}÷ ÄÜl;òüæ}⦡k[V¾3η2<Ê44 žp¶Å4Vé_³iõà34îÏÅ;sÀ©z|ì¿V$„s-Tc æc !•æ²KªÎù½@Ïïæ¨½µ¦+j#5fp@kh¤ZybÛ†ÔÆú ùKjYË{[§&íž"Þæà2há¾Ë ¦ÛC-ÎC%uøÉ¼yÃ-¯ŽF§Wö €CrƒR^Þ#òûÖk\€ô ,4Tû ’òó·„<`øQñ¥JI`Û8zÔÀÒtwÚ3™íoôâI•+ÎúHE/»Æ¥WiÆJ¬6ͱ;(GV3uøŒU#]õúvÏKÙR¢ªˆ]uroUê¬Ú²t²mc5âY^KS®·²Ó]áïyùãzF̸ â?oýt v–‚€}èÈÕéîï°´¼m4#eªb؆{Ìß™kFprX|G0=Ñ…>…±lÇÜ´†‹]×OÛmôo¾•ëù‰4ÛÍõ;·X3•l,ÛˆkÒÌs>ÕüEøI–iGo”Õ¾J&æŠ+g§¾`ðq£²kÌ{ãÕ0mAVïCÉF:±1§.ŸÂQµœXAém%ôâ^ zRS ì.KB!‡;BŽF çú×â#."­„w•Nù ¸ _µ÷G´5o*(Nìdñl: Ý@š‰Ù˜oL÷±Vif{㙌`öµI¥'×ßù4ÊÏF×ø'¢Ç8¶4À­baH­@" ×Si%¡lmøq‰œEμ¦¢=ºê”?ÜbƒåîS`)9ñŠ÷±XçyòÖÔYÊ ÛYщc~#ª §ÃÔˆ~’º.ïjFÕZœÕVÏÅÀiKþÔP•þ¼dIÝ2;ŠÏõ• ‘ŽÀvˆý6©E¦í©áç¢FÖOaïúŸ–77áhíF©Œc\@¿G€ 1-ÆOøÎ¯¨\ä/ã4¿a9™U=]I_¢,çÅ«›¶ØÁˆ¹‰ ÀÝìh6÷Ê/¦¥’|¡a>ì9ß™í'ç–34P©XjŒçiämÕuC½¬Éš1Šd<¦9Âk.)DO, ‚è‰.¦Ý>Ìf¢^þš(…V'îwIŠ˜÷d„3Ïš¢9,èA¶îŠ@µ‡Cdºí~%úº’Ð{ V¦ e ãËÏ-¾ûšvéÍÅpô™ó N*yw„'e»¿h§>¸Ð‘аԓ­òM·¤ð’V¤©Õ :Dê¡t‡è¤:"Žç‡ä_iÅü.5 IŽ­‹ˆàs•;-Í[³ÝŽq€,Êl—ñ]’/4å»Êž±‰ºž9Î)ÉÄë[–âþ-E£e?ND …ûĆ3Üg‹=oåÇI#‡Ð™îÕìü 80esñD1äá]«röJEQ.\‡›¦÷t\øvb,ýƒæº’‘د2ª8AÉú¡àû¶7i”îGê`m¬F-³ßĘRcfÃv#)VRéz€qgN¨µÒ8²×m˜™¸*›‹~38ö&™U]°3ª»Æ|™¹}¹#E»´[â_ÔìCN2òã¼>cÞgϺ«R^„ý%ùyX/ ¡”ÝŠN½œdô’e}˺Hس¤»f ÏîöÛ/w‚W9Üä——±ž9ÎzTŸúèE‚ ˜s—ö’¤É’p1ò>¤vh™}êÒ’§Wú3E°Û7fß û”‘š|G kaË™NâÈýžÝD´d>*qJ,þþÕ1—io|-^¬ó¬ÅÊ’Dº½äŒ©ôu¢ sKzG©P‡ ÁÛº5µROý‰–ƒ"Ÿ]é‡Ùë·Õ$G šß¢ÛD·O÷N1ÜUKËiª%Þ1° 5‘#¾v<ÐѲFºíRžY E@!^æÍ Ƴâ–Ôš„­[: Y†HA}dÝݹ([#ØpúÎëÍ[fQÚXž eµÊok@)7Û [M×zë´÷ÉŽ¼tBT,ou‹T¶°Äâkû¼Q'q:ƒ¸Æ9åO—HõÐýäT ßãDƒaÙ`t³ÃÒxØâ^j(ã’€u¯,£É]á<Ž÷´ɯ&w!‹I݆T#mv~&c|e,6 ,æGÈM´AÕÕ#ÎYAÚ:rÔ¾q÷×êÄN‡®XKT¦Ú³cÉ>–$cÍ¥/ˆ¹ø žƒX?Gk_ú4hô(Œ}²^Xh*²¯æTˆÕB—IøL‰ÿ~ÂócYÄʳ¸W¡28îþç´åÜëÒA>ˆ˜éœùÏ9té-P¾k¾+b÷].²òʱÕ"R)#_ðÛ{<`?<ùu*¯u5_3U©âÆUÉ9¬OG?]¢øt‘ ,›F^þ"#X Ý¼âËÞ Á»²9”þ¶L"‘9Q<‹’h)gB-Qcÿ,UKÙtÞNø3}ê²ÒQAr5vóŽÞ2çË,¸ù¹yv‰B<ãY»»ÓPU­šïš,•ts`ëŸÆ´$+@fïüjî§Ûdö< {o%ïˆ Ý¾"¹oøÞ†u2”P€õø› ÃaŸi†¢gM¶ò<¢G,eEÊo²õ X®‘kÓn¼»·›Ù7óž}Ø’lÄEüòX1lÕÀ·åPñ­Açf~=%®c.)­âѦ!”{Ÿ-Îôr°Èœ‘Už¯wšÖƒßš*¯®ADÃaÌltmÎp‘=v“’€à&yÑæ,/Œ×Œs“c"³GªÐJý\ðE9‹o&ÈäÚ—yò^JÞBIÌÕ¡ÛÕ _díñD«N2çdžIˆO¨qhÒ‰ÁUÃâ&†!iù™Ñz¶]Ù“/ØHñ»ßô‰¯ÂyC·IÑŸ^†’†œ ±# òZ€ ëâÝõ+¤ …;­R-=ƒÍí9²[{Þ.ª1þX`Þg4Oº º êÑñ{}ké6ŽPÓ¶¢$ µ¾SŸG•}›‚Ðõ#£É^ñq…]ŠEorðI$@ƒ±#8ªºcUBó¼*mGL²MÉY`:ßì°ÉeÚôÅ(í ¢oä<•ÜaxÝ;] ôv?£M}¾ ϵ{©ÏÔVÀ?…¾²â”³»-ž=Ÿ'PÇõ#ײâñ»ƒþÇÁR—xÛ´j¸qûµÔÇŽÜ•®ãÂQIp½Ö³h:þ³mnº«c,q/%²Oúžˆw›6ˆ MNŸÏ]ÒQ_ª¿¹ù‰¥®Ùö70}ÂhMð’¤^kÀžàsãO“ׇî`ù†ö̵•Tk ºŸ£ªÈØ4­úûÁ€6€$DÚFŒÁÈ V¯í÷m4{͘E\g´Â"žÒc¿Œk.µñuM›$Õ¼h€—4bè7ÇY›ýÓ¦ Ÿ±é©y˜.Ž æҎFÍ÷땼¦_O¥Bܦ‚ÃçšvÂ7çͱ?”¬Õ{»§ËxØ j)N›’QEp¹Ë)Iɬº˜ëd $þŒ'lýAð‰jZyÒ{RZRóQ:ÆFJË›’Ï›s‹¢¿p͹wKç.º‹ª3DuŸ×RnÚ__u±®”<ŠzkÞ†qÅęߗ…­žÝOâ6ë˜øõªQîú¥×„%_Óó~å¦áv~p4 ÐR(gÊÒ=èŽn/¡K:C ]ͰÝ>fý0( ;’ß§O•ÖÈ\‹Œ»¨Â‘@Y±‡C–£WäħeR&Ûá«G˜H) Â}€ˆ‡~©–9w3™u!ªÑpöç±1iQÄä϶ »ˆú3ŸnWt…?bƒ3Î!#??닊"¯°tñh UxA³û²“/¶¥îûZ™$›,Â>W»@ðŒ %¡Ýzþäþº‡PÕmÙ#æ±XF‹y›±WÈ þ™–/Àò˜ _ÃÎN F+ C8¢æŒ™ wÙóR÷ N“ég©Ç}ËèîžÇµn=Aøûp[fvhöPÞ¤¬ˆVlÅfP4HÓ38RUÆ¢ÿ¾™›½bO‚‰¶œ²N“uÙUçÉ@ðBê¾Ïmù½æ‚ÃDÚ>Ìå92ÙÁ¶–»À"ñPS8kaá-&]hu={‘æ\Vm@Û§™æZæï·9ˆú5H 9eÞ@»¹çó#ó—^¡ »pŒ·:î^J—"©øŽ ê€£v¸ÈšRWñ‡yß-j?§uè_î×;Ø5þ)5øÇåö_§N‹êäÂk²›È¯¦pMàÀ.ñTÔ)LÇBÙbå»ö¯7fÕÆ™ju–qîcÁ‘ÝÅ«OŸfr9Óãå//nƺJo$K|Oô&z·xBlâûð/ƒÇBIŸžÔÏb1n¢[ÕE½Àj3Nƒ‚ö@jhíºÙ––_JÑÙ^`ÌlJýâÅxêcñ˜gSŸ5 _W·äȱ־À踌ã¬Dô{¤SˆVFråYðPÂñ/Ò„Jj›%= “à³½ç–Ó«¥KÍ,\ 1gî½V-„æÇ¥zo«S xÅ|ºBŸæmûv‰Úc‡äå°ågâÝŠ2z(í×^mì<â&LSªQ@¿gº±¦f™åJ0ó/¿aÍõ÷Èߘâó€¯/ÅíÉ´FS!ZWÝl6Q)§Õ³‹=­x¢}`âsš¨ÓèÈÆ Ån¾ìêš9ˆ¨à°‡FhjŸÙÚ¥KžÄo¤€çdÞ„ÑÄ [^9HÛ¾P²Òõ‚Í\·9¸]½Hqq6^£Ub_r׸"”"±šL•`±Æ÷–[_ÒTòÍêÁ9Êq–ÏØ´uîKŽöwT$8¡Q§)òô®_n5‘œsÑC{§ÞÃQT>/5*H“Á—ã¬÷æ¥ÑïÔÏ>.·S6À¿ÁwCϼÙs–™¶L înå[wN“#H{󬌸¦l9¹éË‘^|1Äæ˜´~ KÖÔ-òï«l{u SÑì•5Ú?=þÒ•úºfÜ;Ù赺J:‚L¡} ÛÆNÝÌwó¼¥#Û7íö$nÔz#CPÌF\GþIzÍv#Ž6mÛÚ¶듌·š§Ã°‘š8[U#¬A9¬: ´´xaéÀûÔ>ó=*j ‰5Ò¸`²ÔÕ>LÒ&&7½7xŒˆôøÈŠ¿FÑ$w¾‹ëUÇ1Vñs`ŸÐ*©o¸ûþ7ÑFÇs, algmxæÙ¹ß4:lw‹w¦Yß»ˆ”|$7d”[аý™ÜüéLáÐaËf«éë¡Bµ ªœí¹;7Yîk·ÚÜcbñÛåw2[­P;&™³í(iä ™J®#S®©ŽÓµ1žÂ’#XS ÀQ¨d ,ýÒdu4-1[|Çâƒúõw°º ˆ`ò¼€{¿Ô±a‡\,·$BaU^Д‰MJÎŽ{I—ßuT­Êôwɫε«[éè´å‚1æÏ›b‘Ô8mMúµ­dr(^*NÁ §|ôòu²ÙU>g ‡Ù†ˆûyß=˜ú03lÎü¦PôD&äî}Ûóœ"º(v"°Ã„Õ¨$”ó+žvǵÁŒ=&¿^zÓP…Ð^‰(ôÏ%"SÏ!O–0Ö¦áÄWR×+Fû8·ùaI☆û~==ñRÎ".`l¢’^P Gâ“Ű:žJ±w…êÀ¹Øª½{è ô ÿ}⤋Œj[7¥Iˆ ßØÉšï­Ç|ÌÈg»~ª\iþdd£<þó(•bQ{£NJsðµfUóÀWàg7©‡ÙöÎô&ž„Hð@—)XM.]±es§P®QFº3ú9ߎP)l,“íæ'Ml¬+óÙÍ_b[Jñc6%!cú™Ó/᜹$ŒÍs+Ùéz’ùÂÁ$œ<‰‚ò·R®Ž 3Y¤w¨ñ(–#nÞCÚô™²Ýl®x‹ÙgEE,RU]AS[÷Ù.‰`Åùš!ûê\Åh š‚üݰá7®;·ÓÖbî®lî_°/%š’Ãùɾʞp×Ùlš?eëgóþJ%‘gO<h2 vfôŠ9rªýyÄÂn¿R«*B×¼k)ãÏñÝmi!§ X@¥ß<Ç[»%³þ Šš}T³šz%ÎýbáŸ!4›â˜¸òÿÁ[0's+0Kqe>H]™˜ºÞªÈL‰¦–áa1Qãx’é^CFNJ<ŧˆ™Çká¯ÉçÄÙ2Yþ,%Ác[O33*Q¡pÖˆ†¸ ÓÌ6j²FZ1]Zªõ¤Å§?ch¤-áý ÀI'âTœŸ–©Íâ,å6w‚“ê¼™ ‘uË¿I}gjp< †u_uBþUÜ T«£Ë¡\¾ûè&ЍøsŽÊF!ÀBi—Ò:B”1ù2Gs‘ÈFLë^œQÑR©ÊøQºfUÞ û›Äá'Ú x›”aJ”Ÿo vó߇|¯ø—;IÔbL¦ÐBóÍÀMŽBÆa12¤‹pÕIâþ²Bøb8ëÌõÛ3Eò‰/§I…¨ýíÖ»tiÄúŽçø+ZÏ¥oŽâc7ÞÒúXÿ5püsÀlm+¥¬¯§$ýtöÊOä„>LôÌE~ʉ{ÓìOÏòß›Qˆ£xýÃQÚæ¸Ì'šœbkl1ßÑ;òiÌ[CÜæ©úSÔ %‡7pä¹›`”ò>±™ [ái ‡Qëè}T· u ^b@ÜdMŸRÂm™-.Þ]õ¤q(Ò›ùÝØþ6‘7Ñ”æ½ðP P÷<‚ÓRZ6[æÌiÇó°6]ÃÚŠýVAW>uæúty8±›é’+ ©qyéáÚ -HþÒþøòA0ZÃÈÄæ"ª”<}É9ý+GÀ|f[gŸ:Ê êüF—qÁ®afhI(ü-#¾*ÏÙra¶ù,\ÁS‚Ùl-ƒr9^ïNnq ¨²ÍÔ  Ú«½Pò c^Ã<Þ›q.¶µÁüÔ2K.pÑ€ ÉwpÔJL<ƒ£Òzt[4·Ã}¿ob;³™ü0má"—Þpü&µt‘.óQãyŠ6]­[6: , Nƒ?Û˜õ%†Åv·wÊYÉ:¯ÚÓmâòÎG'…ðõ‡€“f§«,ØÇ·‘à™…cóð¤ú¡Ì4#ôO`¶ˆA|BÔŠD^ßÂÎ)=¾¶ù·q.jÀ…¯C%â,› –8ôµAyòú´ŽÜ@7à¢]ÇnÅ=.íFÜáW·ñ­a>ÀCzo._[ÇÓ7ÄøR¼áÙÚqÆÍšfØ ¥£Ñ%ŸtŠ'ZuíÞÚý\ÿ-ïÔæ.I#õ³Üb&•˜°±hÞà䢒hÐI¼¡Q—¿Qй÷4œ±ôœkC-:»•OˆÚbXT’bÙøF&ùâäkç‚„íwï\½•q>„ÛktŽék¹Èp‡ãÞÿ»[} ЇÆ{¶éÍ”ÙÐʼf4êzgç{ŒC,‡sÀw>×,žFQªR¶Ï¡aNI>¾I¤×;#4$Lrö;½o7ÜY,§/n®KòÆò†eü!GŠCCÆIêS})y‚l€Å3ëÒ¬„íqT¥Eî%+‹˜‰ ?Üg]ˆ °áX²ˆ¦ö <˜] ÿ0 è ùMQoÁƒÑ¿¦I÷Ø)öÃ~Ž[tfŒô+üFQ'±ßGCe^J†5“¼˜X£9oÍš"«oŒ½JlMuІb±ljKæHš$¦Ì47SVéài³L؃ƒZ4R(F ïRµ4‰pŽý¯}çªÐjUgàã Ðø5 rf¿Vm¦É`$ “$=ˆR ~ÛòùL¼{0$ËŠò „Íêí±±ƒAY°=SÃai)´¹Çà\p-üÈ™•pI×êü•i¬äÛG:³O*ˆDä\“ä˜i_ŽÑ5¸×Èêõ›å˜ð<%Ukõå‘öæKÕ7ÊšæáÊ ||ÄLgµnŠVݪC&‚Ž_¥øIB<ö4,k³Ôov;,.®p”Ü›pù Ž_5Ñ&}pÙ@„eÄ(=ÂYì¶ø¢êNuûºto–O7òhå’e„¥¶ŽÛXYàºlÞÉÊVë{‹k¡Ìo‹ñß²TÊLÉsª’Õ©w=o`ïb‡Ò—ÇI²¤3o'Ǻ’5„Ð++eÓÇ祢Ҫù:årÊ5¿2L&“£³$¶®}EÑ“õ½‰üÜ-L%²š…Ý‹^Fʬïš5l÷̙魤£³üQoÈ•@kR:ø*Qì×d»æ³“ˆ|Gj9$€'áñ(+z€Sé¨мî¾Gý𠜙ú Õv‰ ¸Ðœjzaö§ÃÉÌŽV¯Ø3UòLJU ’锉µË'žSŸˆÛ½VŽB$õÚèi¼ô„W|ÕÍ«ãÅy~#ß¾¡½žµ·bì¯Løäþx ¿ejàUúšê ôíž[ëúÆÌ`dž›ßÙ.HäY¿ýѨ¥ª ­ÇÖ囿}0—4Ò¥#ÛPw¬¦!ÿXŒ4c.¢(ó] ÁË@kßo¢Â£·9.’VæªtGsÜãÕð ùŸÏ§‘0üÜÒ°|™/:¶xbÇšW“«¯$á–KÓ¿ˆ¨YÏ­*†Þ¦à'„è—ë-=Ü;[°eÍ€opM}Ãf$ÆX¥ó£ÃKìßâ#OÑÛó­lÛ»OíËûiÇÆy)3›}F’”]p ZÞ@¥Ku±©6=Ïæ»?ÑHµÁðdldÂGº²ü U¹‰ÇDÑäXsVq ßï¢ áxȆTÚÈãÏ®3AÐàöx”òãçÒ }4N:Ÿ<³©à£ý×£¹¸W<øš,>ؘbÖVo, f´_/¾pÎ;X0åZÐW¾±­½Ààt>²×Ïá› ´‡„;êÔ«cNur]È }WQ.EúÍÏ0€¾Wõ’/ïÌÊ@Šb)\Uô%iqø’x¤Ñ‹“76àa"rŒBd¥þ)¬ÌQå…<óH¿ ¼.sÚ¼ Ê‚ù^ý“BA÷ù Y„ÃRº$Ê ŸÝ³Ø%4ß(7|~8F}Ac H§ÝàyÛÿ"0Ô÷IÓ6™T~’qÄÛp¡L?¾ 3`Ž ®N΋kZ«Ç¢–ˇª¤/ûº^*á2™ÿQÝ]ílÝCì·:Þ1"$6œ¼PòàòG}•‡P¸¢XË&ÜŒO¹^R+ø)ÞdFö|T’Ð+´'Kß“ÙÈ:#ö”W‚$¯ LôµÃsºµ4›Ò"bO9‚MóZ"Y±—a¼ÛĽ„ —–ê–vÿ†Ç*ŽItùý’ÄÎFòñ”2múòôãD$¢ùt$U$xP›Õ}Ad¨üy2)79È,ütè¡<$o©”~ ¸|4ª’BYYÉôô©k¯nl[£ÐÚéë*Ê«[b;m—Y|e©mDÖOk²®5jì*ŽNXùjþS M ¹Oˆ$Åqÿ)@40fN¢!æökÓ™ZYó‹™!‹¬VåopoβE!ßÒ‘ ±æòVŸIÉËÖ†/(¦g‚˜_Òêrh“¿/žÈb XuÛŸÑØ`Å«ýT7 ­-dü¦‘2w”Þ»Ñ1RÓÊ:A’fpΊۭ*‡*¾aŠÊøk×?ZïÚ™±XxXKLTP§ÇÖyÙ^)ªQ™~ÿZ— ‰° l¯;Ùën¨“}*hñj¿†*¡OØg ’£Í J)9rgeã"7ür0§K^ª¿ƒÌêî†ÑfQžŽ®êFaϱŒ_'ØiõçW—‹}˜»0P09™¾|,6Íl-l¶D8ã"Éȼy ûd˜=SÍ3,%~!< }©…Ä1 Ô§GVÔ%Z®Ÿ½!³IÅ)!xå͇$úVµÜ®l¬žU$wny·cÀ¢3ˆ½]VKŒ%Ër”òtCÚe*†Éq›.‹vÊjC­ŠGs|8áeÆós7"É*Ü5j‡èXW5&‚ÝëÜÅ1ç|@hÖ‰¦Ô3þ¢Û\¯7¾œ#7Ô(!i:ÕM7°ÃY‹þ!Û¦LOzKþ¹sGæ[Ÿð¬…Åp/å4Þà¢é¾Œ}ˆDÆ Ô7ì•”µº‰)ßg¶&fÄRÆ)ÇÝïtÈ€ÞªVô;|`üEf…)9=¨ø•l×kºø7 A½T•F\"Þa¡@ägqµNcbÅúCE¬a FœñTAhã¶ @¬E×3?#½Ýèn[–%X‚>NXnÇñèWVŽ;˜Þ-º"âDx yÄ8ÂŽIuGY’HàÅ)±©ã6üØÍ|ÐJ40¾Ã[‡¨D>u Sõé’ŽÚ&GCwMñ[¾“î¯ez¡ õÂÍvum<Íã‡HÖ0;º-*l»:Kíe½ÏPБ‘™ìµ^òÈ.\`œå8èŽñäÑü±,ùíÖ[á%·÷ºíSùâµEzÞa ì=t?B®ªàïï•mÖ ù›³Nꈳ®ôÄæ‚GUUû€¼„”Kl‘š×§+òb†¿J0Ú°3„)˜TvÚá40%ñÎSzè*Ñ“Œa|Ÿ‚õ-ÛR¼ ŠÏ¸ D›Wɰ±n¶©,ÞT²Æ2áW³æ’Ä\ó uÜ?5EºWÏç6A1VŠb©ë‰XŠ‡Ô˜Ðà趨½×¶íf>¦—”DRŒ«• îßÁbΖë—Úœ\_" -Ëÿ>4>àýÑöW•i¨âÕwÁjòÇÕ ZBtœ´ ØC"OŽ“§gF)8:¨ùÞÜš°¤ö/¢˜v Œ`º‰!øœOc•~æu ùÍ­CgËûEãCËÔÕ bÇ_ìÌ¢]øåâzéA›/ÉZå­ÖëXÖ^ë}o8«h¶ŸGJzädmv"Šã²«PcXätŒ^° xèÏè*o—•É$×´`zP~ÌI¯ d–‡ïdÆ¥{ŽªˆšºVù 5¯ÀnJ+ €P6Õs»q7 .vÌÈÉÔz+i¢ãå.=áŽi'L–ëA/a! w×\|0¾cL*‡è¾˜÷WJöØè ™ÚüüÑ<¯6¥ËÒ9 Ž·º[óòþGÔ#Ç3f÷¤÷œÑXEQÚ æE]tF)¨ŠKÔköŽ n*ˆ­÷+Jº ¡ì©é$*÷3Ödö¤é‡U[[duŸù Ôò;ñ°ÇÓðœü5K¨¶9: @/—rèJ@į—è—m«W¥,cb9 W§–Fm…ÁÞU±³7`ÝnG¤¥ÄxìMÚ’wtQ Lš®£;]°´¬`«Ë^¾z@GÞ¥°z’ã+fé×’ÈãËjA²~¢Ÿs|!ƒº³ÔÝÏÊ„QFÊX¼YœÕKÜY´3²ÆG9 %j=¼Éå×Ñë•>ðoúŠÝš‰hÑLÕ·ž.lX2ônµlèß´µoLñrÌ1ŠE1Åkʹ¬?Îl'‰@±5‘\·æÁ÷o•sc»IÝvGZêK]éÊÀ±Ã€Å°òë‹ð9«Z¥4êÕ¨w¹ˆ4Ï<¦¸‚e~6+¨[§Lº3øÒbË¿˜Ó ¿ƒ ¢u©l™ª‘T/$ÍæŸP-hßk–?9¡—¥öžÉ4»Ÿ+ì~´¹=³÷ó#Á͇@mfe>Åô›iûPù Zµjý¬²¿ååí1Ï׿žLµ¨uÆM4×hƒ‹=ùÍ Ou˜¿¼ÇY¸‹S‡«úpy•ø—@¼D»¬žnTþÌôŠ@;|É.ç[º..ʤ¯ÕJíw rÌG=O2|ny„†l§h¿½U_Ö8È'Ó­æÍ4ôvËt×à_4õ !D£ŽûtˆM¹¨ÉJÛÖ(EGæû$¿I„påGj¨PþðRà:^ã?èYráÃÒÃOs'à”™lã}™üþy4P0ÞÕNØåé!@å³”~yf¾%+›ÑÆu4s(¤§^Où¸y9EKöR0©ÊNÀbÔ±.½iœi„ÅwSø]XØZÑýc3D ]@,­e0iÁê¼*c˜G3 <#—¯:dÐD¢‹âÊ?¸ ýúœà§7ÑJú|>Õ᳿O;á+ä\)ƒ“W«“É„[êºÔH>€åÉÎW1m“™E¦ék§'7h…]”ãwGϸæÚyU\deÕE:¥äŽu³XX”§._ÌdFV¡ê²;Ô²8…~Í#ÓLã™I¨Óy]+1ÂM§²<„á©'B¢ÝÝvöDÕ›Ð64õÐÑùé`IÒ‰ãy…Vn¤Ê"ØØH>>§KØ®²‹8i%$y´ìkØç9)#ÌB¾Ó}©ûo„ð;σŽñ¬‚ÍÕÞíßíµFk÷l]ý`Š[çÉ —é/âc`‡Ëþ«;Ú¨ƒ¯Ÿ¢ÛüØJqÜÔYÁwn¿šà}…ê|¿SÙ¢m4SWq¯Å|›!Ä=LÁۥ׊¾á»'éTñ¿vLêN‹¯öN?÷àíº%÷ü{j¼XÛ|¬äãÙûó­õ²ƒ4œ!sBÖãÃ5ÓÃòš.(“©/«¢ˆmBJB­B„î&úø¤Ä†ü.'9ììÏ/‹·'ÒƒÔ›¨¤€H¿¹êöp<Ñæ¢ŽKµ¬Ì‚ºV8TCŒj2t8¹ã‚u‹ùñ0øâEaK ø›ð$_ý„)âÙæÏÇq½ÆØE¤WìþX E—8 ‰^Š8•çÿ‘8 «j3ØH÷2Å,ªÑ ןX´Sœµ#©9§g®AcÅegÛÕÕ{D‡A¯bÆD“²Ÿ]Íx£“wñsµ=ª—°cxï‘QîÔGᬀVç(°7ãç±Ñ‰Ìgu¡„ƒXvNÞb›Ã̃OÍ„D*?QWj¤r—€¿®³·h/ ¬¯)Wz„û[2^„*± Ùžjý´Üä‡o¸:ŠšÔDŽsÙåê.‚k]Æ…,*oªÐ30ŠK|^uu·alTŽ,¶ß’ãw´.µL¾72\ÖÌ3SÀRp„àŸ‡?ùÙ$š=lË£ÍúÄ0Jã “ëÇ©SƒH­Ð?dÏø»×oae&Eƒ©D‡78ƒÌ³ì«ŸhÖµÃl˜¦Ñ÷„&P¬B ÷åÓ-ñœŸ†˜.w“pÛIÏÖ_%~•bMyå‹J„ÖÐÊU(Õ¤uYt¼ÈÚÎÏè/Áª/ ²a??¤j(Óô)q{[ˆò®4>3æ1çxt8÷”ò õÿŒi›‹×ú^„’B'Ïo¢Sòy‘AÈѹŠ+¸Æ43¤ÄÅŠ…¨î¿O0‘÷òÅþÁ¢ºí7Jû/Ìã9ž¾z|. ¦ ®cLx–ºPBÉ$;8Ó5LÇòX·–ñ!F5WC™ò\æ¡âàX/ÊNŸ²3#”³©Ë÷ãøÓoÚ€A°6)OáÞ‡öøþr“hpõ¯[¶º3`óGöppy±Q¬ŠåðBÇ_¶bž[èÈËxâÞÿ}fÀ̺ˆ'Ô…ÕJûiùVqRùWa=‘l \|ioò\ùä Êo×ÐÞòRÁLœÙÕál–ƒPâaÉ:» +s>¾5þÝ–¤±ÏÁ¶¿œ’'·LyÐ#Ååì1¬Üøöyk–ç÷BtaõõNÂÚð®YäBÂYêO·gA¹û(v` ÙxÉŒ 7¸&Ç#\K\%9.ˆ¯W¨FmŠ-|ò"ßFÍBÉ´vWUSúTh#äPãó´æ6TVäådàV"ͼpJË1óªû·¾èœV”œcË+2ß”@¯¯áQ¥“C>ç[ßµ‚¾b|G› ¢íbÇÊ|¹™Sªòiµˆâ4áÚgí9¿)·æ§ðäßÞ­Vp„qÎŽTY¢Úÿê“×4…¯ñ–wØÄÏkBîµÜq6Ú“Î1I3Kœ‰µÈ!ëWÀÜ‚”–üj|¤ðºÛ¿Ø§ñoôù‹Ý;Ûxm¡fW鵕A,Évê[IBƒ[¾YˆfF(Ÿámا ~UNÁ@l1tã®tïDÉ,oÃ`Â@JfŒ¡5_õ—´aAA+¾J­kÖ¬À‹­ ¶i;ó Ì 8m¬°@÷¯AJf“ Î:¼‰ø~̾lÍN»\.Qðö,ˆ°¶ÏÇÔ¶ÙÆ ³ …þÛž­PéAíö¤¨mt·{èQn&>=`âô÷mÕåeñ¨)âiÝØÌH»ì½ ÕÍýäíç¥TJ#˜ø@þ«ª7‚©ŠÑùˆ¼%ˆðúëC æ:IŸÒÕï …$ÅgU,_˜ðÏ´9:Á2)Œª¶Lì.‘rÙò^¥i€\’郦äÎèd½jÅd7~ aõ­sR]¡ãÝp㑹P²¡)SÃ<„Æ+ŽæŒ^4`D‹!éúLšÆWÖ2¶ééºQƒD¶=-g{_(›©Ïë‘“õòˆs&*FFåJMXh•r½íƒ@ÛçÅrÓ¨­ÕžUŽŠO)\ m®(OŽDëN¯<¯l™b«މ"½ùLòþŒ«@;¯:4l~ïÄ]ÈdöØÉ|óJii“ARé!›Z²,¬?ÿÕb/˜âÎ/j»þz’Xþ ¥°£ð³ÒsUÅ[äBóË@-õRùnÇïUDÌ›²Ž‹mŽyEés'©Š,ób|$XEŒŠ|§E'cUXddÉ rݹ¶bô’¯HÄ#Ýô?IñŒƒâºp—3Û9ih¿9ëlÜò ~ˆ?jÈeá~¸àÂê>s9$Úù¹Ð{¢cé©›N8¹”{ËŸ0Y›G¯¿Ì¦{ßwuS¼ljÉ/õ¥¬*öbÎqbYÕÁ’霰ë ”Í";Œ8èÅÑUo4Œ,YyÌ‹ÀjweTµcY8;ëC]"Ï»r÷ɹü|«CÕxÉó‰ ÀÖ¿b -m4 é˜7õ|µòt°ÜgÉÐØ°x{ Ú»ÅJwóôÀrÈ­B¾ Å›õa”"n¨EÂñ‚hè¶…Ò×ßÌÏYÄTšŠþfGÏvƒ“lÝKi¦.¯¼¨ƒÍ3ýÀƒýÚK‚1~ÁIhÿ ®fh‡\m-Ëe‚ðkKâ´õ/B¤Ð¬lYàcíJðÌäþ9Y³+·þ*¡l†”tð$,Ãq†RÙ ~]¼±näŽÁ<ö=éh­ JÃáÍîSHºqâND™¼feœpƒÈ‹ ]¢¦|lEDa£ÜºÝo—³éâõ±ù™Û¼'£* Éñð ?OÚ¼¾œ¬/ç#Ú:Î7%XI¥«÷Øv â’á‘9æñm˜,÷%Œ€1Ål|ü¨P+L•&þ¼’ÐYkhº+zƒ”®y˜ä5Ôy‹ Å,K^‰ ¨ÑÉYÛð"³D·ÆõN°âz¿ÁJï}i™tæ?ZBa4¬Iûø8•b¶=9XP¼B~¶¤‘1ã´©øÉe© 'Ù"0Ì©v+øË‘˜½æwjÅŠi#wKÌi¼u”+fõ׉{Ší»©“Ê«Øè…ýèó»:~ÈSjú,î¥qT¤·úæÊmsÚ¡ò×ý®‹9ÍÊMÜÈoæéuZ·S½¥ΔÄ,{T!d¦…EtŠ‚I9qU»®!'“¤§ÙDxbéK7s3ínÄ/+Zq¯6›áñ-"_¡¦Òq8Ó|¯=»ÂU‹×Äýk¹m»vk|@%p˜/Ÿ¬ˆd +T@Ç#ó饬‹Þ-tÝéÌ¢¥¥p¢o¥?˜uXåÆ6ýŽË3‰?²6,Ýz’þâ5슻ƥ âÂã3õ¼½p6ón«Ô‘‚¸ŠQªYN‰f È\Q÷¾ûêo%Ud¹u©îÏxÙ ø¶\ôü Ôf9"KÒž‡þ| ãñrN¶6¶ä§uœ+ÔQlâñRáàq£ò<õqïÞ¢I3ZÈ0¶N§TÞî!8y&Koc›í•à À˜”2H¹Ó€²½Cª‘#\†md¹oWù<äR!#;²“úiù¬$ ìÙ¤q4d*tØ|uç°ó|˜&Ž&óIigrv Uª¬™ÓáF©0@%è¤1Pb¤‰DvîÕ"~‡+:)›í©272³v‹Öìd;k›‹ÂÕÕ-ì7<›* ÈáQÚ«Tk~d6ÞYGdœºm§¹Çñ¹áYÂl¶¦;îó3Ä÷WG˜d†µõ¾$i°-ó ëÏ:|ÿê|h áŸ3ÅP»aæ*È@Ü'Y5˜U€‘ §™?¿Ì²æ”(É>BÁŸP3«W\¡iŸS"º†Ê.× Çø¤yÌîyN´ó+?Lzþ—…M&¢“;Ù+«þgùt0ÖÓßE};Ju2”¡I)óB#: 1Œß.Î!Â…Em¡WŠjßY„9Zdt»>ëÊ^™­=Ùx íéZ\2Õ³÷sôõ†«Z÷cØá_ð«¤hÝ"ùÔáÊé—)GùQT¼Y+i”™i‘×ÉP½XlNKúUD£ äáüÚÐÈznÓ5Årn²ù¾ #÷£Y‡)ñi΢ ­/eI[UÆK®Þž´ {1˜êò]`ø1Ò2ÍO<Æ |h«ÛÇ«ëT]Æ7ÿ^"ž×dñu8»Kp•u}[D¹ÝâQwnìˆNW_Ó»`uöÿŒê\Ì endstream endobj 78 0 obj << /Length1 1453 /Length2 7143 /Length3 0 /Length 8122 /Filter /FlateDecode >> stream xÚ´T”]6LH£4ˆ ¥4CwK H‡€Ã03À38 C+HwI#H#!Hww¨´”€ˆÒå7>õ¾Ïûÿk}ßšµî9×Þ×Þgïs®}¸Øô”¡H[˜:ÊTuUT… PT!åâ2†£aÿ8H¹La(78!ó_U ŒÆÚ€ÑX¦.Ðvw‹„%d„%e€@€(ý7‰’<càP€® @‰€¹‘r©"]½Pp{4v£¿—n@XZZ’ÿp€² ‡€]0Úæ‚Ýv!!pÚë_)¸åÐhW!!A°‹› e¯ÀÃð€£†07 ƒ~7 лÀþîM” `ìwûÓc„´C{€Q0Öà ‡ÀnØw†`·ié¹Â’uþ$ðþ:€° ð?éþŠþŽø# ]\Á/8Â`w†©ë¢=Ñü0ú›vvCbãÁ0Ül‹%üQ; ®lc[ü«A7 îŠvtƒ;ÿnRèwì9«! ªHíFú»¾p ‚=x/¡¿ï× ô@øüíà¨ÝïF î®B&øSw˜Öƒ¿HXélö04@(%)Àž`ž¡ß[{¹Âþp ÿ6c»ðóqEºì°Àüàv0ì© Qî0?Ÿÿvü‘  p` ³‡#Hÿ“k†Ùý‰±@Á=–@¬…Àß¿VÖX‘A‘g¯ÿÐÿ¸e!UC#mu¾¿{þÇ«¢‚ôø‹DÄa ¤$@»ðûw}0ü¯:þ+T a‡üÎõ»^ìAý]3æ/pÿ5$<€'ÓCbÕ pÿGìV@q ûþ–ü!ÿJÿåÿ.öÿ-IÝÝÙù÷_Œÿìwöú‹‚•¯;; ºHì@ þ—jûs€uaP¸»ËÿzµÐ`ìH(#ìÿ9K¸›:ÜÕ‡£!jæO»Éïys†#`úH7øï' þ;d'ì3â†æŸ.°vâÐÜâo ÃÎÔ¿KPC@ÐßÃ'".£P`/RìÍc‘8VØ)…Â<ÿ6@HDcCØvývHéï[Æ*DH÷·é$…Efÿ i,ÿƒ„…EB®ÿÅB¨?à¿ ‚¸£PØŠÿ¶Ú¿ñO æ ƒÎÏ !²ÁŽÕÁͧUÊLë#rû©§æ"#OˆÑÝj •x£ÌW–¨Ïw «?qlÕSyzšµ8ûÓçK k­—ر«ú–=«mì̯cÜ©Ÿ“»ì3 8¹fÉ*,2E¨n}æÊ6E¨}·…ïýêι{´oÔ%µCšõZÚªÞ¼Ò¡¿+mº»jˆ~oÛg¼.~xû~öªKLÐZ¤UxŠ^:ûC¹–3ÒxJÊåÞ¾ÏT]ÌíÚ˜Àõh*5Ù¾»Ĉ*M?çݺÌ.Âì¤SûØjÐ(í@»KøiÖ}aÜ^Ó%Ó¾ «.Ežµ´½‚CØRê@í8ð„ N¨7]é [ƒ†øE^®dj5|íï›!êý77½Òùh޲çË" RoÖ=d4´–És‚½eÌŸqèëçoD Þ)ïç1êáËj”«‘Ûy·*à‚`&ž“N©¯ºà>æ¥M±»]J¯— þÜ~ÆÓNOì Æ\%ŽÕ¼¹óÉQ½e¥^Ýã˜ÞZæ—Žˆ2±C¶7wc¸8¶."ÇM—mêýY¼9Xqàusbýa¦f­âÛ\ÂéÚ¾ø#í½ÏØãxŠïI³ióoå¤YgÞéSOõ®6(U{®øzÝô —ˆ¤˜$êsZ/7àðé;›8ýUšà¡_/D”I;õîlÏ·Žm¶åµ¥¥Åš©Ã”IáðËζ–o òQþScpiSD ½CqŒèçeÿõJ1ÞëÚ›û“Üvb•'RéYÞŒŸ]½tw2ÝÝ«’½ƒ)Cb,¬ú¾Ø=;Kº½fv´n`oĮᨱßSÊýý3å÷o¾\¯tì%†ü Ÿ‘/RW²iCD7Ša p1åpÉP‹¸CÇõf©³£ ©ƒg× Mb ŽÂïß•‹­ A,БŸ…³_AóNlù$ŽGbmESû“Æ7æBU½ú¸æÌóÍôªEˆ< >^{©>R ¶ÕÅ€" –Ð4Ot^ù>9G(±ì«VÚf’ÐR)ŠJ¥Ñˆ‚ÔÙ>5@ÉÕúH˜7%»q­µ+ÚÄ·Þéôåa|@\Jë_A¸[ö§ø³ÞäÑ­J݃X:3ó÷†ï·Šš³xe ÉÑà@‚7CÓÛf6b¶Ëç_–n_‚®§Ziõ›Nq…lêú|w·hYN*0)—8¿Äˆab&wMYXr¥ ïûÎtÁÎÂ8ÕîDÞ’sÌYfDGöÒî2z&(Rçºzè2ÎJ×~ªœ~ñ5ª6ªÒ›â.FAËÆ*³¹CЕ”ºð-”"NrnÒº£wr‡vU^;“\¿‚L@äÀ¾X,h“qÁm>pãÒ;:ä+Ñýý“ñ¼gºb•Sq5©qýžMcã"myÜ ¯»š–µ­ºŽŽÃ¶:/OP$AKŠa¬É”&\aÝŒ\ù6q²k@õ.€KæUüÙBºèü@\ñäÍ ëãb*êhm%v¯Öòs“,æþѯòA¸×êM_f@´ ›ÊÈ!µ ‚’!fB’ß—Ì*ùG‚êè¯ÛQ=$³ÙCT|}ÜøäW€L£—?¾ï3ÅKøOê8²½ Í=ë mJÍ7?$UMXÅàˆ0¥",V½p÷5ïhúŒqŸÊ*ê.ÞÉw¸='b_>œñKmˆà¼ ?.oÉcëûZH?ð]Cågk:ÒpïÜd5¯Ån]1EMP ;?plÆêL’#Æ›xm¾²·'™ÆBØfXÚê'¤=&–ëºÖ§›¬ÁDj+¯tP;šW¤5Ñ ê™.JŒÚœQÛ¬„NQÙ3»æ]¥dº©À¾ÆFŒ—°p>•EÜ{oç´G±îbS^’‘^3<:Öߤhã;™0% ³\â‹t¸.›%L­E¨zâ?³“ÃÔ®…~Y›ÍÕ–@’ö\Œ,£nµ]²ÒNŒÇ¸ÛÍË£lÇ ¢Ù“ƒ­A{dƒÄ[ýõ§é³4†z¥þ®»aż˜O@óù7ÌѡɎÇM [¶Æë°¸Áפ—•Kñ•Û0 H_öíS“QÀë¹ ÊxùGâäYkqÑJw†³ˆ8›+n¸±8¼cȦ9S”Ÿ“¾›ùê½êºé&öûÕÄÀºc×¾¦bMg¢Á `æ2r°WÏ{XMêÎP¿z—y8›“´,Æè“Cþ¸Bͽ]BV®›š"c‡çzÖ[®3?«ê]üXö9:NÆzç|^ s9ãÈënýòžË ‘O³Ä÷=\•mýˆË6òL»)ð`õ•èüMSï‹Åæµ»[_„éˆSÏ}xƲxú|#¥€;CçÅ4·L»&ƒ~¾G‰¸Æœœ±†MkVâŽÄ,C©‡Ð gz{G8–ïU°‰Ì­Žb ·Çjª»a¿ÚâdMoûöœAKU¦“gš -[åín¼¾oá^´h6~Ìo#¡CDJ•¯/s¿¤Êñ®nõU¥¢=÷ò¤c2yQöDÓÙk|l%º”ËÙ{Bz½«ž®ÓÊfæw¦v×D¼“ŸaT±6tG/yÉÏ^ôê»à«T—zÙ•cºó}[›g¿È§÷( š³ç:ßÿ:È”5ýÌú £*`ê44ÓÚZÈ•‚8õ¦ÍXíÅgWj›Am>v¿£¤“:Þ™”»ÌEšÑb\d䦶+ËYœ gÍÉ…Dc3A† Ó¤Gªµï’Q &¥&r‡·W:,ê áY½›Z@¥EÊ——¼ReA­ƒ »K¡ƒ(Q]ÚõqR^VŠRˆDjׇ ?Ät5§sR`¤ZœÉ÷ã‡Cä HÚñPö‰µÛ«7:HAÓ7p¨oàüba‹É3W>"Lô–¤„½Ê\ —~Ê*5èš@y¨v|©2ÂK{ âl@ž[¶`\’itS}]Z®ÖL ƒÇWÖ$;0$jq çeßU¸­‘öw­ŽNåb`¬²+Äþ‰'Fƒ|Õ–z)Ræ™BËý@i«Ø•‘ˆ«’³#Y+‰ÏÃAÙ@ùûJ°'#‹ˆYhVðâÃ/×"~¾ÕÕK•Ûºf…µêÃ*cZ§uEÞïy‡¬’^züQXDõ£ì‡ÍͶҸmåsvIi %zÛ`?ã>[bÚ™ûEW£—aza »ü‡[UG¤ ñ¡^Qç•b#kZ…qš\–’Ò:Ŧ '~r¡­²T/çkÝ-§È…òÕ#J_ãRÌ™kg÷‰-¢ù:.ñœHÖ|¾Ûâr-’—ƒ¾ª^=Ÿcó@œÌQ<erÍ'ùÖå®§†ˆ2aT†íe¥‘Ý‘¶]¥¦9p-í5˜û{HUÇ~}hÿKÑàY£¹Ÿ³&1¾Æë#Ä­Ï󜶌Ú-vmh‚²4pZûÁOº\)& mk·û¥äéȯ¡ öá­÷—>(œ~yKæÅôŒ>üˆµëÑ"ù2•æÓÏÔ˜$áåühÿ‡ìÌ÷.­; Ü&‡£iíã¶ÅÞwêâ¨åŽ\!×gV:¾H-)›[?x{ýEÄÿyédñùö™róÚ%gs™ŽeûÃc¡&HNN%_ Uê¸ésïÌéÑÉÙ¨n¼"|¶!z–)š°’b‚98ë¹uå; ΓÈc6žùÔ[sUe"åjnÈ„0Ú=ºaÔYî¨Ä’'¸V{´Jt¯­+ 4 $Ÿ6“œí_ÜNSØ"®: ¦V5«R45µ†æBp¶±6T¡A- ý`æW:»/ã())DÁ8ùx:»AÍfÙÞ4ã M¦—ü#Þ”Ðá~H/kª‰ž¨áã¼X#O%±ô\Žæ>7Ÿ'ËŸ“ªŽùç¢ð: “ÁnÈ=2ÃmZ‹Å¯}`äµîl“H±[›~O›«´AY4Ò·€ß«+n¸bÆìÐ0i0pÏëùļtMž€Rþ¾ÿd˜’æÁ¡1z÷øímkd:õnD(óÄÒ¨xö±áí£³_5Fç)´²—<ž$§üÉ{9‘ÁAìþ–ˆxwc›>…¹Þ5uÄ=¬YOÅI°¢Mêºî…¼^ÿƒâ±¼iû $‘IÒl¹}ˆ ¸;ÙNEXÁÄLKv­Š¸½¶YiO «ëêg+sºšpëÐD× n´Ôh ?Phó…TKpªµë_+=e_W×û×mó¾ÌeO.~÷)© 2þÓâh¦#&¹6ê,pñ»/a—Î![Y~Nòæ²$uéc¼.¼ðw†Æñ1Û¦{&ì11²\'ŠO#˜Ž&×I· è ‰ëµ+ËŠ'Íú/Oµh£7TôÕü“pT#å’%põ`ÿy(U?™±v U{w×u~?ÿ²ucå§c]óƒWÊ?¦ *k ¾à‰‡kH@¬UhæNbÓ¼ ;UÞeÙJW±Š$¡Nꬪs„.uJ†õ/2ˆ«ÏT®¸ÞM•›\;dúÆn?ážX†jç ÉàbV:ƒ4žéMYJhɶ‰à¯ÍN‹ šjŠíØÏ½\€t(p»Ïr²©ÂJ¾È¤·ø_•‹1Ǽ»ƒñ£yuÁ!tìØ<êD3^€ªxù=ü•\DNWÈPß»“NY§ÛЪåyó4‹V>í»OJ¡•^°ðËÚÙø÷å%„h²ªxAºAêq€`õ(Ì0~[TóN’xV'¥Ö­C‚@•Íëuk5A’"ð^ié €âãåâ—}ù·òþßã{æ¦Á|]4¨kwÂ×÷¤i,g‹[åÈ%,ç§¥$eº!D‰Ç"òV«¥ÃtvA þ’V;‹Á»€;•;®)RFÝheCÐÍ‚ŸÅ"¤OÏ‹j´+ê>Ž–(ÕJáªpf„ؼUöí“3´N¾‡/ú¦uî`‚½qUý…%Œ¢¹¡v¶¾ÄòÚøs”‘#é £Ý*tù—«Ì‡©L§:‘M’G%ù)›æU;>ö{˜Üä«(•®ýÒ|6Ð|,EØV–b‹ëàb„)}?t´¸9•5ˆö<”8··ŽËÇùR¸åák <¹$qä½2ƃÖF>!ê§oIg< ß²|•P* õúŠß“{êSWx³‚}§¾Œ÷’´ œ·çÓ~Ò\šnÜuÅb«^¸ËD™ß0;ôìŠþë}csHÀcZÌ+’MÀg9³N¼¢î_5`šðºoÛ+üÞ]TRàôwºgƃÖé‹~ÔØÚw7ÏÙwF…·nu^†(&àÄV’ 'Þ/<ŒÏ›@DÏPyC{Ò©Ä¢"EÁ3ï‚HœÔ'Ì‘J7¡"ýHç4]ABÒÕ$¦]„CVÖ*ü«üjeñ^Yƒm¡ó½F9Z¿R<²‚ T÷$Ð?bNž¬·ìñ©æªµè–œW?¾Å]éŒÌVa_¥môÜšn¥fznÛç±ÁÈ[œÑ‹hI«÷i·ÊCôÔ/rK[Ó“õûv|ÜÃZBš|ìã(<È3ûi‘6¡vç®þë xž ó™„yIœŽÇ“¦lÁ)ï \„¬»#í!Œü6‹òµŸžŽSä_e2öõʵrSžõ3+œ09/ådYE½l_s³×ÚHš;ÜÄß<qÆø©®Ôú”Å5ŸÞlÉÒ_<ÞzYÂã+9šÜ.Ô©u]å#1vgO9eÊiÇÅqbtVÕÀP†Íâ;I^@´Â÷ZXŒ¹Î|¼my£øÄ¦}Z,0|câbšì§§Í;îä 1AúB꽇ü:dã4Á'jlîCTÞ¡yÔ„|@I‹œ¬MúÅÇuõ9.Þ&Ð.ó=0³%‡Ü®1ÿcM‡ÇIcYºÑ–<-¢}TìN·ëo¿JPÅÐ}®1†Z8’äOwNˆFÜï-àÛ··W¥[:cfНeeÏ;—x»ÉXÛ}½ŠQ‹›ê˯Ã3Ï@Æ\œá˜+¶!ÛÊC›5nôþTÈû!Ž÷,Hü¤œÝ;áŒçdêé›HýRÂðöGõæ:[β$òx!ˆT­ hÊqà«‹7«eaù ÄJ‰O>×8êhäô[%úÚÓ[Ysü¨7è±gJж~Gph½{{âX#ó@¢°îÑÚ¹ |öÑfÜZ×xÅþÒD®Ä°øì+-×ÞAÄå}NªEb[Ö7í-„&Ãw¿†{PŒ=#“a.Lîy7›åøùÌÿ¹::\®©;~ù¤{*õį{ÜÃã=¨žÄë|Ú“—á9(¶âímOÓH»¾(ðXcÆŸYÅÖtÊ:gdí¸¡¼9I$¨Ì2ÌB#B9’ÜùzÓH¤°ö5¢5±¥A ýM ÐD‰SE.@òÝl0-»èÎçä™·IKEÜFªva-ÑüKÏw.•eC… 1Ü•Nù/ïÅM£¾jú» °×Å•ŒDÓ¶3âÙŠ¸ÌÝQOMXF?s5ÍÂÀçÜtv'Vœ2÷|{-ˆ/ˆ‡¼‘m A´@ …rôÁ eé*'¾) Ú×êH…úƵubëgWw óž‘LƒV¥X6RjT.qNhƒˆ?NŒˆ÷²?\7yð¹¯è”iw*?%ê¦B‚ÀÌ”´¾¤#…¤®“ÕtDã5y"}Nu÷YäÑÜ{CD¨ò„Â/ÏÁ'q=M2a7]Ì”2NØÇRñ¸c§÷1ïçú…«xìŸÕs<$‘tr8çòøàX(}Ô†z0ïô]d§_áÖ‰59»èÐ}9Õ'òÖ·_òÞÐK7i¡~2áÒlç“X^e"ÛÕvpýöÁdd®SwkääuœØÎ{–»á'sr”xË4ûÅ{…½ÍæË*]L‡N³Þýã ÆoQî¨ÇJóm[0™ sÕ¬-Àó«Ò¶àfó·«ÙR·.ÄDÍ2·J¶ˆûæ¹ð—)q.’Å꘺û¯rFçi"5Ñ\v=1òE±ÛUå‡ÓûÁL—OMµs|8&wLÚ|sN{Ý£‡vgï2ܳxDül§•¯+gÍouÆ€Ò–™®"Çù1¾žá$Ž!%ÑéÎB`ŸÊužú‘àä—ƒàÈ9wƒï²Ï6Sè‚Jq€þ‰æ÷_±lî†ÇÓu H:Ç´[=´‘Ø Ëq{k]¸w³ÞëJŠ-Ú‰kKéu¢¯Öw WŒÏTºÜÑ~õl°Õ·é niú­Ñ±Fÿ®rÑ}ët{’Û“4²Ÿ,¿ÄÎf©þˆý5”¤+‹7:ÞÎîÆó‚™C3 Í4ÂmÚɵ®øåøøBwG8Ò÷ÖË äf‡j·“Sh4É]'Åm'|Æø‰[ªG0.˜?õó•Uã /£õ%jTG‰™v„|ùrŽ$J¶õiî½7@_LÁ\Ïq-QsëÐÙióöS§!íÂ_‹MªÒOÖˆºXǃ7>µzû¯ñŽ=ãqýNˆ’y¥ÔÁRì/‰“-$@5Ö‰—9¡[,qÚÆÝ1Óºó͈Y‚¶¥PdÊã\ÑIÀÒ‹æö3ÂÖQǵ™µ‚÷§â®}9zµ¯ÈoÎtxDê@òêf:4ë)ÉÅ[TîÆƒÉvKö³n'ðv2—>8G4%“xåÄþ§zÙÑER¬6@Á€ÕF|íѺf«‘CBíòr‡…]:µE@ïâøZ’õ4ÝãöôõÉ}Ûã›TÔzxJ%û Ì$“ƒú{xIòËtb“'­9Ú¾èŒwÙ"eÛc6˜@ÈdIZ,d’åGŒ{þ-ù"ZÂÁÚ#ÊÓb!„MËœ©Œï[½¾ÍÊÔ×ûUËZÙûúHÅ‚÷4LCo€+í”ÆÍ I蘭“„ÐÔ‰ ¾'Xób‡/ƒæö¸n5( ±±ðüêïH¹2óŽy)ÉQÍìN¨_шK~¼ ÔÒôŒ!}°pZÛåÍÖ•‹SŠdÞ…‰ 9½:¥/ñfOIÔ¨B²¹ËýHú¼ñuµ{¶›Rµ×*òÆ'զʶ-ûî„ðn³•Ý š^FaPçÀšæ–Ê“•¯\%A»àé•V\uâUÓ°Eî·•ò,ç\ŒËï éÁü®Ö“‘–"Z<"© màsÕ­÷M“¼‰uü:™3þ½ßem å¢ úÃyÅ ³õІFpv¡ãúHÙmHŒ”@‘+Cˆ…~Ñ”\î…páYHÚj-–ÐW%úf̪Kì¹\~ã «¢ÓžˆúqÕ £žG–æÀô¼*ä軑ceä•àÛGb?'M£(ÞPȪ™¾¶Í•VÓ‘>|XA³ÓYSPI›zÂ<]ðxüãvƒqò!Ú[5!01{O„—rKÿÃà.M$½üòø(*ì8ejZþÝ)G¥ãw!Òvµ‰ôîJ£l;TƒíW^†ûâNúÊJ soß›`å2¨®£®¦…Úk5äòñ*ß7›W쥽šä}+µÈ,³ðÃ%y]s–‚7ÂÕªßxï™Ñš´”G“Ûõ¿L7ÔéN3·Í)pº[«u[Ä“ïtGA‰ÀÒF¹G¨.¶˜RŽ×µjÞýùÉ×]ï›;.©/ÒLõµŽlñSL›Ý%ã-ë~ìèêóÆèëd†Õæ<Ñüš}²[  |\§ KuàL×R` ¨ôLV~cÈC•ÞÒèN-I+55F8’{mÍòÜ;ßóÌ+¯=}&—È%ÛˆêÅâIõfjSïš´œKä°Þmû‰-»'`>œ-Äòëós¦ÚæCýˆãä´PÆþ¹ØaχÎ]ª¹žž×WÑÞ„YîßX²ä¬KQh›ÑptL¾€œ€#çׇ·?ä ôÍ.ÿkgÊ endstream endobj 80 0 obj << /Length1 1467 /Length2 7558 /Length3 0 /Length 8560 /Filter /FlateDecode >> stream xÚwT”íÖ6 ­4Ò1”Ò0tIIH·48  1ÌPÒ * ÒÒ¥4Ò  --Ò݈ô7ú¾ç¼ß9ÿ¿Öÿ¯YkæÙ{_{ß{ßûºžµ†I[GÎnQ‚Ã<@^~ ÀS  €Ÿ_—Ÿ_ŸMŠt„üËÏö⊀Âaÿ ñÔB¢| $ ¨‡TÝ@APD(*ÁÏàçÿî*P¹C­¼U8 ‚Àg{ wör…ÚÚ!QçüëÀæÅÅE¹ÿ¤äœ ®P0Ð!í N¨Á G€ … ½þ£»”é,ÁÇçááÁ rBðÂ]m¥9¸P¤@‚€¸ºC¬¿Gh‚œ Æ‹Ïзƒ"þ èÁm Wåp„‚!0*Å f q N詨´œ!°¿Àê¸_È üw¹¿³‚Âþ$ƒÀ`¸“3æ…Ùl Ž€–’:/ÒÉ Á¬AŽ8*ä‚:‚¬P€?­ƒJr:j¿çC€]¡ÎH/êø{F¾ßeP׬³~ wr‚Àüßý)@]!`Ô½{ñý½\Üæý/Ë ³¶ù=†µ›3Ÿ êâQQøƒráÿã³… Âüb¢‚b"ˆ â ¶ãû}€¾—3äOøÛšÁ×Ûî °Añ…Ú@P?øÞ;€tuƒøzÿïÀZø@ À F¬ ¶Pþ?ÕQnˆÍ_6jÿ®PO€)?Š~@ÿïÏ¿ŸÌQ ³†Ã½þÿY1Ÿ¾¶¶‘¶<×ß#ÿ;(/÷xó<Âü ¿€@õàûŸu´Aпûàÿ'WfGeüÕ/ê¢þÕ³ûß$`ÿ[!€ÿ,¦ GQ`ÿ‡éfüÂü`Ôðÿ›ïRþo4ÿ]åÿÉôÿîHÉÍÑñOœý/Àÿ9A½þF ¨ë†DÉ@Žì¿¡†¿´«±†º9ýwT BÉAf‹¢4Pˆ—_è/?¡õ„XkC‘`»¿hó—ßà·à¡0ˆ6ýýŠAeñóÿW ¥2°ê5‚@qó¯’òÏ"Û”¨þ³Ený[}Â"«+È µ|”% ð¢dj ñüÃn/ ŽD¥P3ûlà®ø¿-,àCIØ ôÛýÇðAœQ:„Àÿ8ùQ^è¿Ma1Ÿ3j§pë@òù ‚Ý\]QüaªûÙÞˆ'Œ?3K†Ø×„´üª’£õàY–Â:Hùe$À3œo‹ìQ³ü§—‘>«Vª4Ó T²°o×”wù•¹øíÄ{µ–±ÎKè'£Ò¦-£ÕÛ©»ŸèñÞçtÌSDÑr “ä$Š\{дé_wàÉXÛöè±ù<®éšŽ÷xD^¬$ªÚ¢ÙÖQUœ®NA'þ|wYÙhÕ¯¿&|Jõ8kÙ)&xåYd²æ;f5©¶ ü8J⥾Áþy’núO¯U݃ÖYÃ$Š’ýt B8•Ïçs ¯³ŠÜwÞ‘z[)“=¥ÐÓÈaÒ¥Âïš›Ðx@evÍ‚cdŸi¿CEÔšûn£À|!(Ü,–œ5ÁnûÊÛZjAI7 ­ñ[øàåù ÖÒàªãýŽ‘föt»²âc¿Ïrz¯íS*À&<¼†Ù)²œnRN0ÿýóFe`²”gfOþqJ[¨„tl&^’µãCUíæ*~KkíÎ4hÿå„Ym­.à-ˆÔÑ¡/ßÖ`MÖå•Äð{Ñf„xNBbåò~ŒŸEƒL|Œ^fú}ÜQuįõícQw$ñy¯ï«†õ«c#6K«ï‡Ö¼A&ûµt E›îüJk"Õ?“‹²©\$kÌÌ£¤Ê:žS{mú„5\HO½©ðÑöÕ¤mêäZHÈ#Q‘‡¤oë/ØßáùƉÑösç^'Ê#r?0϶ŒÊÀfÄ«”židºx8bÔà½ÎdaëSî~ºôjñŒ#©ìŽ·Tpfl”(SˇFgx a¼ëËJå³zö"Ê bÎlûœ(¶ð ÁW¬GΉ vFpgü£*1Zõv“ Õù:¾“oª$KvZë/N'Iå™ßžùˆT¬)^{gòTdµîÕ@9T [åDæ"ýdÖüƒnç¨ÄÆRéÔÉ8§—Ö|>Òºñd ¼&hãf‡ÞäAiÁ<¯ØFü'Å|}™Ìýd%ŸäÓØ"´ä¾M?£É³L{æ¿g@èW»x¾/ÔrÁÇÁ­«Þ{ß´‹OEZˆoÿ.ÅF´V“ WEpÒB(Øõ>!ºUELo„ûõÜz¶ ¢$…RQCã²¹GU -&uÛ=róP{cV61¸G…”¾ yäÝ`aFìç}RF®ÚŽ—–Qlƒü|vƒktWóöºŸÉ™_'B|€õºZ"ìÏq&uS¦Ÿ oç)ÐWÞÍÚçq¼Æœ$¿ê¯°/ä¦É []ëÜê½å±ËúæÕ8¥Ü · nâ£sZEcZÛ"•©²>]¬õ,ÚÚfˆã^LŽ D†~H°rÒæ¾'–ÎVÉâ•J°8*Sõr’A¶•¤SÊèiÜö|ð1€N')ßUÓ°M”´L@½®²‰Í:’Ïþº³9#Œ´¸Šã–æ¶x6"µÊ ³Gߤä$nes…6ëªí:±åÑ,ܺAÚ}ò½ìû'ÔÓš]{,‡’߯É#p¦ç­gbRÕ-wfŠc«9áy(¯PïêOà6¿£?TÜWƦ¤)çšWÎ<Æã_Ú?9Á_ðÀp3Š–Vú”T§ BözI±„Êž®ÒÁ|´˜#ï;}}¾9˜V£ð`VîÆ>órp —à(ï,­p^¼eº=p¶Àá¨Ùø´œë.v­´+"ª›Ýfa~¾ÆGœPmgÍÉ&"7×hÙgã(7Q£L[zUõ4¾{Çþþ0 žïå{MšÓö\ ×Õ$û <‚H–7u­ ªfLÀ¿?Ï$“ÆM˜±ýJeëÀ瀫Ù&üLÛt•ÈÐ9IW†°¦;êqÇ%bõñ “®§êÈh sÈ´Œg€­Áü‰ÝHQëW5¦ªÂvëâ×)zß ‡k¯]îäÂj†ÃãÉ(öp?C‹Æì®~j ;£…IH.D¶˜j<s£Df^iÜêDùÓ]‹Ê3^Nn¿im­?¼Õööª¡åUþXO¡lII®ÿöK©á‰§'‹OÀ8i}Û´4Ä ˆŸ÷1m'FüÑ ¿*íÄN£—Þw:—¡›Þ¹«i*+‘#°¡HEã¿Èì#º‚EжoÞcwlä*¨óV]Zþ®˜MþJAÄ6cÞÈ¡ùÝ–]g“>T+Â~zr>6»;C"Y³\JJ™âf9\V¿Èñ6mŸ|ýÜÏœ´¥áâYnȦÖáê´’Ðö{¶ÆãBì_ß1±`²š‰…ïÏÍŠõºìúÚÀ ¹µgï·?­ˆÚÝõZ†í®7¸“Ÿ­ÖêÇÛ¥Ù²ïêws‡›èÙB4¡Üc¡Ä@‘㉓Šh›'sÒ镳^ÍÒ£ô]ï =|‘ÉjÖCU35Ø[}Z¯ºKꋣ;„"’µÁ†*äßZ†ãÑíä‡?ÛõuUR<ûåÝ/ùñ3eŽ’Æ«·ÇÕA•‰Œç%™øæÐÍ/võñjâDLÎcüc#vި턇°æ1DáR߀$Œ^]qXóT'84Ê#¹àAGU­ÿ•Hn“UªÎö5$Êÿ„&a4²ùžÙÊ\-Ó©òóØÒläÁ¨ÂåÌZµgìëôæ¾³Y}pKèj·2ŹÓfç/n çóÆ–¿å\‹Ï;2ëÛÃò¦Ï›u¾ÜÉgTüI(îËwpBÐÿÚ5PšP…éÖ½Ý-¯¬;ÈHÑ>ú­€ªŽR·Ì5àÖ~ôà¬ç«ñ7ï]“Ùh´Í—ØÑŒç±Ó ÏËgÞÛ;ÓúþŠÊ¥•¥3`!7îê+‘áÔ<„ú~(õdƒ|¹%Ÿ (±<º Rd)|!fÿ¨sñˆÁ$÷u°Œ®ñqÚHÆçM–ªè£Ÿ[ÜG|ÒùÊßÌÏI„«#š$_Œ-y›‘ž‰oJÄ•nu²~â!–<‰ŽcuÝ<¸¬^þ’’R:|`°Ûw4 ]ª¸bwíÚÏÒ¸ŽšYÏÿXĺrúæ©î÷›™Ò2.Â\åQê *×îyà³FÞÛô¾ñNÁ ÚV›á¹´;‹ò´9o•öØügÉ&ñU¾Ý|õ9dð‹½W·¦±mNؼ^ œª*$;5ÍòïÏJØò÷; mvh¸jÈ!ÜÞ¾z`QQJoSQ3K5§ûŒn^6Â4 ÁܼÎó9gpXñ‚NÌ=æ°WÁ GÊ"Á :CK·“†ãD&Oðk!ÞiàôÅâÜ¢—×纚õy¤v/ȃÐ}hãîŸc¨‡ç—žª{hÑRyt| Mûål8–ò¢–,,*DÌ•˜ÀÁçfé©£ôõÐëÚ·X3IoífcUù 4‡µÒ«{¾ÜCg³D í¾MÀUÊõ[<·ŸŽ]³8$Ö¤<^¼g°¹ôX±›JÈÀbÒïW]©x.§cSØ]G©rÂð±¶åôÌíBZÇ-«Þ/¥õlÇG {\&>}90Uæ¿.Áèr«4;j¼ÅÉÊøæfÞöξ!´¦V¥B›¸knX é£<Ë* d¡cú\ŸÌÅ¿àèo'Z±Fxy l±ÏT€¾ðÔ`¬¯Ì«“9ŽvéÆçaµ&ªžöcÑþ«0gàÇàL={ÞK9†¡Ä“aÅœÓÏÍãU…ãÍêàÕâÆ@Cçï¾¥ÄírM߯/3ßÕRëJ§àí!; ­àŽqJÎê6^%òù!}¸r[kboåL™“líÚí¨gl»g“óWFÎç¸ÛÒ¶¿œËÜ9ÀÖ”oä’g™¦›ùDŸŠxbqó>ã$8 *T^JO)#Öy¼O¸ðJ•ZdPiH!´µª )ô´¡» ‘>DòÑü‘Œ0ÐG‹Ìq2à™b¿7êx';AA–šùI£Ö˜¶7o¬/?„þÞd¯JóúÙqf”^%ÃN‚©?»ØŠÃ£”&îsì ¨Uzp`0Ô *û" žâ²5ÏZÃö¾ý”8*â–8–€Îv[ °(?ÜR (Ú@/ÞýR=Oq²åƒ{A BßwóCt–‹ìÑ£iÙ uv’g:ž´§Õjû–[K :FöðójK¤;¥°Â=wf y¾…ï°°U•©m–SW¾Ç+Â>v?Ð×í—÷öþ„V¤íü÷›†l¨CÁ¥AÛ‘Ô¡{îσ{^—ûÈ7Ñ™»/§Jpxñ0p¥Ì±M(‹@9²÷æXBsјAÎpñ²ð%õxÃ0\† “h•c¾ÊÞ3ƒwÍ^„Ί¤]öRúF¼×AÐJ͘)+ž¾ 7Ú2è1Æ8n^ÅRÅH|Z Ò¬.+ß©úv𤣻¸Þôš›AˆÌ©Á¥jõ¶uGtdÉvRÉ–UoÕÆÑ-Yk¤´î7•p² íÝt@Dó+°/:9šÇ¹ÄɽõŽåã²¶ÉVI!mƒ‘¢x-+¤<Úfç·ß»FjßO*Hþ?~ «v+ÝpD»á9g aa²i=Á&ŽZBûù­x¯åÞÜA©¾éׯ¸á²dcAŽ$o¨ÙÍí1\ Hºviî`ŠT²¡2¢6qãf1½G‰$hwl\¤Ù•KäïâÐÂg# н ÝBïŒt_`ómÞËì«åJšœœ]*jèßžã6ª×X}PÞØÆ@S9êËÉeQ˜àÿYòç>QvG#|äÝL*¥;ch1L»ÚŠyŽyZèÁ€îK1mxÓÙIVL²¯ºajjýjH-ë–TíüÍŸc7e}ÙÞ‹y|­`š&ýЧÑÖ™WPÊmX×¶j˜€eõAi¥™ÄΑUNâƒÞвªmQ]üzÖÈŒKþq6Ì£—ÙWVŠ'`† êϽ]ºVéV'—t(ØgÍ!7¯œ×‘ÞoõÝ_7l×à™kWÝzç]i.÷%?Ì#+wT*à}ò²"øÉLÕõ8Äüa¡°`\’ÅÝz30“téÎp7ÑtSe,%B®`K 5»öϳ(£~Ý“¨bÿÍ·Ñ@À6‘ãµí]š¨ÄððR¹ëc¿‚ìjÃ;Â<©JlîyCNš%øz‡ä7Ū˜aaBú×jt¿¤/ò6…ïŒÏDcL0Ãá»9 ƒ íÞQŠÝ® ó*2QÖsæ„Þ]¦šÄ»¯6¿ÎiòZ&‚xWâRÑd¶2jö’]Û ’+R±1ŒµÅšMO7¯Ϊh„äG.;mÜc£lOØ aöR¸µ´™¸åòÚ¢¯Ëw£Ò}»¹€qö¤ÍÈ÷ý¹z¤õ«¥)ïïéÞÆ¯:ï×GYØÌMw¸Ìë™nÁ/]|ù<§DF’X{ó¨ˆqYÚÔ™ô¯¼lÊÕ‰Ì^ ÆÐB©·²©~M.: ê„ÆT &[1õ›^OÝíeeï&uÒïS}6@‹õƶªpöäaçì}Æôü|>к©!@ÒZ([§pÖ„-`°$áÉ Ø‘¸xaNT3ócÿÂrÉÿ͵”úëXÈnZùE a6fX’lô鶃ŸéÌ •àaok*ÙG8‚§͘¯ùºm—ïø£¥eÞÊç>osY›j4%ÆIw?hEVn\‡º·^ü¸Õ\¤ö¦;™ã}ãˆjkÌM\MêõiOš=~¤¹LVțȜØâþIÒÏd¾è‘6^z™“]ptªÿÑg×l‹Ü!õå9OŠ ×…ÖáI›Š™ÜéSù” T{âÖ/=V\„fïáÚæ,MhyÅm8ûGo‚íÜ}űة•(´Þ3·Ž¾»Ä.u¾È-¾Lrºw=^¶%&Yÿ½ÀÅdYÀú.”¤‚ëStr)ÙE³¿•¡¬Ö9¼‡§Qñ\<Â5&[ÅæÎÂ=¢ÿÕT=P²oð3³X¬¾Í;ôTg˪UFÚ—î±'£(VíF^7Y,ßùž YØ_ÈÖ¤sASà¯×mËJªŠ"nôãÁmòˆ‚æ"oÚ'äRR ÷Ê®2=O¡hï¼5”Jaz­ÿ<„#8”qàqŸ<f5ó®S ,Í2ù––4ÝÕOÀ§«ŒÕO—:ü%Ü—>èI¨ã17†É5N®³!—Æ)Ž 5«÷þlæ ù@†t<’õ¢2h#íCY²W©Ú/g°FÖðùæCn~X|u´â)"1ë²Bùª¶´™ˆ¸ðû%// —4d›·ËøÁUëºèÅEÁ1Që­êœM)̰ ¤1rèê¬òöhI *·Äù—4ûÐèü  ¬$q’%ÖHOʘòíeò~¶Ñ&EÃ)µsE3ê» _Ç$«}y  8Ö¢’Oy¨ß€¥Áñ«ÉOV×x=°’tpk˜Â‹ôA÷”"Áê[ì/ÕÉÑéºlJz>˜Œ?ºa—_ÔÙŸ,Dwl–,ìG$ðÅê¬2qšô—Í)aá d$j5µaj«j1qc¿¢ú[ë¿ê­ªs¥î{WmZ®‹ÎÚÚãI8.lP°øùÊùS6[bm¤¤7÷bÞ R…„V-ÔíJë5fËžYä¢>û•E™ý /)ž=%ðXåÌ.°ê:{M¬búK#cî ˆ¼¨Œªi åð-߃^mdIV’^š±j+Dù1ÖÍMªz¸Z1©÷P'oÎÛ@Ì3ÒYœÕYvEVÞ¯”fAǯ ¬p{MDa±”>l0dü£E[U{ÛϘñûFßHï4'6"ȯ&¿<ÇÞ-—ÐÇïxPØ¢eRáäÔé:AáÛè`¬æ”t½b1}y”ù“áÃ@"aWÂT›P 奅TÌŽ¯_2¢_Ôòz–}[*ãÞ@IXÆ#Ù¸ZZHRÓNÿº’ØîçBuãÍ¢kä9<=;<¸_I‚ƒJ¸à ŽCL„†k9Ó&¤YV¹èÒjÙæ;œž?,µÚrÞ‰êÐôâøc:šwŒÈÒsÔšåjmÓರÿ¨eu}Š>^­¨÷™ ݱBÊõ§¹ u/±ýÙC«TýXÐR.¡ ÆŠ¥å-7þ¸@ËŽç ÍWÆú!—¬9Tš_òS ‹U¦ÑMÖ/¢Š¼Z´(²—ç÷xrHH®áE® jU§‘2dsd×’âvó•<;5ûDSñ"8„Ò'ŠS£{‡0Sô¶5›ƒ G"}{?¾âü@#Ú …<Ý«.ÙWV=§{?¼Á\áÀãQ‹ƒ7¤lI/–ÂoÛvnUˆ&:üºdD VÚ8ünN0¦7'‡'ž1Ä4(¿e™½—°ò%GcD’”›™ªÄ…6žʩA&Åâ`öÛ³Ól!™Õ§Ô_S&¡:0óù…s×ò ;–xL‘³ì§äµª9ÆS\™ãíµÃÀØê¥nê9éÔÜ¥([•cº²V“°å‡–GõÒúÛ­y³-ª‰¼HÄWõÍ ³ÐÙùíd«éÁÏJß~žòˆ[á"2ƒ”rÊfpÌ:ìæ•&£,Ë"%Õ÷KÛpÆòTVåsÇ#xèH¶œlC¸Ó󀈞Ý:\sÞÆOØ÷pkHÂ{c_>YRüFúÕY$ðöÅ"¿OµòW—qnA€ˆ–4šDkp¯¸oUT|Ëó<›×odtèCRŒ7 Ïï”;³¹{®¤)Š~ãf˜Z÷jX[“èVèF–9*Ê}¸â׉ê9òÁÐ\?þÀ^üQ×cÉÝ„¡z£´}ï"pÿ#³À4zeÂQgû‡2³pFF¡ÈˆnÍû¾/¿Ðû”°†a_Ó#ý^)í9TsË™cõÜÚÇá{Óc 6%Gã¤Ü™¹J7ØúQSP’ŸKýû}„îû¯¯NR±p@NÓIm¿FW8i˜Æ  $4µªd[¿P×ÇÍ:ì©ã–QlÝ»¸ùøÓ4ÜpQøÕ‹œ43þ”10¶÷¶}fµûpnÌÒÜMÝöÂavº¥1r æÙh×ý2¤¾¢ªV:(óVæ±ÏØ X,nùÈ~i. ­¶ù—O~xÍ{Ía=iÔ©a.X¨“G-† pz ³xzÃ0Tmü3ƒá1-Ct½”“Û}Uc 4i·k;8¨Arœµ*Os—5¼%Êoìù-nŒî,0ò»½ ‘ôùl¥™K,UKÏzÀ¨e­ü}RU) w,ÉœöHü~Þr_ë¦E]g KV‰8ÿ‰º©mÇl]æ")ÑõȨO´CÛJâËdû¤¥Œ_ù+5ÝìíÇÃT»1¬×ÄÐI&rMî’\ Bq×=ðTÙ]e\ -¨3}JJÄèªqŠ ÷ßje+hë‰Úrö×°\³éë^ ³ Æ'¢~Ræ–‹qåV!3sÄTæ.™`¢äc‹a8Ú["âp˜•94Ñ}d¼ï® ±U®dÍHQ÷qW(YF¤: £=!â5fpTÚ陥©KK’ô–Z¯ßŒHxþltÔ*ðyý^Y öYx6Èv¦ê‰éÚ¸ÉðcŽ'ä¾×{¬sÕ ‰ÃãWgøWLžsöÎB¤‡É&þæQ)-TÑ Ä÷m8r}bÿö_® endstream endobj 82 0 obj << /Length1 1867 /Length2 14734 /Length3 0 /Length 15895 /Filter /FlateDecode >> stream xÚ·p¥kÓ¨ÛÆ$Y±mÛ¶Mlc‰m;™xbsbgbcbO¬“ïÝûýþ¿êœZUYÏÕº»ûî~j…œXI•^ØÌÞ(aoçBÏÌÀÄ•Waf01±201±À‘“«Y¹ØÿÑkœ­ìíxþe ê4vù‰»|ØÉÛÛd\m̬ffN&& ÷ÿÚ;ñČݬÌò {; 3¹¨½ƒ§“•…¥ËÇ1ÿó 2¥0sssÒýé¶:Y™Ûä],¶'šÛTíM­€.žÿ‚ŠÏÒÅŇ‘ÑÝÝÁØÖ™ÁÞÉB€šànåb P:Ü€f€? (ÛÿªŒŽ fiåü—\ÕÞÜÅÝØ øØX™íœ?<\íÌ€N€ÃªÒrE Ý_ÆrÐþî €™ù?áþöþ#•ÝŸÎÆ¦¦ö¶ÆvžVvs+ @QBŽÁÅÃ…`lgö‡¡±³ý‡¿±›±•±É‡ÁŸ™$„•Æþ]ž³©“•ƒ‹3ƒ³•Í%2þæ£Ëâvf¢ö¶¶@;g¸?ò³rš~´Ý“ñ¯›ýlgïnçý7˜[Ù™™ÿQ„™«£º•£+PZìo“Ü?2   €‰‰‰“›t=L-ÿ¯æéüSÉü‡ø£_o{€ùG@_+sàÇœ·³±àâä ôõþ·â¿ Ž™`feê0ZXÙÁýýC 4ÿ‹?.ßÉÊ Ëô1{̦?>ÿyÒÿ/3{;ÏÌÿ¼_F)u1aÚ¿*þNDÄÞàMÏÆ gag0ÿ1dœ¾ÿFÉØêï4þå+mgnàþ+Û6ýOÆnÕßËA øïX öS Pý3äzLìL¦˜ÿŸGýO—ÿ¿ ÿ#ÊÿmÈÿwB®66ª©þÔÿÔÆ¶V6ž| ­«ËÇÈÛ¬Ýÿ6Õþµ´ò@3+WÛÿ­•v1þXa; ›ÿ´ÑÊYÂÊh¦dåbjù×´ü%WÿcËl¬ì€JöÎV¼VôWó¿t«eúùãÕáü1’ª€›óßGŠÛ™Ú›ý±b,ìc''cO¸Kþ v€7óÇ.š=þb#ƒ½Ë‡ à£<_€¹½Ü7ÊÁ`þCôqEþ!n£øˆ“ À(ñ±¥ÿ¡?¹ˆÀ(ÿ}DQüq}ø©þClFµˆ À¨õâþˆbü}èLþ¡˜¦ÿ!¶(ïÛ¬ÿè$£Ù¿Àü²ÍÿÁ?Èê_Ú-þ…Ñ-ÿ… û·ñG^6ÿÂÄlÿÁ=d´û~¤aÿ/ü8ØáŸ*>zèð±öÿÊ›ùãl§áÇÙÎÿ—áGÃ\ÿ…™¹ý ?2sÿWÍ©xþ‰ÿ5N¦®NNoÔ?þcÖþ‡ÿ|}@S¸å{SÞ`ëúàŽ‡Za|wúýIþ9ò}Í4jzïe§N×'$èdꚬ/›NwÂÉ#}(k»âT·B+D¯Þ'­ Ðam‰ÊíÏ>/†ñ*3ûípKÓX?¦ŠN„¿À~¢Wúåóêè£ø¼´[†<ÏÑ• I©ýÁ}@Òãû`Åêxè¾ò¯Yø—ŠYúhõ(½ÀÒyò|“ìŸ8$P.ô04h—Èó·wsh¹SïD2ñ´p¾§Ñ¬ÅÞ:[,1?½Ö+ÕXœ{pÉpupÀoÑÆg(¼ESd°½ËŠ×~,y´òå"Ò¥®Ñ£0²dÖX©DÚ5÷×¹/w1ïå%‚)ñ ï%Ö•7c:‘(bÖ´F¢»Ô±~v™‹¬wÜiôš[§~Zážýþ˜GÔ¶< héõ~np\ýAšÚö0Ò<ºÛë«Y*8(øÉ™FÜR7bm•'“ ²Âe¬G(B·â–ÌõiÂçýåJä y§ˆ‰I‡ ²tüÓ9{žÏUŒoUã¥B×Ö<ê¢;š~Ð{‡Â»Iwêåe®%«¸QV(U~¦xï×üXJeÞz`ã|PãåVƒX¹'‘\ÂûÒÕY1›´dÿþbõH„ÞOëGîB†s*õö8öBeâ½ÓHú‰ÃÆÀa‘ î;³Ã»oßD 0ì5/«ÜÃEFb¶Õ8ƒó¿v©äö8+¦K G‚•Üïþì‡5!=Sq#¶mŽEÖTãÚè)yq§«#§,^–”=â óYÖ_+îÇ­ ÂúzÛÀRß©ø@‚…²CžõkœÔ°s¤Yãê O_Uí¡€Ôk ¤qvb—xlf—ÌÛ¦J¯”m ÀË•nOA¼¸q³ÉOñfѲ¡î.ܰò©.sþpótxB„º“• C`òT PTN™µ!WL‹ñ¾˜c½ã•-ôDÛÂ_í¬W¿qËò_¯G”lSL0\ývú× Grd¾²ÝÐ7üŒÜ=«ò…¤âÅ89ì:Ýœ Ôß»ÅþÔÄQæ!Z_`LQ#a@vù~Rb ×Ǧ\© +±ŠçÓóÔ¡R¢n½M #É ×0@.Ô‹ÊL‚ȸT€Pô{sBÅqÔÁ‘jL÷O÷œü\ú‰ŸxÉX>Š$±háN"Ážë~¥NæSóh¯Ì7y0™ ?cä×Ä—MÈÌTî“þÎ×~d{ÑÐü¸”µ1by¹‘¼YuÓØX[›)8‚k$xÙr‚o8ž©›ÜuÃå¡ÄÇÆü“à†ßeêA d‘—#½µÅ×IÖ•ùˆõ9C]Ò*«AÊ¥ª~fÎ÷·páÍÏ”\oÓñ"@¯­í›"›±n¦á½t[AíÅ÷šÌ¿L#ñ˜6 ¾]ËË<Êçj3UŽÇºyslâ$-è=ôÀœrG2HXqùïÁ“²ÕfµeÖdqŽG¨{é°%Ge½ÃEuD$s:á PÕ=3‚é¾½±Í¢o_Ñ¿ ¨6|”¶Cv=̱=—€ÂæidF‚YJ1ƒ)öä¸ÿÒ³² @, Æ‘³cW½v§(§?™«­É‘ôz(ã>Æá¦LØ£í~±TxjXðÞSD ¥1ƒË¹™þ´Å„´j,é¡&‘?=¶jÖüZ…STe»fBδœIód”q=Ÿ¸™Èh~ÛŸmÓI®$Î’ÏC¨!L­*"Çø‹¯ëœ½B4G¸pó>Û†·Ú{¬žŠ´mI ÒN*&$ $˜Ë[eÉ>µw@ ›jÏPóÌDøÍ_ÖÇ^Þ}a.UuóíS|'¢çžüá;GÀ·¼:ƒÎ{c—"!Eæ“|Æl‰+¢¤&VOBÒô]SdyùÅiÉA×u]pÛÊ÷6¯©( (X4›ŠÇo$}2Õ@ˆ% ‘XM‘O¾ÔqkªÃ«V¸tù¥*hX-XÅíÑCàJÙ ‡r3%8†º“Zá¨ØC7¿•ójÕ”ÞoÝ‚òဣt o+xANþ–‰O-‰®XWqÁQF´6Þx0÷@åû…8C!slV<©M%c·/\õ LÃÚÜ Œ:ߘ i*ö†¢Ñjbåi‡LBy½×+Æa«”Y±54x—ò;&ÂçѪs¶¬è:¸¸¾-ö‡†Xäòëño ‘Hl=ÉJ<¨å›<§ÅwiÆØPÙXT÷f¯˜ÌVE¯·VüLù9¦·ýúȟ̦];îøÆ½ã¨QÜR:^ Hp6ø|Vàl“i‡äß ]UxPijðI.Ç W?õ²Â >¢¸ "ÈMA¬+R^’“›LZÎê"QxÉÛΆÃ4L6VB±ñšOvÿDi¢H1FXgÔ-4ÑcÖ¦€â ñA{±ryDsez?ˆ¢§€)Pð†‹™Áhkµ<ë k’ƒ×' Ç54à%,Uü3—ΓáZ7Ï£ugÝ…Yصª"ÁAxŠA—­Pu‰ÅÄ=‰ÖàR^t®Äñü$6^¿?H’NLè·÷—–ÓA¯ÈÝM{GÎ`]¼zbí0íS®áZkŠdãýöåQ¡0‚M3úÌ9³Ñ—+Ã+íùî2ÉÓï%¿×Hà 9œ}{Ífžø0SšóÔ…a\4Mf ©óùÃÔM€Å›m|t£‡†çmã êL6‰>©—Nj©ƒÛu/b6Ah|úÝÒ`ƒ“÷W2L»mÑ*Qæ§— 3!Òû2.éÏ aó‘²µ ys¼…=Çó‰6OTPðKQ 7% ¼[ÛÅfo•}Ïg  U(/›4|?Jò“wуÑ+À{J¸ù%cEÅB4Ž ,·:GÈ1•'%Ší•:vfPƒüÉ*â:IfXY;¹Ou¢¹Ã@)v«OV4y’ŠO‡çn‡’š‰„ Ìƒ² 4×C(XØÜÑÊm¼à‘ͳh^ ×»¯‡ü8Uä6y/Ü'Q,ÉEÐì§‘@Ó_g,1ò¬ˆR®ƒ IÒSNî× ©X³RúŠ>4Pܙʅª’«}Wh“匭¡UI_8Õu*Î|Ö¾D?ÓvúvÔ-}B(޼_ÒSzú 7)ª.^pzóu9'ÔóY*в¾QTGYhYzyË…¼pï=%«G·Œšs€¢ë%ÏrÒ.¡÷H›r~Õ¸¯I­ÿŠRËÉ~3ÑÎÐ.\F. †*E®þ ol:®ªQÀ[V¢qsõÒàs¦ÉFŸÝ±Ö™‘\M¡>̪q‘z>hë ÷K8šÛÎ…ÜæZÛ¯¶ÄßÌidþèN¶ÂïçÎÉ}?n®ít6ÁiÒÛùËïGo/í31L„¼ã=àaˆEE‰"½±Ma4ýušN/1aÛÁo™8„X8+¥™‘ÑÏèÝÕLÎgRÈñ9tC µ Û #ø´úe6p>1Œ ¤4ÑšOyy–¹mÖ‹xU†å†þft›ï€;¾é¸] ë×5.$æÂýYd —²†cá¾L óÀ¹/«-䩪ïw’ –^õhc/²pT™K”’íFÌôxØ!‘ôa}óé¼\|ÓX7ü‹ùƒ’[€TH¦Ï1´æKïª$áŠ6: «Èoöå›—_ÛRz$sßt¡˜S&ÓÏLÙ¸+X8eÚE^oÁÏ#š,¨~—{`*Ó!¹èVïpM$J:¶ò©qës`P„?ÙzVS[5âF¸Y÷Ýi–EÊ ¨ˆ¨ˆÛtŸx|7Ì[ÔÎæ©g—/­Øüu¾ŠqÓ^…܈ï_öÌh]²5¸œOì»a”t~"F¡ù)`¸boAY«• Jj³ôyÜEº¨ªÖø'òö§+¡%;ÌoN)(†¿OíÖû`»_v]„ éåíR"S! 7° CV-0ýr°~ÄòFÖNŸ•ÉŠ„m\ršz׈jâ[à’mº•âCñ¾øÏQ÷„6e?6_3FóB«âR"´Þòì¹@ÈÔY cx|û$NÅ$9Ê;Ù†¹ªìS>”ôY²õ2…7‡/ÎßniÏ5ÐÅFN”9QkÀ>— ç¿8à8[(¸9íÅ,ªJÛó©P‰¹ß8¦Ê2ÏúM&E~e48Ù†êj®‘ †° 8¢¼Ïhë À.Ë ªù Œð¡î_]Ú0ŽJ©ÚÒi«asV÷í8èÿ]…¡˜!KÑN>=y$ž•†™×Þ/›ËÅ•%?4-¯i9%|ÎäY—ÖÇP…b¾Þ̵¡Z"ë*‡ÊYVhÓïñSuzó4fÈ+iK–ÿœæ%䆈þ¤Q>ƒ­ ‚"ݾ9C…÷/ŸÝÔ<"&eV€²ëŒé„ùÅc-îCŸÀÊôBMMþÔçÔê›^Š”R¾ƒ•ŒÚk`µùÌž„W¦QóP³`Á®´)ˆªE ß;dGÂ9ÐÍ„ =0[âË'½]º ÖÁã*abOÏŽ]ž«9ZŒSâBKÈ”/&Sòo _·Í}Y7S2OÆJ†vI$ËSP«(Íåg ç‰´4Õ_}_î›[´£ àæÉ­'†ˆ¥º."¥ÞaF&bˆ ›"yÃê'¯ýãwdZÜò‘êõ×HáÈ–¡+W)E-ÙÓù‚Uq^ ÚÏÆj{¯„«p²a3Œ+è1Ò…ýM#Blì5Aä©®c¡œ@šKIW§í´½­WX}lÀܪÚ(¥mò^ý·êˆ÷^òoç”úFO½“  ÄkÒ.ø'Œ à—,O?ƒe7Ÿgî:<¾lãùB„ÙˆU€ }» ú½jÐö¨Ñ ©FÒ•ÝP2ú¡q™¹äÙ…1jþm+z|çn‹íks•]¸á³˜€¯í/ó nK2‚§²AP}¡ ùG£%ƒÙVIÙ;^öoPEîC'í{ÒNŽÂe¬æÂ_6µQ­\+úÖ÷ú¯;g.NgÑ´PŽÄnïxb£WÌ¡UŠÁ׉Â.¨'ôqtÔ;mÆE#m–;Sܺó¥®ï0ª8ܲ ¸Á¨j²åÆZd{î#‰MŠAº;`‘øŽCA…žÒT)ïÖ(ìr¥Ò=¦¾>–„=dñ^b;èêS}qîíÚÑ´¯•:<“SEƒYÌÝ×6þËÀü!P#×!0<ˆÊS"Ì…µðÆŒ+øçŒ9ž3ÏFÆ—ùh%Ⱥ5“(F³]ãâ9…}îx½§Æ„øù^¿¬®åŒƒ±Ñ|­GkF„ž #ö}ý=]h6AB§ïÛ…9Ǥ1ÙÑ y#ÕØê”{ÝD&¢E ´p9ÐËÍP >ƒ_È ŒÊÈûŒR Î×»Gœ+ÛÜÆÚè½|¥IÀ\xUÝ.S01¡]íèÚα'^.U‡íðš¹±8¶˜0Þ‹‰smÈ›IçëG×zò\o©¨œ{¢é¶¸{gÔbÑï‹c+“ʘ(È\¼Î0èv”Ú×g¥©ŸÝø!Ü'$Ls œRÿ(ºI—²‹Ëk+«æ$9ò Uácdqy•úýè¼_ðü™[Zëw‚yayÖ øÎûÔë3-úr‰–øii Ê0Ãñ6qÏt? ̪*'RÏŠ6a ̧CÈ ëUDŠÙeáCÚo¿Â»[ÛaÐVÐøoSò÷É8ÜêUñÔ´Q¿’®âTË¥¾³M–žf‚LQÞÞ÷?úK`›iHÊ-ÐÑ`9cVJ¾m0¶”;6ôCŒÜZF "W>>êVz‹•»!°ÞÑ22så—„¬©ù4-öä;ÂÞ FÞý¶[gb2?}RÛÚ´}gJE"†±¨ ›㼂¥&$)ùòBFÌuÈÞÍ‘NÆ«å5#IÜ?éà½ÞÌ'‚àÃó¦Ãöø«Äô¾ J¹Îs¼+¾N§Qf+³›ðz¶Ä±Þ©ŽóTX› ž­’·¸ÈÄC3 Œæ+¾Ÿg8ilöázè×¶BuPï\äö6êØd?‚³Ûw¡èäOKð¢Ð)P”Q¢[•GèÕ)(÷J_KÍOüž&êTã9Z’¸À>Px‡‡VÕê]gªã«¤n·ÜÒ\€ ìd3o•k¶Œ]eXú®Fm  9CObçîûJ®£Ð"Ž9- ú»æ^>ZØèÕ7wÉÚ1«×´äröö¦½Ín‹-ág˜éÑ®žãI©•Ð8,)„¬¾€Â! ¯G”|°v'ðÂ3¢aø 6"𳄛FšÉk®QÄ{ æ‚U}ÅëÇÕˆëžD–9øørQÈ­ÒfÙ(µx\8ò—õâ¬'wêêK ôˆ1LÇyž-3kÒâÖš5ÌpKhÇ!øâ¬g{DúV¡8YpIÎØ]’*åé0°_Oûk/gŸ/¾…r?TÑ#ŠyÌ+~Úv”ö ³^Ä.\ªÂ³ ðãÆ/è~7k^J|‘ÉÒ[ûŽEXõéËôt'àåÙj̥˚yæG¦ðÓ[fuÏLõ[,‘(ìuCÈT²ÆF\\\ÚK¦rpƒîÚŸz¯Ï'ˆ/+«‚¦´wä[u°g ík"ªìÜ¡A½ßA£+rHú²¾[ªu¬ï˜”kÂ@­RÕӢܡ*©1#¢wC 0ˆªúµ½ŠùŠC)°Ry…ͤEñÃ}áè­ ^zc6×Èã¯Y²lx4²ô¸‹ëšÅªûJ‘ÕÂ’”AXkOØß§gÇÅ/X–¦¥”8{±kÏ´÷4Gèë%FÐÄåãõ3†E¾îä’¡è_±ó)·þÚñûni°M¸{4~Zë_8Dº2ämVâà>LbõduLdÃí”8¡îmç5æË¡ªïd¸{†øµQ С¬æ \¬ ¢[q¯h_ôª©ÈQÁ`öc» Oˆø`1õPدû@¾zM´™—Üem|!¤ò—*m‹f/¢n z>ñá󤔩ɑŸä#¼8oLáp:„Bê¬DfÏï=3û‡GËA±%OPÑf)Ve»}¸ñ€=ºq$K],Q DئÁ\«\Ÿ··àQƒ3?»$žè@¥3o+­,sØð­v¤6/cÉ,¤Ô'ƒyÓæa[ˤ@°À ^up7¤Ÿt$«¶;ó&+{Ž¿š¾hXÂTF«]´áùg‘4(W˜Ç 8 Ï?Ý$Í(J9ñ*á/§´¬£=쇎–e›¾Rêþ¨`¯(—ºæiJ$õ´w«åªqM¼3¼®§9kÔ¤:r´P†ñ©ãJN‹˜ù½ÆØ#”7ÊA¢”á ”¯þíà“è1«8œ”–¼à4÷ŸøŒÛæÝ~‡á&‹ËËÖß‘„TãAÿì—ÅÕ žTey.~¼ŽÞR½Éd3EI9:Ï+3ÊšÃiÈö•Kˬ~ŒiÓÎäw/û¶FßÉ,rB;OcVÑPÁ«XÜbÉ}/4"Ùf×5Þn/Žàh;£ð–_Kÿ¶S÷wÎáÐ×òS%„gý¬’/<ÌûxBZé#¥ûpÏ•úÛ]A¨ bÖ´ßÞ1½mYórN3M/ü( Oj+Ÿ³°9à@´„AÂ=ÂJ+žµ¨Er1ŸðoV’ޏ÷­z¾~±®o£„‰š²Ž[Æ$ÀøLÍÉ8¨0—u!˜°?Þgþ뫆T‰Ib«Uo¿S…Ѭk&¿ýêrKÔŸT!ø®cH¾â¶?H+Y©gÆ—Å“6FOÑã¤ø!NPNÞvS×c¯ú3ãØk²ø~½‘Ø2ìÆºØeîŸ(LMÉ5§Œ'Jt:W"Ž©çæœ·Ühœâ£QiT?Î 6>ß&ÓAô£(P]u¹CKAÉ»w³j¿?«-y¶ëuAý¼ÛÙŠC 꼈m×”HëˆVà”VUæȄ鵠b{Ê’Ø \l*—ƒÔB“c¸=}”-ËoÞîZº:)Îf¡u®éPbÄÌ2îÚŸŸð·MÅgø ÀˆFȆ#q¿B:þ€!~²¬2B4FbéüÁvñ¼ÔÎ6+Â×㎨36óåFç°p·î¼\ø̰ãÚ½XM›Á ÂN½Òb;+†þû×ýWˆÈNAþ·gP™.bUð]Ž)Lü¸Y¥w vË ‘r™”3r“"ßú®‘âÝàoýšžH¸„É¡›«z{7Tëü8:…Dô{& Q´‹ªH\% `IÙ´ªx#/·vOÆ)¾˜Ãež¾êË)NÌ[5úsŽ!Wä×îdj:Lš£Z°ß(Öp©-¸0 _[ò2P`‹u2“”’ÎZ}¯ÒÕ²ÕBhʈý¤êkÛà…=‰Kfló¢ÆÇ9ÒÈ`R4_œ!p"j|N„ÎF™¿|;t&à GŸ¬Z|ûüÒ¹¬ÏBìÑ,¥{4l§ÌOck6“®ä÷ô‰ÛÒÒÍØÅIQ²ÔÞ¡WÙÝyÏÖÃs,É[Uÿ W\·HŸ•XŒDöH~S¶•»8ì´±ל‹*ücÆ¡çÛ˜®ãK7‚Éoøa}¦÷•PqPä±ëò OµâÃ=ñ×4á­&Ü µëó«a¬ïüíNº‘Dˆ\`Ûݰ‘Hˆ»oòA…g¨‡Ñ’#]ÑO¬î.>cO®w¾oÇt#\3íä³éSq…Å™`¼KTwUdz"ß$u£ çâR aìâÒ´tÚ+aKÓµ3ÐýT¬Ûî®æÃ«ÁçE 5ÂàštRgíì‘¬Î»Ž—n!ζ^Æ€ÅáM«§uBKV¼å(èfŽhÆöêœ<ËøJ¬ÚËð¨XŒš­Ã4u*ˆßJ$F'“+˜ Ü}‡¢,\<E$ëiZ7Ãôqê¯ù|ï“­Ä–2‚“ó0ɺz/Ê=ˆëUwV¬":ˆÒ„Qwy§DÙÐIqÑYˆþªdS¹ÄÂË1«Ä ìÃ\]¯4d ñšÓ€.Q “î»g·¾^Ž ©È8ÜT-(H±‘0Ä·A|AñØö'¾^œ!õÏÙÙ»‚ÔJ=.u·ÉŠäpbêµP¶qI¬+ê:ƒLLÛÏ~§K›\0»&žÆÄ[•ïëÁñ„%‡0ÿ÷¸+!¥îa¨¦žÌyy/*ðÚþjÒ÷Ú ïß´ô2÷îS4jM·9=VW~>èŽ\•Fá÷<7 {•Pd«ÖÏ/m%ì'Í”Ì Ïî°XÏ5€Hödî j¯È2^xC*lôC(CHŒåíúUfã©t›` nd³Ôl÷¢¡ÑòÉ*nÎSÛ³£§ÎïgÕöv‰i–´Œ˜áVnÇ”í>Ó1TÅSžy„Æ1#E]xÔ(ðüér}W$¦…ÑìA~œ•µ%N¿pWããÞ)…Ayê¼ÖÕ¶+xÕŠjã„¥õ&N§E>Ž-*äˆ‰Õ ½ù;m йøÆ–YE;½ÈG¨'ÎÐɦºJ£Ë:HH•M°ÔÝw´¦ùvhð®·Õ&‘·‡³M2‡,g(v²ñ¡Íùk¢Ó $‡ÄF¼ô´AÀ½W18ãO;ŠÛÞ$+­ …ÕFì1¢ÄÿO+•zR$ÇqYyNº|Ά¾/Q—q ËÝÜß^Ut`ø¸öP–H!,²Sšœ°¼×“Iøµ1S™ƒLÈ™6€…›Cádí£ÃXm"cƒ¹ÚÊ&zê¤\^—åf¢*Ä·âØª/EN]OK–+ó¬²U‰fzÜ­t8ÓÝ”ÃO¶£ðmÈWØÝrÔ¹ H -$ï ßëv±×©“ö ¬×¦(æ7»Ô̸£~‰% ¹ÎgþÆÒ» ^ŒX&u“þ,€à…_.Z^`öÜ%rþsÿá ]LGŸ‘4gWÄmwê]Sž˜™j$Á¥q;¯ þ׵Ǹ'E¬(ešO^ëg`X˜"Þ®N‡HJXla~е~“VM=ãØ DÏ£a¢z³½üiXâoófIŶd©_ýÖaÛ“˜’¼ƒ¡ãÀ䥎~›Kg¥ŸGX®Œš¡×úy /Ý2ãÓ,»RÔí+b%€¾íï™é™>z#É”G°tñº XÑÐ=`B_×X[vOÓ «Ž‹·;æñk¼ù8­d€PË#=µuå©;W&OÚ4º'tyÐqh—®Ž=c/HÎVwêL4nŽ*6•vÞVÍr.£>H‡!è¹7¹^!Ý(¼Ó͵ÁògížDaÉÔk^ š^ë sø¯ô¬—FÖ vìã-I±”ë²×iøR³¶‘]Ç6¯ÌÎDƒN¾WÎ\:¡6k9~Íf Qæ—%ùê²âÞ¶÷ñ¹§¿¶Á!€Ä¯¨uDìAå}&­ZÜà R ê.³”!£ßòßé)Ò~¢9;_4uåmžƒµ®¿Û†È/¶-ÚÑXüU=`ebŠvH#=«T¶4ÝÂX÷ŸA‹Cí!~ú€üe}ü$9`7]3kv JA‹åÐè‘ó’ÕƒGŒ”8#¬üÒJ3C#×,¬ýÀdŠŒq߈ð`Ç”}‘¬âÚ‡°lZ˜‚qF‘GQÈçë÷¸läˆ\¯«š"Ø8¢Ž+Mû´:uj©‰D w.+¢LˆÓ:,H¼`»®×š„hºÞμKÑ˵nî£ ¢áÑŸäõÁg£È#WéÃ?e%ŒS¸jïU°Ì¹´Tï:b¤MÀˆÃãÙ^_Üpª#E×ô’‹SñÈ×#Bß+ÙÔÄ•#‰Ï/•A¢)ËÑg•u¼^Ô“r]):ßâ^ø&7Pí½ðšäA_5\{úË8Åì÷àÒD¾ì U4}sv%ÙqXa¦Æ¨„}S—Ç•°S²rÓ}&^s©œtvÒüôM:39&€¹rfwE¦Î'–¯âSÓ­lˆ ±tÆ'ùÜx‡æ@ *WGðÙÞ{zób(,òãO !¤„Y’#V…ÊïÍ¿y@fÏóØï+Íw©€3^ u !ŸÍê°ù³)¾8ðiôø,Šö3fÆÝMãP½iH>_Œ tå6à§&U’k´Œ_‡,"`É“f$à ¹Û×ÄA´¦c¬íãûb°^u?£ÀüÔÄJ C¸àˆžløÕP¾0úŽ› ¬0Atᬠ¨"hñ3}ºW\Üée¦3ÞCÑoÊh%{=þ"ÿ˜±9»øÅfŽTb>¤)@¹cÏæzt*×=kq]¨ÝÇ?B+73|+hú„¡'ÝÓy *íû¼nk={mÿPd½Ü²n?%—â<,¯¾ÑþÀôÙxÙA‰ÿè[c™HàƒžW'¿¨Ï‹‚ Þnˆ:’XÙ[­H=žñ‹6,Z²(H•±™Ý„¾•¢+ÃÔ~øýé+Z»¡*ÞøZÄ/™_zsd9ŃZÍ#¹è.:³ŒlD BBt¿Ã1S#«§M±?˜sq`U¢}/z+ª§˜$Æâíx¾"½EÑX'(©ßxKè³ë¥—Fq:9C×rÿLŒYËùíò–Å”íº#n]Se-^»¶z¥O’c †sžáíåí7Ñ»(¤GgFè¢1éæYà*Ëi¦›xD‘Y$§y“Fh2XíÕÏð!g*wü)Muae¡¬ ¡Àž\€ÀäcyUn’‹– BÌåшËWÌû}D±¨8Ä€jÛɽS>ò,X’ªXæ]ägW=HqÍúÎ탘ê€Ah[ ?¶oۜ˵qŸ ÷ѽK/åäí;GuÜI^!?ñÏí×ð‚‹ÓF󑯨í¨/geM õͯ|C¼ÞŠÈ!J˜üŽý  !Ñ“~ '§_½~Bƒ9K€ ’’Úë øT/Ù„4JPîÃi#è6ˆâXXß6¤¸¶µšFÝ„N‡w¶]IŽ“ˆ@¢±¦Ççf€ÛäÌoU^"=çY`Vñ7SUsþ!‡,3kÇ"˜M¢Ö²¿ÝMØ,0´Ô%>‰*†Ü¬™/8¥à¤&/áDèÆðñû~Cj[´!`Ôf™àÝë7ÿ~DÊr±b¹‚…\¡û,—”òÎ ó®ÿí=‘|¥) @ %•¸ÇRé| æ›fmñ,8Ž)}Ͼ·µï+;f~ V(ÃÆ¼gJñòF‚„¢7+í fÈ¥8*2¹‰îÄeê92–¯±lUtHcLãCö!sØÑŒ&ei^(£>¿Æž~L4Q/Øô©6Ü÷\°`­¥W²F"(_Û½åI‹xgï§÷›ûQãpÞœ¬s+~ÉÅPå ÁêÊÚ;EèNöúÑ÷¯’¶øré—-Z UÓ…0&š$6ú/<'ìÙe⇠?@(~-Û‚{”øÒÌô˜%Á(ùÒ²"Îqß¿[]µyžù´¯ˆþ¶ï†;T,óö—¦O·oÂÅžÕ †çhÍ|ƒË®ã'ÔëÞqѵýNqQiÊkáíšcmY¸À•×r<Ÿ¥ö,ÑåÀpëkX‘"ºËíô%«qX¡|MC»Vàšl#¦ÈÂñfÒ„WjÆÕñ«i Ș¾áx%Swu›fBAëŒzhWkQ7‚¿ –Ùzm‹ܯe~ñ˜!Ð1ÏÃq3Xrô{YÌ(•Öî #•;øPøµs„m'ì›÷i¼lÕkú4[S‰d*èöš«Ãt hqM…÷öÛ™9d]_èïHO¬éMö“äw³ƒèä§ø[ÖwÈ1˜»„ _(` Ë/¯Û§ð€#äîDp…Ø&èÖ«óÚ‰úÙбV,#s¬ ¹÷Ã!dæ_á€ý¨ïÚkÒFy¿´Ø¸*´ÕR;¡ÉÌ ~ì:´*âgxFAlË=ºAìÎ?ñ§óC|,ûÚ~¢23ä-ÐIÑvö2w¨Üv“~)x½ !b²°îCäYyg£‹Ü€à˜’E3¸‘¸ƒ9…¼RÔnV 8ÐÑûŒ2°’º#™úYAKYŃ{2¹è“žg¬#çŠgB4¶L„úÎÉŷ䆙jrñ›÷hp~¹5nB±:Û³¹ü»ïË'ößçzŇóù#J˜^g‚qS°uø"çäÆÂorŠò1³S—/ ¸òÄD;©Ë‰;ná‰àF$7,YZ“"âí…#ô]¿Px¶÷‘'Ê¥ì£ç»jÏÖæ 'XÔ¾Þñ&c+‚¦ACã[¸æ[‰Äfñ2©ͽ>s´KQ÷ë°ÛLQWí¯µy€£©<Ô ©Pd$õfè…Ô1’h6ê/à, ö Æcv׆ƒQ‘•jB†JJ•vúÊetÝï›}c“Ü[àúŒ»<þ…t¨Ë ´ÝÓ’¥ææ9>êPß&ö@À :žñ[oô¶~:%•Ï#Înc•)ƒ>•s_5æøÃ÷¶a4çÇ¤ÈØDà>nqÚúÍ\§7ºtͤϩ{šªK³ÂC‚FCï'öý䤣ˆkµU=½ê ¶´Ô'‹¹[E–µf¥&¢TSò¹íæDî2¤[1Œ‚±/ì*›H#‰áq8 I.´žß1Ñ™(²¡`lúœE½©Íü®õ; ß¡uê ³OddÓBŸ¡ØO’4†c®øI§è»­àd8Ïô(E„G &ü7ͰÊ,hÇíÎ×#-oî!¨ßÀšìª«+q[ƇÒ$†L0¿Ö­ÃÀâ_mnyÔÇãe© ·Œiä¥è¤¾Ë5Éy•¼}^©T´Ñ™Aºq"´+ÉKoàÑ×¼\¯¶ª—q¸ E…ð„×™Ö;Y1ÏnÐnÞbûd3X®¡ò•‚:Õ`[*ØÄÎ Z¾+Þ‰!Ýw0ŸôU„û¦´´ßIcÛÍÑïˆüþhzSÛè—Ž¸e,˜Ù?]˜(įâsÝûQE1*¢ì#S¤ì ·½Yc'ÉUÁíÅp5~ÒÓ3è¶4¦†\Ò„œçVÂ\ºþx¨!ˆÉ†4ö;Q–w û/š°'$X1¦HS冸•‹è;mÃ?ê©“‹“ù»wü¢›EXÎòU<¦í;üII *Tá©RÚ”mø¼I{÷CÁò‹<$.Ø:¹àuô.æåE „ø¸åP+?Ïô+¹ªùä]!xE·ÂQplŸ3R’¡º½0Y ©Ô¥+GÂÁ¯{ný겂mÃÆÉV/Dí 3 uyS*Úå§™¾£§"}Ê ðq­—wýÒÎõÃ7…OP¤ô3ÆËgÆþ@ãY×z¼¹¾þeM–¤çŽlÁ£ØØCPåø€»Ýãê‹KQ° Ÿ-]8#h6êÚÁ5<$~–dˆszÒÂJ%Dm¡ “ÊóuB1t>‡üP.KqøíO)N."Í«57 j!%6CbËIÞƒe%N+ðc`wûN}.»ìôZžWLå?Q”>Õ:äÐÍâ?uÎU7!…ø©ë)×&Çïuj°-Ê੽Ö&iÖ=f{¾¾î,K;„ð)l¦÷…S÷½œaˆ¯îö˜?_×.·½PÓÞ'˜ï°÷ÃinÌJtG|öT aβaþÖÀØž#ÏõM¢˜RK3ÈBHD<Ø9ó„“nèÆ =Ö4#Ëß™ª¡û<ê#yþ{Χ÷,Ëâò{'Ç8HžE·a%zU¾‹³Ùâ|?Ê›zc„XŠÏùÍd ?“-*ßLüªäÐOÂŽCjl6R 7Qó  -‚f·ŸÉ]B³:÷+0.ò‘/4Á4èi ÝIÞ— n!gõâÄ'5ÇV¥T(Fi[µ§/~÷Š=¶D¦h²u+×D®>LŒ¹:WÅ;®Gp¶KZJlùL»2ñ¥Z„ÝÒš ÞgóxëÀt¤”3ñ×ÐñÒ³'+¤Ì…-UË»b‡C9–Þ`£Š0Pb“yµì¢ÈPÙ¢9 —à&_lGÛ•I–Þ™€gfà·w™Ð瞬(7n;q÷V‹¿}³P"­xçB"kÖ>ë¨ãbîk½"]C)Ô"b"¨£ŽOÊq.*‰ö@ö<¤üÞkµIù¦Jb&Èûdþ’×xÚA$äk_lðQfk`ñ÷!<½q‘üz–»†¯{›QºÝ“‹Ð‘ž[xhr+úš¢Ð‚šË×’Y£€‰Õ;l²!„úÃÏ‘"¿ôs~*<$’±c§ú`›ÊëY(7èËé FG @`עǫ²;{ÐE¿‹ïs°ßH"t[ÿü‚Yn´€ÊGÿUSiË„7lùy­žå•0‹ª˜òŠÆÌÃû;Ç ”• e×¹õXm‰ôñqæ®Qºà!oò{DÏÜ ÊÜ6øWýUºª…ñ]Mzz¯…wµ{¬È“åÓQQYä5”ñ$c#µ"HlüI%Õêš¶¡h×ÇZçÆ¾"Õ)õHMêÖgàó£^‚åS-»²«D yùOŽ¡np‹‚Œµ¡YA{O÷oÁ¹»íÒG+?âLA'ñ=‰£·¥&‡x•`ë‹8üC•ƒèãÂÍØao~'}UF´­VR}Ù±;Ò‚‰ØºlL1Döµ¿© ùr¥_d4m}þÒé×ÙòM𠎀& Víª;G¥gœÙLgngü¬´貎ŒÉàHåˆàý‘n­Ðœ„ÜŽâT>±¹C cãêÐÀ7̈Ò.¤…/£Ä’ӭܽ „Å»ù0ׇ“AHÑ%¿Gêý?í×KE±‡6çûì˜-€ê°“_èºà†ïÝN}F²àbFkIÉ„ÏEwy=Þ™Ä+ô„.–͇DÀ­hñl¹QëR…Ëõ1µ¾¢\h¨)p±Tuyêô˜pž‰“Ô±W¤©õ6RW{Œ[§±t&þÐWWæ(½´ÙŸiú8’fiÛíÍÅý™í÷ |¶µ®Œ@È;3Bþ!ßúW âœðì(ñˆ§â³]øÓG>1:¶ úM[cqrЦN‘9]ˆŽÅöäû±ØÛå¼UQ&È:uÁwÐ ÞТÌÐdñJynU½¦’î8„U¼ÀïI˃ïÈTr¢5ϯûÄ(…'L£6`lFãÿºˆ p دn¿µ Ã^4#¯wORï©ßñeË`}™‹øílÂs7wT]’·¿;®H!R0ƒÛÞj å&[»J¶`M åÈ‘cy¿«Cˆñóiê]»\õ ¤TFŽåmÕ^nNeØFåsTC†>‡‚Ë/ÿ¢.U˜©•ô|=á›6Éê²Í^=Œ]BF1Ð(t£ ¸3AV‘ßi'«’(%[ÏDáœÍ%{´Ûrk1ýNôiËí÷“•‰wjäD†«Y¶iI‡-‹7q›º2ë_­¼ïp#9eÑÕ£¶øÊƒ mäŠ~NöOÕ­— «—FÐÊþ8\ŸFa¸–BéÛ®#M°é ~nƒ¤W¹)¿µöƒdê«1¨¢Æ2¸ÚÊÍÝ“ó-ì‹¢ Z¶·óNS³ n#•é0Ú¼ ºëc¶y¹ê@{:IO»¶¬ÄD3µ'¦û#°ÍÐÚ~­&°!­Üï?쉵›Bp¹!Í ³QO–O\¢ýBÛDãÛÕ"µ‚XõØ8¢ÝtÌéÇÂñ†09Ç=ÛÉÇžø”7›5ñm¶Æ=rè³:@F/ríB\o&n8/ÅÊMÊ„!—ADûÕ;GsÏŽk\™Ü¯Ûbp2ŒëEà| òrKëš29€—Àõþ¬qSËw:NjaÕ08Æws´jyÇÖ_Z—Š…ÿéþ­qÅ«É`Á??çNw a1¨è¢)EƒîĹ)> stream xÚŒ·P\‹¶-ŠÜÝwhÜÝÝ î»kà.Á]‚»k.ÁÝ  ÁÝÂë}ö¹'ûÜÿ«Þ+ª Ç”1}­†š\UƒYÌÂÉ $íäèÎÌÆäH(©³±€@ ‘šZÓÆÝôo1"µ6ÈÕÍÆÉ‘ÿ® Sw°LÒÔl§ää÷°°qظùÙxø@;È÷?†N®üISO € @ÞÉä†H-áäìãjceíó?tæô6>>¦¹Ä@®6榎%Swk8¢¹©=@ÃÉÜäîó_t‚ÖîîÎü¬¬^^^,¦n,N®VÂôL/wk€:È äê ²üU0@ÙÔôwe,ˆÔMk·¿åN–î^¦® X`ocrt{x8Z€\àà 9E€Š3ÈñocÅ¿ ˜ÿî €…í?tÿöþ‹ÈÆñ_ΦææNΦŽ>6ŽVK{@EZ‘ÅÝÛ `êhñ—¡©½›ØßÔÓÔÆÞÔ lð¯ÌMÒbjSpÿ.ÏÍÜÕÆÙÝÅÍÆþ¯Yÿ¢wYÊÑBÂÉÁäèî†øW~’6® spÛ}Xÿž¬£“—£ß¿¥£…å_EXx8³j9Ú¸x€ä$ÿm!þ‘YÜ\@ ‡r€¼Í­Yÿ¢×ôqýKÉö—\A€Ÿ³“3À\(ÀÆþƒèçfê ¸»z€üþ©øo„ÈÆ°°1w˜¬lÿ°ƒÅ Ë¿1xø®6Þ} x÷ØÀ¿~þóɼ^NŽö>Ìÿ5_V=yE E]Æ¿+þN\ÜÉàÇÌÁ `fçbðñòx¸€€€ÿfQ5µùwÀ?®rŽ–N¾¿“wéöü÷üéþ}ô€ÿæRv/-@÷gÇ €\@sð/¶ÿçMÿ—Ëÿß‚ÿÅòÛñÿ´‡½ý¿ÔtÿÒÿÔ¦6ö>ÿ6﬇;xÿ•œÀWàø¿M߃þ¾Y%…‡ÃÿÖʹ›‚ï@ÌÑÊþ?m´q“¶ñY¨Ú¸›[ÿ½,˵þ:2{Gª“›Í_O3ø¿tàË2·?9ÜÀù/|8ÿRÊÑÜÉ⯠cç☺ºšú Á‹ÄÎÅðcŸ¢Èû_; `eqtr»Àå,\ÿš(7€Uì/Ñ߈À*þñX%þ ^«äÄ`•úâX¥ÿ 6«ÌÄ`•ýƒ8¬r8žâާôã)ÿAàx*ÿA¼àxª8‚úŽ ñqX5ÿ pµZ8ºöŽþþG×ùâÇÓûƒÀ–¦ØÒìçiþÄÖ™;Ùƒ‡û?Nο$üÿš:«Å? ¸{ ? àÿ^¹ÿ°ƒ ï©›õŸiüåã⾞?4à¦Xþ`ËÀ¿”6‚pü=ÿDeûKð‡Œë/s'×°ƒ ¬þ@p™V®¦ÿ$‚ëü“'¸ïÖ>ÎÖ ÇX€e6ÿ€àBmÿÁ=¶ûGøgqà.;ü£8pÿ0s]ÁÇó=¸z§?É€þK .ÏùLæ ~%:Úƒ,ÿt“íßR×ÿ'8kgðSÌéÏ9Á­q¶÷pû?XâòÈïâá~Äü÷XÙÀûG‡ÙÀíùÃÁvr9Øü÷2qýeòüGW¹À$nà÷Æ’÷ÂÍþŸ«ÂÆNùOXð™ÕÝÚô×ïîåô0‡Ç? xžÿ€à̼þ±X`oï@0½Ï? ¸Ó¾’3ù‚\ÿõ_O5sWp«ÝÿõÞ¯úÿà}‰¼A戫KNæ¡¶¡ÝõbD^ÌSBóÔï3è™ýV]{<žPáSéërB¶]ïÄRÇúÑ7ö¤ènE×È^ý~v4ÃGt¦¨u=û¿'©Ït!®ÌàO—ük"A fÖ=ôuñ×¶ƒî€ì•§.pñàEU-Âzð”ñnª\Ÿ_:P;¬ãV@z©œcŽÓŠ5.[ .4Ë]ħ€sg&yÇ€yá¶p{7™?ýF&ŸÄˆð+Žã³ŸÞwöøÇEßÍjMv·¯Tzø$з˜³4~âGiòxË~執]'Òq{&w>±ÙÑù(«?¸_ÑPOóÓà³BcËÅÄnwÊ&;”‘'Ãqæ^lÈo{Ë]ñt˜¹1©$Û¼©Øó4q©#ñô=å7ùÁÓá4ê0D¨[ã¤6‘9pE@æ7Ñ FX¼ÄámŒ˜oŽob·´ó¡šH‘tôíZå4zoj’mxÊ-\ÊûÎEzï1Øc_ܘg; ÷NºY8A¦R·´„Õw¦æK"1Åà6å’xÜñuÁÆQ¦ædtp´¨"6üD¢Ï®;êòB|ˆ:ÙîԪ|««)àÍÁ(A…OˆlƒŠØ™ôÀ•™Ùá—ÜŒؑŒÿM^tý¾¦ÿzòËõ¹a13P¥ÒJC YÙþ–^žJ¢âù|a<‘_óöoþ2…NXÿ3iÄÐ7¿(ÀZDPå’Ó6AÞ³K7žp-Ð(ÝûgZ£ÚÐoZãÓÀã°¨nä1½1Õ[÷v˜½"(\á·†• ç¤lÁÚõ #ü¥_·*M¯-€ÖƒË~‚p‹ì^§ùiOá8aV\àCÒFÏ!?ñÉ„XÅ~˜>½^ äИÅG ³è­‚’€XÂS$uaˆ¹í¥& Ûô¢e+p ¾6R–ô,nÍCÏa‘lÖpìöÖ;?+IÆõÏ~fÉÕˆIQº!£_k‹=ó|U·¢d“£T1>pÛ,镾·ò¨Ø;Å5ûn»Îèþð–’\xñŒ’ï ZEïMû´—@ÃÎígâl¹d…w?ý‚gójuI¢T5mÐ¥ _}zIÚ ¢U>‡ç=—­:3'r¶)W@îËD;NçÙèQË ÁÍæ„Ô\ Oÿ]ÂHå 6H‹Åǽ³"ÇWdÊ{@+™5KA¦,¾oÏzd<™¶Ø4?NÞCI¶*3õi=+mœ5Úo«4K¸åÃÍâb9¶IeüûEÖ»™¿¯øpcú\7@ýÇ´ÕÈ߇º™c÷c{­'_òJCÚW‘gK²íÿÄÅ»Yº"©™¾á^QØ.d G»ì¾G Óµè¡b•;á­=ù¼Ø&±|ú¼©ŒªýA¸®jì,­¨¡WXŸó8|®[çOíêùZ÷íWX4#ÀîÎr¬ÄÚ4æïÙ¼X©³îrobÞ ÅT;äVdêÐø²AÄUê}Ú§Z߃~‰Û—Æ)­Vϲ[a©­³`‡iò¤à?µzM§Ò‹t@–x·]¦m†Íc´k—Wq+/PmŽ‚¨üõÃ5Êjœ ñ×Ò’ï«þÙÉ ¤‘Z%o擵ÛEG¨cåö ;)ÜsÖYܰúì«Û-3ù‰¤dzß=µn²ví»Uý©éµGÚQ.:—«rI01…hºMTãÞÈǸe„“O4&gÂúÄ®úû©‡Åq6ç§‹§'ðØÊÝÂãEf°§¾6™bG½”Q#¿eˆòp"‰¾AàœpÒ%w³Až&ÉLòæ¬i«çö½S='uÂEb&0d–80$IøÓCŒZZ çóh:8/W\w½ã^v¸@Ф FÖhÙv¢—ÆñdöFFpk­Ì.|¢³Û ·-ц®ß¥ðmþÑ^JÑ®)æØ|Ûª8tûy‚v¼]ðu©•<#²¬)Åmœéêk²ø]\_jæƒà–´Zp–™¤‰ý'6>ƆBcUG›’8G¡âTÖ@žÑ'§©ÅJ$>¢ ô_¼w †Öì™¶«ßywìêV¯+ªäÝæ1õÞ„Z„M—äÆK†ÃŠ$è·@7’Åg¸ö ûq'„IÂöWä­ë[¯Ü»K1Ô„Cºš·´ê7±#„¶sùNKl$J•ŽŠ¿!.RøU~·°N˜Ü‹~ü1Ÿ?€3ÆÙß\%ˆ*Ž31JU¥kºX/‹ƒ –hÄ•SûDp-¸%—þìé/xÊ ¿ ³º/êç¢+¼3–à,‡WC]OGªsã™:~ÈÀÖÌi_%V§°VIÆýã]ZšaJ:cÖÓ÷û¤cnœkÚ4‚Ÿ3&v šÈ­tµ†yhÜ\ê+Ìú}tR5¿ÄäÉ9ÜøaA bE'ÅȰz¿+G¥Üš•gcšÍg*/YXÖ…‘#ú#ç¯r„Õz#h:ˆÒF¼k~Ntø:f öF†ÛI”×[º¼g^M}ýÈíåÏáÌÈrgek¯WàJjíN”0%ÂÁÏþÙ}õrÕ‡†H:“ÜKðÎ…ìõ´¾KšEiÕ¿bG K èød–\+â9ˆ¥«<Å(Ÿ>¼W‡5ÄMS@õ+û9QÉó„Òí~ºÚ‘ðãm=‹æ~*ÄmþMFïÁB¾oÃP®ŒS$ß׉ #¼šÇ uô,ï=r£!´/^R¦Ë– sgcm6o9qœœD¬fµÊo¿h 3ï Öû9z0.¯Ž‚«T¬§åÅF2³šº…Ê0ù<óç}ˆàiåÜÛçkù-”)ÏÓCŠ?)Κª{ ‡½X÷¨#A~ÊŒÌja¸,€ îÝç;,ÀÓ¨’´À²[ L6£ªÒ¾ ¯4rOã °æ%mÉ*GºÊÖÈ}fRiƒç¦ýþ™`gþ¨‰,<1ô-\YåÒÛa\E3ïös]¹|K›Þm„žrrÃ:ßå Ñe–Ö ŠGd®Ó(ˆiæ„IÅf.c×Uك㫲:VR×e!èGV“uªÔ)1Þ€j‹“Þ´¯Þ b¯æ?‡2Æ;§ ‹^t-6éBøóœâ,L"‹ŠÄ”žTÍBcÙK’"ŽëÜa’ )[>G Û[ь̓ÊÓkÐŽÒ̸,°fT¤¸Q´4­Ÿ6í={ùºˆŒé!&¨œ%²³†’ 3Nе+Å#,v¯©>kÇ$«8ޏ›K˜t.ì³ãƒjy¹ªuÅè†h“#Ùä³è‘ ë°>Í ;ŠH9ÇÇ`EÔ=žÐÒ3æ\%ù  [XÇØb±$ld¾¥Ã=Œ ”Òvg}ÅÆ" ¯¶¹ƒTÈšjæó¹1J‰lxŹ~3‡¦{wì%ë“z†’T}î,QaËÝ®ÿ2jw\ýjФ[)ŒóPXdGù½ÖK¤Ïy`§ùm2eàuǽ%—dý+¹1 {~еÑïó‹ròSÊœè•!ãJkRO´Ä:šoÇ­#†Ì1Pý—Vm¯Âe,1ÍbðÚ1Y½ápMâÆþL›¢x}Õ4&¥ü~#dËÅ×ëß—í$Îxx@œI6Ä”N˜<&F’ž¢$…iqêå¡[9±È‚­ûí/?+]¬\žLaþ<Äx wô ADŠàGÆÂÆ ×;ÀCŽwÞŠmð7¡ÈæÀº.¾Þß¹/ä0¥Ã­® å^eg±¨4N8-7C3«$HÒ8fEþ±÷¬8ÕkµÎX¦+iïÐø÷fؼG>]î›$ÁiM½¤‘’‚Êi5GÇG]zÀF–XOÉäáid6Y¥‚©«Qò܆?!9Áõo £qŒB®åÖ!´¢t´˜ŽÐOñÂØ v¤ µXOwZp"»/3ûõɉuOp³«*²x¥ Š4Â[)Q®×±ç¦FŸÊBRóDo ýynÀv°í{HŠ¿ Ë)>/3 ¨N·!qxßÄ¥¬Ñfò–,v« ¨’¥lîrôïë“fðæ®dWëIï ÙPÅ(¶uŠ&.ÙZ »8Ó‚HúT$˜q•Å*v„øð¬¸„NßyONÐÁz7¾­åI’Ö÷­¹óâ¡(çß,ÉÅKއ~JΈê­ÊúLÖKœˆ?µDaÙ*Ý;ô5iUJ‹}ÔAÝF¡´ß•Ã8òsˆœÔr7yä¶+Z#‡æ=ŽŸ6ÑD-ܺñJ%ê÷Á²ÖôÌ÷æˆÁ(l)+\ù>I¼MD¬ÈKpÚ{ue7«eWÁ!¹è FÒ„d”"ȪD‡ñíAÌp/çÒ>Ø^|ÊI~'íI¬= ‹R¸XaA‡7 Õ-ºŽ¿Ñ ‰ÎÇŠ#‰Š\ò?Ää£ÏéBݲtåAÛi RëþàØÆ PäŠRÃ<8eÕ†ê!Æ×O RQ÷•á½È N#}ö…xª³UýVÇdûþGð'\õµZžf”_]¶öˆáÑYùä|®É¡? ãlŽÑM<yɹ¨›Ìaʵ´2_TÆ>¬—£µc,òÿîÉ•ôr¦¨°½¬ƒyªA˜2ÑP7hÕ…Am`™óRþŽ÷*ÑdwàƒUõaËC–ò˜ŽuZ™§ à‰¶Í*‡GŠd%p”T²$ô[I~–æ AH‰û¨á%ëè Ù<…úyãs»ojYò1¨N C—…Øð8·U±·¦†¨)V5ñ4–8EiõýA¯nØ÷f-²¦ïæ,BùË»8Èãu(âäÛt•ݶñNn×CY\ödÓE<ÞöûJœXrîP–N×5k`€ÛƒÏdnÖ)Ýz[Ôiðë¾ÛjFä ܽlÔá Þz·‘bŸHƒ<‰+yˆú`ší¯JQÔD0{½ðY0b½}3W<ÎÕÅŠe˜ŸåÅ;€·w·Ùê‹Þ¸>Æ× xªîÒcÉÔ½ì¨âS£5ZR'¨¸&tìáÛ[v‹ÙÁïb -å‡í´´ŠFO·5î½ÁV\¿Ç¦ùQNKù8µTŸ»ôÌXˆG5–È~hcœY!žëë snBl(q*K,‡Œß5)M^L(VÁÃvI9vìbÙÂ4Ä7Ô}g…,1¢ŽÓè¬lÅ6Sh½#ÌÄU-ëö>ÍÅ3Í“£ z.8¬ É“'50Ö6°j4BöC )Mðè诫sì<‰±3*´øI±ë !Í u›¬΂V85¯§¬"ID²×ÿƒÌ'¶ØŸ óBá‡0×\ ÂÎμ0#|øGFÎ.ŸEÑrœ-ØÜøñÅ3}]²öîO·Õ$Ì&/±©QŸ’.'“È?—1ûWܪk+¹r#XPaØÆÝWyÕ‚ó;kâNé¨YLXî®PÜ¿¦ šà_ŽFæÝ5'8²XÐ}g×Aê¹ßƒ(ö±·Tê¡~¯†ã{õ{©x0(< ÚAx›Gçf¾i/ôñUËö»ðÖ³•Lcp\M]]-.fß}d ÖÈ‚cÅ¥Aë‰N2œ5üškö~»¼Hyë³ó*ŽéÀ0Ù2¡Û>aÓ±kQJ2¹ÙþH•ÿ²þšã`á—:ŒPñ>DÒöîDîû"h\^?Ò$ ­•665÷ßD{¹úµÑzÛ•˜¶ÃYÍþºÐjœd£‡‚8z é•3<§ýƒ'É0·ë%^ÈiÙª§Üu˜q¥Ùô£Ž‹‚§™¶ç]5þaμaKBdo."sÝaXmBRR¨ há]î<…àKöK/Ó$CSaa[é±¶†°ßˆéy镯nÝa­3íWÑÉ£ð_^´c¸R zž¿• 08NšQ]iÔzžZ¿|câõ™ü–Øð½õ÷©Ð…Ûú×X2Wº\V”s/­vdÇ“^”"‡7Se„.òS„Ò*Ee_JzH§¢­öTs¯ãdæsb“6l½û—”G9דt_ÔKÒ{dÉ÷ÚZ¹pü¹˜¶ Ñý•¾À é°PÌ‘cWÉ8ÿkg‚2Uèwø¦ %}F$£¯Ûú­1ɺûg¡re¼¼Ó“¾ÿ-‰¿¨ñè£Ùþ¶¯Qµªk–Fb*‘,¨‰š®—a åë\Fíù‹’„ªãûz;r&ˆÂ‰ê3õs:P8æÓÔ)ÔÏR#!d ¥0zTV luæ•8qa©ßõúÖdñ<ÓôqؽEdzµ™PárÛ‚9áV$öîʪé=<1O¦bÁÖAü»Ä VPZÝq~Ç#”‹t̃ýäãÓw™µVåNÒsÊ×¥Y=#ì壱ùÚ™` çÍ‹8GbÉ þú·Ãrsiƒb6ý2÷àÀ{rDQy¶‹ïÉÉüíM${µtMyZ§i»¾³r‹oDÖâ--{_E\~—`šJ3ÓÍxêÚÈ0©”h"´œ@”ÞJBT¼I0ë´0înܽù…Â?E?Ò'’ÃA1Ux[U´"Ìwwû •î];w/þl»f&‹~s2–ç°h¹.â`ÄQáÎÓcÕRqÙY±$m£Ç–¬Ä°ÓyOb"LÂ,ûiíÝN”JA 4”ª>1ÄŒû=ûÊüÍ®áí4iÕUÝéˆnËSšÅ.6P<É¥ÓÜ$ ¥L>@ê³'ó~5zxÖé»–×c½SçüKaz]G³ ¯Ð8æÝåÝSÒÊP7ÿÜ#›×Ê Æa~77g5ŽØE%Ø5¸ò×§p§.Àô×÷Ùº’ú½è rflFEkŽŽ6å~Ì´üÁä“ç<.9ÞnÊ¢Y¯kYt.-a2ÁLãÁÈuœ‘„|å}¸Ù(Ýß 2w™‹l5Ï„7iGÖ]kº©èeFÇæ½ËÝÂI›ª Ý']‡?54à3Ë0 Øgàr·Ê»±ílqSMrA‡Ižòÿøö^±ëD§:ê7ò‰íýwÚ Ü¨µüqéÎHŸq“émærŽBÚlï7 K8—V å*$ô:ø¡2±òúÃ嬾Ó™x^ I1&¦è:°S(¢‘•!W™»š¼ºÄq²œx‰Û $¸þEìu=†tËÓ’Ì"“ó6~ȽéG)‘yU({VäÇÍRŒwò“K϶G–Œ¼ìp§F ‚¥ï-Õ@ëœ|(ÉÑÝVؽˆ©RͲ¯½ÂÈÎrTT—ÁúËÂËmïq¹ïPgúñ£ý”´0©¦þ¦rò7RB%e\íäkׇΊ9%= ÃÑ=#—1öé‘,î/t‰ÐU Ÿ Ü5ìî¹rfØ=¯D?ã7&ýJö¥FC˜¾ K‚,ŽË|²) >7µ·§¢ñô× Ê¶\ôXwÌÚëCáøîÆÈÒ¥kÍ~¹ ÁŸReEÀ¤ïÊφœÖH怾L]³L „{û¨Œsü\ØâãØêM\ºõ*r¸=ti{·òý"Fµ³3Hò½¾U¸Ý3zÃ~:;ƒg¨xE}æ¢õ6têÖ}%œUø#_Ì­ïÒwVR}M8ªœß2eqÉ6l¼Ó…ýÛ7x–C,•—j¨ÐLwoÊ^d\~7zÇ/è-CàÃ8ÎÌÞoí°þÚ¾µ4}ä¢k_ù43•NKuèÌýuÒȆ´+[TÐäwU(Ò]ñ´1hX:b²ì~Æö²tZy<¨z&EdB~ÆÑ71íù…²WUÕ¢|©5øX·‚xv؈öë»ÍÀˆñL˜e"¹ÎÌY·ðÈÏÉ$£ïXMg7Ú¯©,Ÿ8iš”ô‡ô›ÍïXûAq5pæÛõ6ÞÇýˆ½pŸÌëyfÎH Ó€W½—Fçrq5ÑGÖ«màÿÛ?«©7žMôòŒ5 ŸFÅÛ*±™Í©³ ÚÈræ¿9X’÷d€R€~*Û0‹ô§P“ Ç2*è3eŇŒ@¼žÅ-'¡iÌz W»r,I‡pòÉæ»•è5‹ØKMãè>è5”öMõèq}ú íDåÌ·BLŒm‚†oc[t^"4©pvFì2¶LbIº/spÙÃ.|ÏZ«E&°íÄ6ÛÖâO{‡ÁŸfNíilYƶ· ÞÕ´ŠËé$Œ?óQHb 8O©èŽÙ¿Sr™Õ¥Ùwåôó lWÊ!Ô$å®#M¦‡N¤aRÿÜ+ŒÂ¢8Ý&lÒu=IqÍåf¹F÷p•“PPûTg%g™µŽ§è-о‹³Ñ<»@Söºj¢ˆ*ªµ¤£OÞØÁÒ®ÜTSä†I€a§Käů4,<ÈŠÏ6«Ÿî=v¯Ts­âÝûc;/¢y`N¡ÖÄ?—î•ÒH0Î?ÍåµÖ1–ŠòûŽðpˆ½z2¡{z½0¨ÀbŒŠîÚ†f•©£Ý'½Ó («ðD Â>[”Ž6„æÆFh[Q_wóqN-¿Ï¹l¦£‡«0T™2´ô“ÜþÁ¬—Õµa×’œK=ZãÞMs„á°M>œ* ÙAWZõƒé4Ѭ —É›}cJg¼|íÝú4gò¦(íÐ ^¾‹ð’Æý—;?ùRÌe©8Ê¢ò|ž/ƒRU‰Â²b‚ä†Ãuˆ¿û{.KG=WBô»ßnëïJˆáÃûàìJ¤<ÄÅÌ‹Ùð¼*S&²©´æ9Ò°žæÚÙv15‰:–’NqÌNäœgØB…t— Nô>æ_¦´ïQËëJ»G«ÕhlcôŸR?49¶ª<ŒCè”çzl-XÎ&ÚÔmžáunµºñco8 ^g—ÀµîÇêãÔ 4x xH¿¡ÉÍ?¤_ï>}æãœLàCû|‡—¯¡¾Ssa³?Y}~l½x¿;P¯Ç¢%³:µÎdï¤ÿú;îNÏo«)ÍÂå½MQ@_¼·ïwÐù‡B3 ÷kuS ¼‘£™Êh;t§ÉG7Kí]¯Â#k½S1áɪ㠳Ÿj2•þöTø¡ç÷“-ÁŽÄ÷ Ö <’”Fû¨×UøÂ¥˜ªãq%s™vö4Ä/ŒEoï˜=!üªï¹ I¸zãðäsá\C´}÷•õuyEitv‡Þ{†vNˆ<<8¾—0©Ósõ‘9|¦‚G dzDÇÀ$©S.g:W®µ=©H@EdBuQÈÓ˜K‘ŽÉ› àÿŽ÷bôRAì9¶Vý(ÜAy—Õù˜ÀÄoF|¸Sœ)‰’ZõŽXíXêó°?­ “xÉzÛd²ÿ«=ˆøó¦¢ QöÃÔkÂÏh)[–m U/É=˜˜6#Ëf´uÅïS xbhcb³Ì¿½ü’¼eg¿ä™áá0_Þ!‰ÿ·@NÔ6gŸ}ø°ÇX@‹¾CÙC©¼“üû“\âè¤ÕOõ僟DÂ~î÷¤Ò£©®ó'/4¶7¤$ MϯÉ%pOÂé<Õ«,mŒþhŽúÆ©í+SâÒJ_hÃÈq¢qÌâÍÓW4L°–ßÒɽwlvÑ¿µm¦ÿð™… 9ÃÇ!É•Ef3Õ½ç`/dŽð”ù-ŶF«ž®ÔÈ­¿_‰F6•Ÿb!Œ€¢²*lÛî"#Ÿ3xÆ¢‹pá¦öØÝxøjÙ gáÍð•ÛSçáBéûÏKõ0 Vq…Ø8þ;ØåÚk^F:Ç^;§>'Ì ÌQ– ŸFo”%мÑÈØ \ØZÓyúÐâ׿ek{[ÙáPmÝ5ˆ¢_ÚϽk·ª§åG>Ì¥ÇÆìÄü,äGAfçXm˜þ4¤kµ®´þŒÇ»·g×ì™Ñ˜‡ŒfpÑ r%)îŒyNËØª"ÕgáF—æŠLtYMŸã S¯ç¿óA¥ÍÒ cÞØˆ…:´fÐí É¿v®:`¯ï5÷ x/>Pë9=»ŽñKSÁžå8aü¼¨Ió öVq‹ ³8¿Uµ}@‰>å$Â}ëù­Ý¯þ–Ÿ!­×–R[›uš·Z‡µfó2°„ç5ª¥cã‘IÈü ™<¸¢­hOÙö8ÔøÕû Ð‹z/‹kf¢ŒF©\‰÷?<î-®R!­ÎˆJÂLI[y€ ˆ¥÷/­Ë„s—Å‚2Š {ôo‡%ί|–áÇOÁq§×ŒÑ@½ç²¨«×”O}#¿óíû`©µ¬S5š%T—O3u[#mtvZ£íú:dG؇ý-¾ ¿ÛÃa9~áÖ""z¦Ý¥°g1G5íyÚ©?ªš¶Î2qF•;k^xìQÿ}fEûé›!‚bb™sÒp£MÙø×ñôê~méM3š8ûSæÙ‡KÓ k;–6n¸4®îÓ€ 1N,î+0$a© J}§GÃ|@Ažë¦Ÿ!7íÓ8d¨vç% J\Ëj›gz~~égk|«$|¾ªBŒx §#ô#ÔqH•ÅÂLÅ-ÿ±ŽÝ¬4£_ •x çá–˜ì4eÒ@g$·¾»J$´¦)8RŠ]µø!ÍMãXhIŒ¼Ïþ©dÁý‹þTR„Y{Ë9•ó“²,ãq ŽÃ‹ã¬œÈfµ|°Û9s]8)ŒŠ* ^RD¾—žÏœ ÓKn餲uyºOèoå–73h-‡4ZFƒx¦8˜›ûï4½>!ÄðÑÑÞhØÐ_vùˆµVÐü4äˆ7Øfæá~R¸à˜œdê&ÌØ´ž¸¡» n+{r¢$„Óï!˜Œ!Èš<´ÌPE$ E¹kyvØa)¡‚“i®dìÑÚÍÏ£öùÚ_I¶š¶T‹ U˜ÛþvÕþ탂w*yÒ:+àˆ^)й‘‚½zà'Ì’ò\¯+=â4Wž½Þ^‹Òšë›(°ê>j×áóÎô³×R,LJrâCµ›:Òùo; m+sö?é}šêÏIåêQ„lô„wMq—%ÑÝô$ï< ~A¥¼Ò/dþMLuµžJseÅHmélðþt‹ÔÉÏ¡IË`ïm¨ú.ÅøMϤSsŸ âÄ}À²ø¶ÆÀúª-9ˆ7VW§}}#­–ã .f9c¢³t¨8ƒ[Ê—Kog9Ï9;.íZÍc˜+ùgÿmA½¯‰ÏûÚÀR[žÖ«V€`Ãi°Ý"¾„¼ìñG„wzûU®$!w©)2©MÐã~ߥ_k¸%Ýã»ÜÃÖǦŽðW÷kd­± ñ}2ïånáŒÄãô–žD‡‚^ªýb•ÊÈ~Úë£B»d[3â›·PѨxtµÞ} ¬8•"J"Íýþoõ„¿D5QÐÊMN¥!¤?L®•]þFŸ¼û*L­=R(ܘçX! ÙG‰¼?‡wšÛ lµW¦ªƒŠñqºþÄ¿(À‡z3J´‰Cá#‚“˜Ù#£§?ŠÏ«H¯,öáuQh'y¯ñx.NÍó§Ê½ÜZ¬g-Eé2÷Ò¸ÉßÐ|ÂM©«¥_ËHJp( `çæ¯ŒßÅ ý>ÿbÿÂ/c7½b¹Î)¶Ë ¬¢Áì F;¨À øôpuŸ¾µçïIÝ?lÏÁ£Þg-œ´°±›î>}æ[ŽÂËXˆõV»èêœIó6Ô¦øâ×Ñ}jç0«FÃå©…ÅÙ0ËJ«Õ÷¯ÊÀo†ÆFR¹4Ô=™ÿ² Ý€¾§o÷äT¿·'±ÍÙ*†_äk`©¬9¸ñ-+JKÝ`³®áfý`Y¤ÓJq=«mNÌ4ôÂËéõnöô½9霻TøYŸñbð|¼{idºì•Á¯¨UYÓâ,ذŸ ÊÓ_}r-Y¾¼ý(3Hb'“Ý”Þ ý_Pè²cô3½¤+:Õ­Þ“TBHÍ– Ãñ(éNtͲ3š^ž1üQïŠÚ¯ë³0™ôg+ó¦­¶Þ´²’€‰kúp…MQ‚Wmêã±ÊE‹œ®„m&ö!|¿n=Y®Õ«2ïe|I­“Ñ`έ&’Ia\ÞÿÇŸicgêci¦®þaï5Â02Hèžb…– e¡·ýãdoàŒØˆ&½Ñ.ÏQ9ÀIHkº…ix›ƒ«‰+k£à!3ñ”¶AX±«œ+¡FøÎoXÍHƒ~¾W˜âÈVZùzvÍ `?L÷æ'UíFl.8úv ~5³ÞƒzÔÊ­—ÚˆÊP‹ðZæUU¦Í3žœÈtÚ Ž›Ì…à°[üX>ÆJ#šS“5×W1>™Y8Ipã wb‹/RÂ|ŠMr˵x-ÉÝÕfó…×[€òHï1D•­å„š (“?ñKÞWµ"®ÂF¿tIJ˜£sù^ƒ=ŠÇ9Ÿ§H¤|ý1ÿ7jÃ}ºv!By QÓÕáóÔó„¨W”2ú¦ 8QY R¤x|[Lúmúäâå¸p &… "²>}Íò‘k×&/â)W ]t]6 œo -o*åd œ&ú]Oø¸ˆ@i™Áª_…2o./©;C½1Ê¢1`t»Ÿ‡Gõ›SP5h¹˜lÎÉï„¢Öß´"Öpí.D–܅ زI ;dÏgC÷:UÐ#á%Œc|P'±ØOìО]LY¸Å)Œ2 ½yM€Â†‘Y¦|V]¹Ážbø®$H=aâ)K„3¾[ êP`Ä&Ž”_è~1_$’j†+3R7Wø= rHóæ^Êz‘鋼JEsÇ5λAþX=Ó( 6W˜OŽ¡´g8â}?—(uõá”—›×2$Ó(†Ü9icÐr¹ý‘ç{V©rØž©ì¼z³]nÎ)Ê›-s‡'S‘õŒJwŒÚ› f<çYÅ‚TÉŠ³R|#Gøë±g31 cò;Ô(éŽCJ3L7[¹êéÊåü¹ÝÂú±È{šÁ!Î"êDf¸ü(î†Éƒ`ë½9Rb€€Ç…(ÐNQ±óFŒ¦ÑsW%h¤;(—¼Ð*:n‰:¾æáe)dêqxæˆâù³žÁ\[q¤ÉØ Ä,öéù.ƒƒ#ýGä‡vêÐÏô–^¾Aq?¾E®;  EÀTpSr©ì3¸¼C¯º¥”Ü ùÅ.ηq¦¸3¨XŠmW¹jÀÛí ìÜç©Yñ3d+Š>Û…|W—f8×@ƒ]°"6öƒÌ7ðyañ‚u¶a¸,‚2h:÷–©õíþëÌÅÑJäð×À›E2ÂoãªâVŒ…>¤ÑÀgÄ^4B¨÷ùóv~Í÷¥QEyGRRš:sºš…>B+Ýå!Mtœ ÒÇ ™Ù0EN’-·’Ô×pÆ'né³SËí›Öìw™€¼¦æû~>{ãéo°‚‘’Gè÷ú!¥c6ðF¿mÜ__`’hTo0P2¸¯ Ê°` V‡ìXVɶ(Wj†¨Kiúa$”V Ó’Ä&"í” l‘6kßsÆm:¬Ë s¾×ŒhÖ9e†òi”$” ICÑB~Ì•‚ÀŠïÜÌûFƒÕŽkl“#ù…ëX£'³ !$ ö+!UÐðszÚ•|ò;àŸžS¹ÑVÃɤª¬?ss;1ÕGÓ:Ø¿%2«¦bï_3z+f"ñë)˜£@‡1š:T]šò+5\G£…:àšl1¬©º­;ñÚÞïœØÐ±æ‹Ùê‰ÑEdí;™RŸe[ÊñõH·nü¦D˜øPfÊF½ª0iÃ]ûm†ãk,ùWÙo3R&ˆòcÎNÃøi=&ÝÖ¤É"é¿6æ?Æ Çéï¤ Õõ÷&ÞбToáB07ÝêÞK«¬'ÇAàݶY°‹I‰=Ä·»„Á;»®m¨oÛ°~‘jŸ 7»H‡-EU+÷òÄ%‰5ZZ´}[×ü]Ye(å¸Y1KþÙ zñUÞóÞŸp¡Sôö}†z¿ÄmÏ;’AœÚ<ÀtK}¾¾®Ù3/ƒ¶¯&ªiX–{‚xê錂V¶kÒ°^e~A³Æî(åSx(­]5ãx°‡Az½¤&vÊP¿Éê[ð¿ŽÍÊX«Æ"ÊÃݼufKpv<-÷9Ù4Ñû~üú jÅv~¹‹g?”}®Ýa® Û¥Ov¬–Uù †£ßØ>ÛÒ7Jx¾mG‹\‚c¾ƒT[½?^ä’Ÿºø]Ÿ\ 9ÅLÉð¿µã_¢Êš‰ÝàsY\A5ž!h°1ö`¡•ãYíÝ?S·{‰RªìMìÜrÇYq×Çr’T¡ Š[ C¹‰Èh¸lñø¥,¬n”׫¹s ÇHªx×Uú¸iÑ{¼°´~˜]‘86± !Â'­ÕÇqd§ï­i×N=b‹Yåiih÷öPž–öÑeL|„s‘£¾Å5Hwû|Ü›Y5kø ™ 2 %ZSã ó “%Ù‘¡?‚rŽßµEAW÷eÂqaú ž{•!/0ÉLá¤-¥Q¢4éÔÏÑÁ²ëõÇK–Ô¡ëžéøãÔäT»_ýŠlF°IX[æÂÏ@é”·rçX—ÐJÖ£{Ê÷i‡9ùŽ$)gÑ—¯Ÿï=Chö^“©Åê|N׫³›õ8³dý€7ø}ù!òs­ƒd‡Ì¨ë°ÄÛ‡ar‡W V~ŸXwö»"-\Ê]£‘›€&Vþ­d˜Zt/ƒåG6sfÄT‹áŽÅ¹øîø ͼ=Öø.•ß=#ýû©¹Î“2\©õM0ZŽB&…¾}†ÇV3 6㞉¯ê+þðl£Q>¤ÆS¿·àö. v*v·ÃÍÙ0ïñµ…@¼Îv‰¤ÍßïÉ–.ö=~52Ózì듸ӳ¬×Ö¯Û‚a±YÚXGpJ•Uân-Áˆ×ù4³D'аsøŸÊì¬aßT ŽBL¾—ëE žm÷J¡ó~Ðf]‘—}W\óá7t ÅzÌ{gFÔbÕoº 5¢2®TÉ]Ãw¹[4ÚÍŽR•<Sißzxø{´ œýä |8gŸ—w!pÖ2éVÇqÝÎ3«güi!@:—¬ÜD bc»Ì\#Ùåþ˜1d—”8CIæô«È²lE]¶+T#1ìߌðý18¯PøWÊ k¼Šž{J…úrvžƒÅ¨=1’¡Ÿ{l{ªŒ†|JÂ2~ŽÝL| £ºÒÁ?Ö]ÎÞ‡ñ@Ùë¯Þî°µy’”\£YvÖÀ¨ ´“üzŸ#:Ü&èÄiá²P¶¥±QÙ¤øHú©þ€•i2ðXà±õÇ]ä*c³þ*»•ˆ»òŸ»Ã<·­”Ãâ1&/²¯=¹xC†aj«9Žß‘ÃIDÍ©òmÜÌ.S˜Â—DzõRúKZR…Im~ ê•(}›.sÒ¶óX<@/X2“—MXozzЊ½x¹Öu ÔfŸE¢Ï¦\VPÆ{.} ˆ³û&6Æ  âÑdå³ý¾b1ìj—¤çW´P+gB_UVLÁɹkƒÄý­Ü¯oÎØâ” ØÀOÓ|æYB!çZ#’@뻊SÀÖ‰ NûçN˜=.¶õK¶kø³ñ5m®0›‡?¥üDúÂÚ: ý«ªŠ§ª¬íË,§”ºº¦ìpTcÎs‚·'§ú»ÄœF³ê„ë¯Xå®h1¸B·$¼·/6æ% Ï e÷µÉó%Ò Ø’tD:Œq/Õ•Ö]Ä~åsCkÅQê¶1 í+©î5$u/÷ƒ7ÞÎñE{8±mèÔ_“«¤P¾Ý~àé*™­NEæ…#¾c9‘ýÞ•'Gªž[¹£!{”ÜBéô¥Õdëwi'L«‚;^Ž4zxį¡;t1âȬ‚\WcJÐÄ/shÉf_e%~ï8Âܨ˜E#-SpùÄDå5¤Ò˜O‚êáŠ\"œ#c(gÝšÌzeý•²9ÆžÞKûÞnÔÇbÕKr¬£V( äaP¯JÆÕSá }QôG·ô!¡dŠX[yhPŠF2Qþ\˜iПvf³2§™6BQô}Þ@#©µIœ‘{©ÿÚ z¥0°ƒáàEãCVâaÌjÀó®O@… Jª1+w%z'Ì—•KEFô+tl1éñEe,ZaJ$¡×ª/+)+óæ¾uˆÁCÝ-Öî|„³ M™Æ‚F‰i…=µÏ3Òг;÷âH=Ïð=PMÒFî5óËþ6Ò “Á*ÈsM`ww .–!Õ~fš¯¢Põ–Ha¹qü`Ä>XCÚÕö(ì¹,?…BšU¹¯c6žçœéW0$àw*RÁ·ò”˜÷Ò×ñÿÚ˜âF³“L3¡NôÉTM2´ª+º½‡ &Ztx¡XË ¶"·Ñü‹ø´GLs^ Kœ *RÊ“QÆÏ¯2“»ë•}ÙïEŠû¾Cõ'µõa –G¾ 2ÍÞÁ.3¯6ãîwl>Z6ü°ü¢4/Pœš¥äuÊÍôžvê êÙòmÁM8äØ2Šº[Vù~åæùj#cæâs-FÉVZ¼Ä-=²_Q‚lÛ|ݤàmPg¶º˜ëéqé¦Ï–¬ÄÚÒKÓ9ã¨ìÈ¢»þqîŒJÿƒFðjjh ¢\r$ùK^ÈFGµàÇú÷¨¬¯\w•A#Ÿsbéð´ØcõV™£#q£ÉW“–kBƒ~м¿àÊ‘1" Û¹¹m?UkÖú®Þ艆JT9JXz‡%"ÎI97Œ9lÔ‹(2ÎÇ)«ï*—WÂåýùrª3ñâ™^§*^Ný‹„™ÏÂè8›ÓžaTÈóÉ[T-Á~âÊ$NœùmÎzБÜëeäì'}6; E‚zõB.¾êX=Z2sK"³y+dL†'i}žz¥/á&jì2t“‚)ízõcÁ %ÑeB ý¨L‰m±GÊÒ–7jž×.J°*fïû*j²‹úõÒ&öRØu—/ÓzਸÃ|¸¹ÙêF´4ÍÒMé‚«@ÞÍ;….Ù¥fùÞ¨öYúÉi.éÌQ[–y†A×MD.åï5ѪIciÊ,O¨¼0«ðU^âÕêkgYa›&…fÓCTÇ’0"æYú°•%ÊÔŒ3ɘ14tÉ>…óþr»s-{LfO÷Œ-œ¶:gwlÅœ[ÆA=ã ¿Ñõˆù~BözÆVä–d ®À' þFýJDÆ¥¥]$)^ÀMb[çUÓUäuüf•©,ˆ{qºþ¾çɉeWTŒ8 «¶ùHõ‚§ix`¢#CZ\°jÀgèi?‚ìJÞc÷ÐŒÌ:D)ëù¡‚}DìMIëéõ;¦»|Ëù¡ Wاiùt´ˆó]ÕŽË_ä‘40âªuåÍÌ‚ÑjQªʉeKæy7ÖËÃó~‘õÓQu¬Gèû#éy]ϵ?Ž”6mB°û&[ªe&ßt%Üûúð~r7)/ {Ú¢¢ÿ…@äpÆhLk4?´IÊNpÎÛ“fªHNÖ&+„²z’ 1XJ´¨œaEÅ«ÊxŠàZUfib¼júZ*L¹^¶cŽ• tǽ>$”†™úÝÚ`¯‹Dj‰a÷9~rÂh¢Fþk°i;.‰÷,zQ}‘°†푾ÍòP½ÏTzÚü#/"~ Ç»’D5Æ™ƒ¹kÌí}{ÞÖUÈ&ï~\5%àJgjÍ„V9dŒN*èˆo¨^µËÆ}‚5èptU’#;wëßk¥Ø+ÌtK?£™'{1'‹ëN™e)bü”ex:§&ç[ºŽ$$2xe]{k‡Ã˜MíLkä¤ã“eUî¶ ž$”=³M4:zRåØ`pŸ.ö5~ˆ¢g°ø\T*„Çt2iˆpîqP®(sðúW«¡†±ŸÃÃî+¸QžZèÛ+OïAÿäé"&ïý?Š uò‘GÑ’ŠÛÜê1ÅÂO‡>›ÓÝŽJÒ°kÂ:ÅÒ(ª­a"cüŸ\ØT1$SOOÖûÁQ¬8×'4°üüD!)›1eL”1°øýœ–»Fû€´F¥‚ƒø&¿õê§ávmÓ‰á¯^5y½C9ÜîÒ©&+a¯âVCA,z´¼”?9=mð|ÒY„±@ÛƒH ÎÝ¢Aim~DÇßøäõ‡­îÒ΂b‚“(LóQ¿rÙM0Ž"|ÂûGí‘ÉLþÎԞו PWKh¾3º¼.ˆþÉÈ‚Êä*’. ƒÌA­&ƒ MÉàc°´N¿ºM1£ØZc¦ª”ìûêºÒÿF¸ÐÀRDºþw*¹øÄв½øGEQÞivíÒ^m1£DkqA ŠyÇÊ@·‰Ïœ.Ý”U j Þá[´%æ­Ò;ã3å›ý"#ñDzˆ½‡ä·MâkDßöl¯ã@'KTƒ²Û@ÄL~{³OÝM‚ÖNˆñÕXµ ä«IQOÿ‘b ×{ûMéïѯ3Lw„®%Hªù:ýçÔž —]’PbV»™h…ã<¾›Ù ªûò2ÒÙ÷;÷a¯ ¾«²É{~øwb"Eôxh°0C7¡ U³ý83¯ÿ¾Bœªc‡zòæÏŒopD¾»^ƒùû¯|Êjü›Üóc¦x°d¥”W #L Q-‘R¥ª•n]+!÷g3¬ÍT4¾ºJƒÊŠ\XxHÉZOO]2çæ7UL° –BÞü0QCѳĕ2bÅdÝ>êxG’Í šº[ÓíµðÅýiÃÅËt½-> ?»+A‚k¦“üx욎-YVá۷Ïåúš»[ùá;ÈdÆz¶ÂÓ§ó¢ØÈ–xAòøãÍbScîÏ ãôGg,Èô\k5÷¢VïÌÒ}Ô¦A£chåÒGšõ"Ñ5C3(›ˆ4PrlS£4E¨xä$¢8©_¦s1‚ب1BZú¸>•V$se'6X‚²L:TQø6ÄI‹]‹å² J}ÏoÒ!jx‹œü4ÃÎ à• x±+?7†|©%è~ůfîüpì3CƒšyFlÿSÅIŽ_Ès'ö0¤z’Vº¯ï r²•}˜¡Œ^‡†|P.éŒÖÄÌ<ˆ£QŠ>fŽ¥4>^ö·®k,¢VŸià/ìE¸Và'ªÂA“† ™€»DÑ(•}.[É®sP#=·]d|K¨XÍäÐÅ$.&é``ªÌ)ɪ íå°ÁZX“Ö:ùcU36P°CžDïÙžAéÏ¡DúŽ" ®ž¿ûCž¢LU=Ô©šÑ/¯XÐ! 漏7=¼d$dõÚ tõœó¢q††P•Úv Ù›Y=ø¯º¹Ϲåp@Ô]m&¾0.e°ïЪÅ0áW ÷ísO ãe`¢Ú3Aï v“ÈŒ§ÔnÞ*j4rèÅ9Û€…ùæ+ó$S%Oî}öÛúˆCíUZ–EzájqÝÁëGÜ{ý¨“š¨†Ù)’—õdU_«úŒOoL_njn¸ýŒÑí=D@Sœ³ÌŒIfûוæQÔ_¢Þåç\Žô4ƒ¦Õ1¦u xÉSÎu`[ü0N——©𸵤ÈÂÁ]ßüƒzÌ5Mø ü‰–ΡR Uhm™E¸²¬Â!OÌ_4c‡õ6Úá± ÷7Ã!O»»2G^nD£lôqDNMÉ‚ÉÏ`³Wg<ó¶ŠXãÙ7Ø2LÔɵ޹pLøµÃ)<H/YYkÏ»ÞL‹õñÇ&üè„iA~”L¹|±™çTÚ0 u|{ÐmeAëÔ$‹HP¯GÖ ìØï¿((*X&X’â”}n9ÿe]Ý E׆ÃÄ Œ÷Ì /Ç®ZöOàëv¬eGû˜ÏÆ'4:@óõžÝ×ÍkDTÑcÒÙ ˆ 7ÆSøÙÒˆ¹#¸n¹Ò-Bø%A¼¡‰W[¼´ß@å?úGÍ •eÄ€Zckdå4¿4s -^³m†Ò[ò"šÃžìÿêGÂâlV‹Û첚Ùf­€”?—M8Üôe^NN8Fb6܉ ýŠ´V/™u×Ñ\dØŽðôN˜èh¯à«ô9€¶KfP>‡Ú@+héT †\0|œ@çòuóZfÉ®zãG–$ÿÝ:Ýf0à_EìßôE~OõÓ5Çýü»JˆñxŽà8¤‘ÉN{_B´' BÆä¤²> ñ‚–¨·Áö'XGXLÿ¨eµëë/ymÁåœ3h“ ,õ†_eG%ð >2ÉåPbŒÙKGΚxbÏàGûdx¸c«à4Pìl·ή Çݘv½®-]«8ŒVÉEk mwÆ k¨™:f[­qªD‡î:mç|ã·æU‚ç×—mø)|º\:!Å ™@¶·"á4yQÒëzšO.Ž ßÒg(i€s_™–Úþqx,‹$üf*ƒÈ˜è¸Q˜~–'ž¬uÒ‰(X‘G¸—DFƹ”Ñû忊пT¡ ð!ŠèÍ5¾X˜(Æjð²/üñÓÏE¯Mëßþœ"mjK]Þ`žú ï†*ÿ…' -.Ž×¢«EÓ7Vö[§Ø¯8h:5¾(]¢ #!öhCEË6“k(‡¨™ÕqÀy¦JÓ¶ù @TÙë$}þ†âµôCt±¢ßäþÜ·6÷JÇAq¡D ÂkÅíožÄ+qاI?|€±%ËÂ?ŽdfJ’U*%e»ãÏX[ òÐ)§·Ŧ©V¿fº•7öèÊ zMR¡‚ñA]ñóÈÁ¡ð&@a’KšË3²m0¯áóíÐ>šš©‚cÔ _Ó’þœÞ¡wÍ/=˜y)Ô4áì ƒä“7ç<}ʬÊïTð•åï1˼7¿ F¬½¸'XgË[ÿÇne¬¼€bæuÿ´Š¸I‡rëøâË(Îã|U%…‚‹æéÅ}÷UJÍäl­Q#†åüöª¢¨!’ ¿L@}Þ‚nv_æ¸Ü¹ñvßÞ;wowÜ û—W_™‚ ×L½ÏˆÝ²Ú’¹Ê‰³¥‹ˆ4 LŸÍ;ÈÎz¢^“ƒ×—æ_NÂ5VÙb• endstream endobj 86 0 obj << /Length1 1561 /Length2 8219 /Length3 0 /Length 9244 /Filter /FlateDecode >> stream xÚvPÚ²-—àA‚ ww ®Á`Ü]‚»{à—àÜ]‚K îᑜsÜÿ«Þ«©bfu¯îÝÝ{õ.h(TÔ™ÅÌ¡¦ i(Ä™™ÈPRcã,@ ;* ØÙô§•F äè†BøÿAp™8?Ù$MœŸxJP@ÞÅÀÆ`ãægãáì@ ߈PG~€¤‰+ؠćB@N¨4P{G°¥•óÓ1ÿù  3£°ñññ0ýˆÙÁf&€’‰³ÈîéD3[€:Ô röøW :A+gg{~VV777;'¨£¥0=À ìlP9]Aæ€_ ”Mì@tÆ‚Jа;ýaW‡Z8»™8‚O[°âôá19ž¨Ë)^Ûƒ ÿ 0þœ €…í¯tFÿJ†ü613ƒÚÙ›@<ÀK€Øx-­ÈâìîÌ0˜ÿ"šØ:AŸâM\MÀ¶&¦O„ß•›¤ÅT&O þÙž“™#ØÞىŠlû«EÖ_iž¦,1—€ÚÙ ÎN¨¿ê“;‚ÌžÆîÁúÇÍÚ@ n¯?bnñ« s{VMØÁ$'ù'åÉ„ú·Íä à<|\änfÅú+½†‡=è·“í—ù©/{¨=Àâ© Øôô…êådâ 8;º€|¼þéø7Bec˜ƒÍœ¦ K0õïìOfÅøéòÁî}à“öØÀ_Ÿ¿~<ÉË ±õø›þû~YåeÄ%$ÿèø/Ÿ¸8ÔàÅÌÁ`fçø8¹<œ|ŸgQ1ÿYðïP9ˆÀ÷G±OSúOÁ®Þ?ÝŸ»Aøw.eè“hAº¿5þÈ4{úÃöVúïÿŸÀeùß4þßI»ØÚþvÓýöÿ?n;°­ÇŸ„'ͺ8?é_ ú´ÿ¦jƒþØY%9ØÅrÎ&O{ ±´ýkŒ`'i°;È\ìlfõ‡Xþ°kþZ2[0¤uÿzUÌl@àùž6ËÌæéåpzRäoèiqþ}¤Ä jþkÃØ¹¸&ŽŽ&¨À'!±sq¼ØžVÑäþ[ÃVÔù)ðÔžÀêˆúëFyج2¿L¿/€UóoÄ `Õú ýªŽÕüð)ôø þ²=‘!ÿ€Odè_ðI}¬Oâßøé û'-@ÿ‘žÀêøø”Þé/ø4 Vg7è?Ü<V—ßð_Ó1sqt|z~ë÷itÿÁ¿#Èd†º45¶® n»®#vcÞš¡ÙÕN£göZrlw¹Å@J¦¯Ê \w¼KêÁZÙ–¢»]&ðÚÿXÚ’¨Úzç}o¯6µÛŠº8‰ß?Q¸/V×GŠB¬!úÅûÁÁ[+Àî#l§<Í;^ •|Ük·O2îu}eŸGßÎïª~©âV@»/›fŽÖŒzPžÕç šã½—Þ{ÌÍœçj…»S5‘!)ÜÎèÔ+/ño)ò ^%E‘XÍ,#ìùòÙᨋòt†»þ½^Öã ÝH’—¯ÜAoÛG¾\ùû "ÿð”n“¨GŽü¢¢+ãÞ-Ôb§JMÂf1{†¥wÙé}=çr(?Uœ6õ> ìXûóÂ1•Ž_K/§,·ÉÅ]}±°»ã‡e¾T_¸c/oƒ¸.¶.ÆÞºÊŒH²Ìrþ;,„Ï*é<˜«™Ý_R…#OÛZ‰p¢0쯣æ¥5”¶î&´Þ—(É>Û¤ÚY˜òГiO2;‰¢Ð¨ÖÙL½ò±´qàË–Å!8xŽáUùÀ*æv-|ýV-äð/¥çÕ¶öÜÞgÀ·K÷-«é¶uÎÐR9·ûçà ‚9’¼ó?t9´¾¹f L}x#c¹¹‡N®†iÖ(I÷62Ý¯ï ´hwD0iÔÍ‘› ¯± kX sßbәߒȩñÁˆ Ò—Íßüd &éRJ¼ò¯g̵4_V;¢Lüa'ãŸMïG2³Y‡ù²¢ÇH  ·Ï½J Lú†EÊòàtºþèkæp¸ŠÓW8;Ëšª¶¬þ£ew)õØô¤ó.Ÿ|jË8Q‹ÊEŒÌ-“"BÀG&Ýž,vhu M›a÷8µÜ–OÍà;ͬxùÏÚ®¿X~%kW9xušˆlö 8ò,5 ¯„[³=‹Óöð>1Þ+Bfðj8âSÈu‰Yxè9ÎÀ=ޝh3R¤VºÁ˜üËu‘˜öz!NÔw'‹nà d²Ï‹/2Øñ•»CM.¤Ì-ŽC##ò³ç$×q±&˜½< “U[ð’¶íH0ÉýÝâd0¤ü6ÐùÛ¿e£z¿äï2\yq!íi$çönxÑÂ_ô_å=`j¬v•t»Á[¹ê‰ó>ânì©Èq'7Љ$YBœ× |JÃÓ”Ïjò\Åq£.>ôm Ó[§@ |̧bÃÅ—ë^‚¶Cr9’æqe­’¢œ]HÄ”ƒÕ}^ì„ø•æ¶âxñ¦šÐLT)T-qˆ!› H dlF #¶ÉѬó:/̃ŬºxzS -¶alåðçúµŽÄ“b³ ¨ÜK6qdžˆz;ˆ ¼œ&™t6À³éÖÍÉá±à°£$y„Œ1!E®ÿhˆYVì7n·/!Ë&J,ýZ íLƒÖ ¦éh˜2²¼ÜÀ§6‹¾e´Ð?'#Ö~y„_ð~¨5¹Ä­X[W£g­?hÛÿÈ™âÔ{vÜj‰iêa‘SÇʃ«ÜÏŒƒæ=¶UÆ!ñ5Ók÷™Ð¦‹•4 —°æå…^UÕdÚ39Í÷0±ö¾%Ïýæ“»Kú§[ ­—ö+ÄJ{®Iw²•þ¹íÐPó6üzæÙ¨Še‚-LàÌ ¿‘Äa&²¨¹jÒ£ªiô+5R®ùeÙŠoo¼ã¡ð7HW{”½þ» ùýAÚY@…É·éåhuËÁ2“#g+sAÇ©;6׈< ½³ÌyE?»à~6¼¶È§¯Óœ’°âe©{.§ ôZÛ™-: Iú†Ò€+^s1"Ž«FdOeÕºŠˆ±×¹¥`´zÑ©t~¹ä­)±–^>É0vÈзô£{ZÅÝ®#§Ú‘lïÅf$ï«Î°Ñ žvµ`qVkJÛ­„ “ÜÞ^#FgØŒ²\ßíJÑKW9Eu„ü§8ÌN[WykGêw‘m({®-¥çßµšááºy¶37?&¿¡…+`ˆß€Ñ"„QëÜâ¸{w¡GûÝ>Zu»oïí£¡R]–9ªéhz{7_ l³Kb¸“†î½•\Á†™]ˆùjàtN<ÜÊÉ‹²‹ØH¡Ÿ/s\>êŒ ©AÏf‹‘¾®eк™{ùÞ˜—Uسєg)çÖú«"S85xúónj»§ƒeyf”½^T»²€VY³|;„F`8âl9!„($E_Æ@¯’º¤_`)d[Ï0¯¾ sv3àÖ–¥›€Ÿ`«ª=ëÁð¢d°ƒïØ2á|OåïÞ´C}%¬¬W}Ó[²¦ã6ì쇥çTΕûã–ªÅà+°ØüÅ 0Ð}Åú]ƒ`Xû&”R›é„†¬`xJmò‚ÖgŨÐ$ÍåEAò9³ƒÂ†Òv6VÁëv÷Æ]LG‰ŒÜf¥£PÅmÊ.áÒ´Õ<8Viðè`#’’—‘îT CaR;ù”`­3ÄÚ´EmªuÂø]j9å¸a9vBp„{a—:í»Gî1Þ…W‘Ÿ Ëì»ÎmÖþ§ªÅêó‡‡õ'4ãÇò5³½«§r>Š]±áêú•·V ëßK8é?‘%íUF¦âæ²WPðsmS­µ&ÂZ¦kArwLîÃÝÊ<~½ŸµÒÜ¿c®6'Å…Ì :®*cÖXCmàÅÂ[Òɧ"C‚7j@ýUžÌ™<¿ªÍ7ëÝ@ÅŸ’ÏÜ8¦4Þmjn²ËàÂÏø Ê}%íp¡”¼T¹b‚v-€1•aû2+ç=·»’6Á+?jïÉZæÖ±¥²#a˜,µ¨3/6Ê0…µ=ãNS' |‹`MNÇKÕ}ÔE`Ïy˜šP¯Ü$W™þGM»ö’+×(Ö›x}Ôˆ·ßÓå\UÓq˜ó ¾²tÑ·% ½±TÉ*¬Hj:ñ ?hÀ"@id@Ñï°ì¤™LüI~ XöE°ÿ\驈›6ÎçTlÖ~,…¸›*Ôçê £÷øšˆqãÃèƒ(?È*GØÅ' žo…Ïj³”O5 'çé ÿŽ _cøRw‚‡ÞI£gÝ8¿tÌ›[Óõ~³‘[T]!¶ºGi›>èwHºéÄkÛØ õIp&ý±• @­½ÀÙyä›)%"tý¬ª"€x¸Bzó̓e·ûÖ¬ÅK­‚¹—ˆÍlŨpùK4›d¹Úñöa8^@{Tó9jÑ Ê~†¾×±Àïò å’ĦÀžnålUb›ò½·:¹Èþ¶-—º"Ù%#KJe÷xD®ÌÛˆUr ÷ÓÌÄHpM©""õZèѶå2ú”ÙcÔ]~y%ˆeÎt ªÓïqP¦¹ß®i”ŸuYLÜ4Ÿg˜J†òɵ‹#Ïä_é³JÄ_Y㼡¦È„â6TuÁ;x1ý\ͱ-@ó¨Á—œt kᥠníÊ·`ŸŽÜ}±¬gê!@„ñÐ^ÁTkŽÆìŸåм 2ºœ›ïØbO}ú±ŒÃ]—¹sQò Ûk4rÑšmðªŽ(%I+Ø·b|ºK×|…HY6©ÉÅõyš«0ÝD¥&M#IR÷n~_ço¤dó.D“M¦1Wí$bb°TzåAYdo`ˆÖL„Ô®QÎõù™›†À˜§õ˜NX#Ø’AŸü(èEÓ7Hd b¸¥íGšM¥f½¨^S9ü8 «…½%á0¦Ê¾µ©É¾a¥"}Ö83žl©r_~Ja{³Yç,¡‚ȧôiæKÆÑ{s”ùO܆¦ø» o:Õ%|7TY°Sßì‰k+¤@FµÅï$*½¹ÌUt0~´â+k1ØÐl½èªy§{g…ÞF¸ÁÔ›~zéCz~²»”Ñ¥,÷êàdš´¡>7›1Ò¯µ˜/J×q’ŠC“Ìà?T6"žÃ!‹Õ šKEU{‘”á;È×ûVB½U©«¦åâ+_ð2Æ7yY¼T¼Á)Á—2¯59­Í+ÛêÌy‡$Ivߨl‚»›Ê9¶øSUS•óxR¯ž±[–—õUªÕrÕØ:¤¼l!ÿtu,27»0»ùÌ :½I¶õ™ÿãŠ]è+”Å´I—½Ï)ìDrºÍ\uü™PÆ|­ÃÁkïÈß…Íã2Žœhz§Ÿ ‹WaªK¹­ }F ¶~\Ó<¢züôß‘DèͳF´6Î3 ÅÇÐq×hDm½²½ï†‡}Ô_âÓ) ÑÁºeyÁD±Íœ›é¹¨€+|¹ö’㨽»o8î¶R<„ÖÏÛcóæî]õ¥^Ã!¶„YnÂÊ~Ç´ˆú~¦3žõկѦ~£öDLgîVà ¢jö¶\²Ùß„öl«]ýyð\9«d QB¤áㆲ/zidƒ¹´ `¿Rüæ· ï64 —a Sí’s³íâǾ€ˆâÃÏÏUšY’†g¯ªVe$Þ}·-HâQýÈd TÒ ½G W!#ÀÆ¢[hxH»Ås:¢Xe…Eßê RU<E0_üÈ©x£‚°’àþùž&rB´>F =&{Ÿpâ­%FÙ²/{ÆDu>¡¨¶ÁZTŠjϲÚp|;fߛ뾾å^®mç†9n}X²ýÊi˪¡šôIØ£©Þ@ï §ˆÍ´ÕXŠŽ9f$¦ÔƒR³Ð¯jƒ‚îǧ˜:tÿE,&·ItäRÞõ‚ p/ÙU7Mm4çþ1FÝ“µ‡Ú­/U*º,OwÃV¦ÿ:?=ÕwË*š2òkBm§Ö… ý9MM‹2n6”íD®_7†›8“È;ì)]è V^ ¬‹ \S¹|ãã< ÊAaÿüíë\áìâí1õ˳2.Úüñ€žzòì ­ ŽHÚŒMõØ ²¥ñ¹µSùѸÕ1âkUç8d"5]´Ë´Ï†zx’ì KDÎ7jIJT4¾[Tßû"‘Ÿí¿þqX ^Ú«÷²%&Ãpà¼KÍxL&¾ =Þæ‰"Ó +éOX¥v”BïŸF¼cÊ¡70™¡½ "Œªå퀌ØEâE¶41 =~ßÞ£Bµ[#"»X±ŠG0½Oï´QßgÉÜñ”ƒydJi54qôl,4ÆH!{à~WÎO2 ‘8þ´Þ…oÔ“ÔÏHR't¥Öð€dGЖ»U{–À±ª¬0ý4ã“›i•~+çôðEøÐ¥¢«g ÑžW‘À_Uv]Ï.´uö€ç'T†µ±M…¾ÁVð ;Í[“=BGâdÆ÷'ô‡¯Y¡vE®ág˜ÖáõµþIÐ÷œ÷3vËG•ÏŒ8‚gÂ$2«Æ1]v’wÀs¾ÿü3Ñ%ïFjÖåBnŠlq~ù¹ÂÛŸ¨ÇoÇÊÑÞ¶â÷‚¹ž'œ+Ž:žf}?Y¯‹ó˜ñ…Ý£D“yÀ«—éÐÇÆÿûßÊd øj|Ó€/æ ÌB}T)ǯÒV ÷ß>UWȾړ–\Œ@ÛH1®Q&ß‚a‰}”èJ{¶r©÷E8ÙPå|ã“zŽB:Ž ©bù*¨´hKy´Gé“°v¤ª+V[ñŒö-UP`¾ d,gÄZÍîx–ÄêÕÐ%é70£Éª³t}ꘙuÇp4Âh?ºRœŽ#šy ³fƒ,áv]p×'Ö3_£"ZºÖ=ö°¶ï¤Úðd‰¥SñŒ¸.M0Xê e{\~ÖdtÔÓQ6ç£qnð"^á”.ôᓦ.JJÃ/£Ž?ÒÛ¯ç{Vrfkø0?Ù&.K…V·-_ÊD<×dHÓïû sÕuưꚙ‡ž}(¡Ï¾{ã{8úåÚÃÆïøzàôU®BÙìI€£:Fç§u䉿‹ÁU!ÃŽ1‡ªiâ‘åXe¡ëRïö7}äü¬ëõ‹iŒSó^‰£b;(JɘL#DÚI3]”T0¯G/éÈàÄmDØB# ¶˜&gÓ°Ÿ¯ÈÏ·Z CèËN=­ÔɹÖ[IúJϘçÏõUa „Ÿ…ùa«çô·«[õ²N“«Ù,[í.K親W O•~ÒžÅÆnLËejÌ(xË3 Tú%þ„êL˜± ªwØ8?º×B áDrj$s°{ýì;`œ´0›{Ø I°ü0¬ìs×ÂUƒø|Qç¨TarÄ™FÚŠiˉÚÉÙüJ+#(ÇI©cæKŸ–÷óýiÓP¾9¦õ ›ÖŽ# =P‚н)í—m íuÂk´,µJ‰-=jèþhZÌÏ9®ŽIÖ¥´„ÒÐOÉÃ0ܳ‘;ctLnØìIÕe½(ë,OT[ë¸Üd3ø\m“´JÁ›ŽèÄ+ŒòA‹®4–^囎ÀÜííˆ;:Å¡ƒmø~Ð<~Ñ*Mo³Ã % æ°Š¼i!ø{:a;¼PX‚E¯®hH ʌɨ“ÊL¦•E£J§ÌBfbæ¶€ægl>WÒÚâ„h­ÊÕ,Κú^â&¾³~øpTޝçäJϽìif˜¿>l#ªò}í¼öB·æBœ6-¯òÍîÄéÈ6¶Xèe0þN®Ã¤Ö{¦’ªœ¼ìÌmók/Ÿb*ÇJÓõ®ÕoD§”]u'j‘ IuM•ßÖÔíhx‹â÷’á¦[{Æ«lI›Dôç.œñ:]"¬Üy­t\ˆ4áWÎÇŠMg’`”ÚÌœtH&ÞÎ|©É>äêo*5ùÊs/”ÇUL,û˜xâ“Ìʾ0™=î½oàŠê–, ÃIÿzhs%œ"õ"}SyÜsiŠ_w®Û'ã±pµµ{BDLÆ©QªÍGØ1–8²zõp1Š‘ÝF$uŸ|.+rè¿‹ Rš_‚Å4Òd6mç>;°öå´Ž÷ÌŸäœICÖóòq T˜Æy)k"ÌP·^N)|&Åžpvsë`¿_ud È8{Aüf¨,¼xE]%©uÒŸüáÇñþ‹/‰mîT­2‰©«s@¨“çK/6GÙ)N/yÙNGØ5D²èE*£Ï‡ªÌÏdéÎô˜™ÕÀDp?ÂͦÓfgl`¢>`[9iÌ´xd«K2Ïñö²Ÿ~¶ˆNYlÜÏ5 ·‰­-DæÈ5ðÁÙö¤Õí§„·ÒÍ+rªé8E÷CÛâ½1Õ^)Øè{Øâ ‚)˜jÔª¶«¨dJ?:eݰm +2C‡u=Ô3ÛôáVöØiÀàBš½áp‚ÍŒT$Û"¡ŒÚZЊc®¦9’ö`ÿxX¢ÖÊUÉ®ÞOnhÎ;·¼žœ4c§5Ão`Wq¦H;E3߉,C6Ä·WÚFÔvwrާšS˜Ÿúuýš°©50°w‹ˆ'öA•m°ª:dI˜Úá.\h—#Ȫa—Ñ?¨nÔŽîÍItàÙnÞ5¼jq@nw5î¯mÃrøzbAÏv#ˆµH ꤮æ³Úãbßˉ|Ôd›#ò ›¹x(§çîr-hÃbð†òØØ4K±¯">¢-ŸÀ€ušPýèyuPdª Ý7cbœIú­B¸ð×-w—uÂVQË©ð²“Óެ›- d“U!~¦j´ï9]FüvÈ"{ˆ*c𦨙×6Ô·<нôšª¨ü¢$¦@ãbp°¹¼î}q#XN—uć;_1ü±u¥ƒ®=¦’j}÷Y—r([™çšZÔéçVœ²4ö¼é¦q†1çZà<ñäœF˜g‘TaÁ~Tx.%ß„–¤À2¡,šS?)3$ü4¿û°ÄfPuv}OêÊãØü¬ƒÅ:ó-•wJ8Q¬›¿Â{sYP¥N”¶6ë±^uÈfÖ0)JÁ»ˆ¬eŸöÛU—Â…š6Ä)9ß)kضsÿDŸsÓ~ÁÃ~$„‚­SïÇèOe"U¦V1ï2››ê_듼FØåÒÓBeâDKŠÇ°Û¿Ìè$Û]|'Kæn¢·SÉ¢Æ ™q¥öÉÔà2Žæ &².GÜaÿDqüŒE Ó·ZœßÒ0È€nU¾¼Ë½tõ³‹vIw¾÷Ò” Á´É“àfï°¯g?ðGU#á3<±ïUž)üÝ{ìPÿ^H¹¡Åæõ›¬¯ ëiˆ5µC&uhà ‡¸y_eÎ$oi£áØÛÂϗŒcy‘CR¢ŽŽ¼ï ‹ê3nv¼œ?1æNŒ¨ÍÓÞ…MîG™n}G}¾`…Ç÷¥ó{  «{d¹ŸÝný}Õ ÇŠk£;¦âÉåy°Váû€¼ºáh…G×NÆn¼÷½ºs8ødžÁ/W6¤A­ÙlÝkè}®÷QIê[o”2è2¦6¥@Z³"ÏOývÔdG7ábÎnó1h>Ÿà…cUtŽàNpçCÜòÍV§…Œ°Ý;Öm…¾—9lRÅ©G…®=ƒଥÔ(b¸|WŠ•Q£ÚÙ¤ã2“Çü¬i4/+aâ³½B‚C—ÕþÉ£»ÛÀÛæÎ¹D•àåj’€%Þ á¥~°î¼Ž1¤çW.ºS:ߥÂ| ELʺ2ÚÑe È‰ñܨ‹ÈMÿ ø_ endstream endobj 88 0 obj << /Length1 1373 /Length2 6090 /Length3 0 /Length 7029 /Filter /FlateDecode >> stream xÚvTlû7%1:¤‘I(½énI ©1 Øcäh”$$¥Q¤¥A@¤$$”.%E@RþÓçyß÷ÿ¼ßwÎ÷³ÝW_×}ý~÷ÿuc3QUg´\ ŠBÄÀò@uCS ,!‹øùÍXOø_Zÿ8ÆFÉÿ/»:ÅâuP,ÞÍêùz!@ˆ´©ÍÐ.X(Ä+<08Êà‹r†c€øÚ@3]àm/8ê/gƒ¿D€_ "ùwº¿£'B þCa04Ò Š D \.O8ð¶–6+„¢œ;B=}Ðøx¨á uÂ;üi ÔR5Bñóý= ƒðÂúˆù <OúÉš(gu4 Ga}¿ûÓ@`à0ü­‚þ¬Õ…öGáþ:» PÎ.¿GpöõY Þ¾p]¿=ð*Àt®p,P ËÈpo <æúÜ<Ð þÇù­Æ÷‚óB{]ð#ÀC.püçõƒ±_xîþ)  3†:Á](À²ãÕp—¿düæ1ˆà]0x ø÷çß';<¶œÑ(ÏÀÿ¸ÿY.HËZ[ÓØBøÏÀÿ6©©¡€8Qq ¨¸ˆ‹eð‡f1†"þîüŸX]” (÷W³ø[úWÃ~o_àobÿ™ËG,(ð€Û‚¥À0üäÿæBþoèþåÿðÿîGË×ÓóUà·ùÿ°B‘ÏÀ¿íx¼úbñØ7Dã€úoWKø_t5„;#|‘ÿmÕÅBñPE¹zþû>Zˆ¸³1 sû *é-~Ì‚£}¿ ( þ/žU0ü£áƒÇãOš–ÔDÁÐοÙ%.% „b0Ð@~ÅxI ˆƒàiè øƒ` H …ÆâC€øñB€.h à÷>%å€ ü³ô[ùGÆ×aýÑä‚ùb0xšý¾‹É8 ‡Àa€éI4ìÖ=÷×÷ÞW«rø‹®)Žñ¯Zf Šâ¦1-¾§4dé‚/s"ç1GªéýtŸ—5Uf¸/p›oÈbšRMšÏ‚ÏRLGW›S#ÌmªÖôpQpŠš«¬_x߉ð n$lÓãÏ÷ö•¥1.d<öï֨驘ý=¹j²öRZŸò¼â£h¢E‚mDé8ÓÓ VR¬(¹Ã^íøáÑCÞð%·^Š0 d+Q¢g³ žt2ôå¹¹¸O;› +ñ!ÇÑ8µ =–O¸²â¹¢q[ß’8‰ÏívÚ¡“K2 ˆÙWÊ}Ä××\nµQ6  D´c«f2ž­]ˆT†UyI­­ŸƒóúÂèvp“\ u¯yÚΟɨ¿y|uI:.\÷:»¢âáÍ4î=̃?n¥ní¶ŒªëÑ jnj-Ã7¡=. ä5¡Ä\žëˆòŽ<€~¸£UOÑ9…sªˆž}eí}6‘½a»HûB@Ð: ûG!ŠýZáX·ò1"÷Ûþ-Ÿ½·ˆ(öÝq;ÑæE}Zèà¡5e†Ð rz-i,˜l%mÕ²ÇÝš²“r1Áþ¾êµSBÖ îsÜZmB‹8½×ß$)¨UrÂè×ðþèI¸1ÕÕ2æ©äv/„GJƒ£ûîÄÞŠc{vm‡f¥… š|ç[­å¥»š‘˃ŽÙö†(ã~ó„)Ò¦’P¾Ý¯t/¨û}5œ™¢§$’LÈ2ÕØlÌ\}%©6rË:JšçGN~å%@¦8>.X-z¤Ë°Œéf7*ñsœo„Œ…¦nήš?¾,½Ê§Ë?té½ðÈX—·FÔ!uxãN€ÇMg@Ï–ÊÜÛñÙF›y=i·ðÝK3Šnª3ÕóCHåéÚx“ÑN“~MsL`x«í÷mÁ6agA8µãÊ!Ìø¥Z®‡½Ð…@qþ¸Îÿí‹ö“›¸.ȧvç!Ð@+LkºFÕm›ä2Í~±áäÏŠ›©üöe- ñ;í ,‚ ­ìO¿}ìé]˜ßÛFî6±¹4±‘]aà4M³:ÎÅÕ› @„G+&ŒIÞsFRéOr!_q¿*ÎÙ;Ÿ¢¶ÿÚ0é§Zó€Öø¥À]áǹµmU¯ JÔÿÃòMÞ3²¾Ó ¥€õΊ¶M©Q’¨´ƒÝëþcö_S©N˜¦º‹§üÒˆF%ED‹"áßߎ5‘+ƒLã–·2•“4j¼áÞôO+9ÉkD òËÈ4·w€|‡Ÿ³™“ …$Ðo«²"­Ç…Á8a#±Ó‹Úð¥áØØ›Šùõ½ºzgœ]»1ê<>^¨Èê|ñHNâTQó|ƽj“HòpÜÆè½8€àå¡~¨D“ò/Âæg;¼oò£Iä*ØoÞ¨^|bHC)òÙ¾éË¡µ“3Õ+~_ö¼: )ÝIªpÇ^ß“˜{(èÎÃÀŸUÏx4‹eiµéŽ ÖzVºë»[ÕbÝ[hÖ߯w™e9&ÛÚÓ²_>9.¶ËåƒöXÝ4VwO›Ñ&S… ä¬ùØœÎ*ê> ¤gíÒÐæ}ÚäÔYsýärNÛ%¬XA¸{]øc—*ñõåc‹ôYJÅ»4Ú_ìŠú¤ä^?© Ax•BÈÎòCyÞ·g{(èìrGáé¸Bót‡ØY—!Nv‡¡½”éíV¢ì»˜å¸WCéÇJ+•´Ü’7ȵ{”1ŶÁÒÙe4û áþ%¬)Ÿ»²Ô„1ãjɰõÙÜ|‰û~€ìÌ…ëožËƒq¾l€k]…#ª×ÈfÝCpÞ–öjå7Ÿ~¸`dµ.&èsC'-»M7š-*ø2œÌtS]meÚôpW×¥Ç>D¤ Þ,O¼Wœni˜ÉïÍÜLÅÕú¼TÜ@ÚFFD¦·ùÒ{Úk»õqO‘ªœm.pf&ûP4ŸJ_Mæ|Eâtjq“AèyÝM⊒éUå•ÕMT›j~#.'·ú1·HócH,.[ó(vKlÒ4i$ÉÖä1¿&ÀDàϘÝè)6<¡« nË›][´Õ$ˆg«Á.7ˆÞÌ“?>ôºØÄn~¡`ŸGoÓ*q¥¿ ™/ëÍŽÚ;*w5WŠeì`Gué³X5ÇZv(ãì"]zN×ï|«šH­œs—¹u€ö·ÿ8äÅñnm³¬•rˆFœ^ɯs:ÝΜ½û]~GçÅ[²qU+¢ÍÍæ´îËÒŸ®y µÞ¥l]5j•k“ï…ÜŸ5Ñ»ÑLê&ܤâ»Òª2#‹ygòWxyÕÂAÔ¶._W}õ`×2[hôóV÷ž¸¥%úØ!‰Ò¤¨¶×…x0;Çõm ·lew¥|CwVïÊs k«‡Ë¼Öæ1¢ŒŒ±‡mÆØd!Ù2U±*fÃÁ[GÃyÈYaÅêŠ;ÝŒ:¤–ùÆ# ûÁgDù^ÈÇ`žæâV g™õºO­l}wïXå•`[^j½o ÁLÔ6Z‡æ½au™©m™à¿ÚuÄ}x_ÛpÁ$t\1Éx`WcØ“`åÀ€ÞÜ«×ú—Þò[¬lÎä©üÎ<{ê×å²yù‰SàPen~ÝÆ€­”¼œ•Å(Ð=žÈ4{Þ•×n—ÈÒ»6gצ¡,e¹9üIÇjl,_øéÆn Onùækw^áÞ¥Þ>ÛÇ“¸ÔÁ´°ÀôõŠt»‘ÚÛÇ%ì³þšðG^äwÎ~œ_ŸëÚÙ8?_Ï×Ö¢[לïèñ©Tï>¸ÖÍ’@)ô­Œ½5;Ðù‚ŽžJ?vøú~á ¸jcSâ˜ØÛ$SL«ÊËJ5£@+ä蔥Z =]H‚¥Òø˜xÐítï5’ÒÒ0ïꨢž\àý_ÝþÐþÏÜ|¥J>kdsÛ‡E¤WÀÕÖ*e'M}eR§åtõ8Ý–¤)"%ÆWÖ#_£GÔß|ÙŠâVWlW;QÞ)zÛÁcK_ èpuè ­;ûé-¦ D¡? gšKßB([Å;}Œúr‚ý ÏmÿEÌJ4>sYo0 ݼ‘jàl3r mù#›^lS²4)Jl§ÙžP¨x„«†y@c:x×F¹fûžÌ½$KÈá *!j ãeÈ€»ÝIÜe^+ãqzþÒo”¸¾3i°ç);\îbGЃ?ôãÓ“ âoÂ*âë¹ç(>sÎÇä?@²2™‘*1uˆ>M˜â NI¢º6´t×B¼:Sø ÝñP«¢‚®B»qî½ï¹3ùEKxÀ_‚ñK^抠©-/WCÉI¡\±Oäw«8ž×¼NK´þĸ\A´V¸Ñ ‚Ewò›ÙïòMâÇS°Gœ'âŸÌgP¡;bÛ•QÀ{méÁ=×÷Xç“~y ¼ÐºDP˲B¹çœÖ'ŠXÜéê®ìVKîƒÝZ&Ó=ß½'ö[vodÄy£_´Åì=È0­Ö›i27KU¥ßÎÙµx/¯Œ~áMUCgiKûëýÕï«ÜyÞñD%,,Æóï± ‡WÝ—k;{MEü^Ê< Õt"ˆìYk²‘bRd?TêÊ>É${¼×3™Ãt\Ä{µÙÍŒÁTµfKI¼{Ž4Šüö„²'-÷œí¨Æ·ÛÑ1‡¾‡Ä’!ܳ½¹¼åTÅŽFm±§`£J²HºfõÕçÓj KŠ•®›ú·i  ShËõíë1㩎z/>±É‰Åôš ”BÈÜÉJ¾{¢2 j~:žºœ 3‡WD²¾˜ ¬ðmŽ×{åî¯1Ì ‘ÛëÓ··”1¸$¨ýØæ¡³!‹é cÙR%0÷’:߯ü:º|‘ªå^4ĵËÕXÿÑéû•:ß Šº³¥;ÎhóF‡JM¾èÒhà(ƒúf„Ó7šº¡‡É¬‚¥¼¾¿àE_È6„ é¤=!¤—×Bâ(„Ù¼©‡Ðé¥ ‚¹nERÕ 9òñ›“êN6 2¹’_q¨|=•Æ9ŸÑÄõÔèÅÁ©kô^LuЉë¶ÛíÜ#n­„ƒ™f&â/WÑÔ¾6³†­$~ê¯ Ì£Ñ#Ì¢–¸{—‹åuŠ=“þGb# >=¦‹¢\±ö‘ê¹/. ‚’~¥ÎeÜÉsmZ¤ Ó™[{w·÷Z§ ~íÇ ·¢p[¬¡<7ã?§as›ƒ¬:®‹YßgA‹Ôh'ß {!‡¤“зYÛ/Ì»|,È6nFd·ÈjêxߨjK«)×q÷ô‚.áö×™n”ŸÇ9”o gÒL«¶vè”t옇Ñî麵j÷#›Ò«¼€3^Œ4×åê±"ÐrØli ÙÔ£Œ‰ç…3îþË€ókbôgÓƒRk”°‹…ÈÁ™-Ïu_‹2–)¾KÔ3 &åCÉ)!’1ôJ6µ6Î~Û…ef‹¾R%à|Ä*\-¼Õ¼JÕ— é#^8ÚUVWÝsª½J`uÿ ½T>&gb°^pÅj¬å¨‘dK’{uÉægÊkÁçe½"KîÆÐøm¨äi¾{£Ò·P¾_ˆø)æ‰ïŽè E¼bVY-F] åã:Áqto/gÐuìxõº¼B3hFÁéõP%”òG`Ðṫ0ÃküœË á§ã³ -ÉÔähÅFéçèWeÏYöOžMÐTq¹Œ:¤&[ov€­tÊù%«… guˆ±þÛ¬À‘„Žä!'žá?ºgÞBCÕŠ.ì`)(œp.ËiøG:¸«ìI4ú¡.#dŽdÙ–™ŽØ­‘ÂbÔ¢X‡p »üaš®A¤Éäyb›àF˜ÑÐPÙ,ór…¾%¸[â°L-äx»”\^ê-eœáVî“å”àãU£f‹ÞŸI›×yç©M>¶ÐªWgäê¶C×Ð?)Á¹$ñK|úFTop€\NSìö„ܳE²}Ô8¹Öé ‹> È…9JÊ*~¨|î"çU†”M•¢³êcu%úF—%¶®í\¸Aó œ›]Uoý*¿$…ÂìHh™çØ$£ƒøÀvše­{E³³áí®6î‚øU³Y$¼œ£“§«ežrX±IX!—ûáÒï|?Fyžj5½`ÍeBªÒEd—}ø†ÍXÜ­ôÉr3RÐê»ßl[ª5 ÿœxZ¸=õJ?g^®Á ¢ƒ1¡Jˆ©Ò±I4B.üЏc?3{—µÊ½gäìÎþK¬mÂÏw#ûÚízQ.žl[«­›ª÷]\” Rêt|åÒKž®É­éuB’» !Æ,Îe>ÃŽÊ’_È%g>²šÔ2>p |mÒS ý|^K-À±ã/kûõ±­Uî²j_[v˜d¶ã»—ÛÁ©~ÑËQ3â6Á‡”¹÷óœ[¤IÄd´š<Ô×@ )=)çì5VxŽv׫¸Sö(ïȪŒÆpîE¿HsŽùöù\£Þá`Û~âwdÑpu‡-¥.F>«CY˜Ú~ÃMUq*ÏäÚk£w Óš‡¨¼’Ó–dÈ™ZõÚ×Ç,#9 Ÿž¬w®‹ÒŽ‘kz¸¯ o~F¢_vzððP³ê¾ÜXÞ­ ¤õlùzh°‘†×‹LsNsiþïg#:0ºó¬{Å~D^ÎŒíU P] ÜÄY,gÊu7û]¡D×höUrz²b;…@îü¥}M墄Ó.¿» _…¡sÝŸ¬À¦Oêã÷–°ëË=yñôQ£ûÞô$ƒŸ%³“ù ew¬ýj:ßéÔ‘6²˜#Ù´1”ÂÊ+Ë¥ûW”–|p{7ê«ÊU¨­‚è©VÎ^ó®0èèkð'øÙ„ZÞNT¾C.Ñ#AlD©u,"Gn„,p—‡Š§¹ƒ|ωÍÜÌÀMÿ’0àf—y¸îšó´·&óí¦)‰£‰¾ì+nÛã½™ôp°Ûaþ+`¸BÕ¥,SÁ}êÀ¨©w¹ØÛ·Æó'[Ñö/z!s÷lïóÐU«·j9íþð44! JãnX*ØÓ}IP-ÛàâGU):=´@Ä?“[|;bLÍüÎ#òYkáv/½3À|ÿk¤W«›DtY¿õý h¡Õ—¼N’Z!3kƒ&5c‡»‘:–$j Ý&®.k@ǽVÎPú²¤­»f‰‚Hˆ½–)~ùÊ¥ì ¶€÷ S½«¾#^öÝ­*y}ýG$—èD® …B*¼^tÞ7JÁ5»äk†Çª¸å/¸Òˆq9:óôÔF1°–=ÇP.­ÒO±û`š$¥ØÌD»,˜úéXž-\:~Ð⥙_mKÆ BôCL1+4:JJù9Êùl7ù"P~g)¢8{ånÈ2¶Éž½˜ñ Nâ‘õŠ4'ÚÈÂøB‚¼‰6R¯M¿ÕîT±.XJ¼Vs09L,ųòƒhnðWý'×qûG.Y›‚í,‘DÍæ¹ÝŸªoà·Š;¸óBËôÂÃ޵=ûôÄ!á &Ãm¨ØeE4†íE³¬¼†„1RTmÐw$u»[3x÷Ÿºtˆ®GBˆ<vMSãŸìß¹R´.ѱ¿ì$CDE%~zßKg·ð?Ç1P endstream endobj 90 0 obj << /Length1 1373 /Length2 6093 /Length3 0 /Length 7034 /Filter /FlateDecode >> stream xÚtTÔíÖ/]Ò%È€Ò9H#ÒÝ)Ò 00ÌÀÌÐ-Ý-J#¼tJK·€¤€ €(Ýߨï9ç{ϽkÝ»f­ÿ<»÷~öï÷°±èðÉÙÁmÀÊpŠÈ/( PÐÒ >â"bc3„  à?Z"6c0 Ã$ÿ—]¡Ð:E í¦‡ÔÝ¡à#PT(&)(”ø—#! Py@ìZüu8 Œ$bS€»z# Ž(t•œ¶\ „„ïïp€œ ±ÁZ ”#Ø]ÑÀm!`”÷?Rp>vD¡\%<==ùA.H~8Âá /À‚r胑`„Øðk\€6Èü{0~"6€¡#ùGm·Gy‚`Z…Ø‚aHt€;ÌŒ k Ô4:®`ØgÍ?¼€¿¯äþ;ÝßÑ¿A`¿ƒA¶¶pWÌsØC `€Ž²&?Ê Å Áì~9‚ H8:ä‚@A6h‡ßƒÊrzz¾¿§CÚ" ®($?ý5¡À¯4èKV‚Ù)À]\À0’èWŠØ}ëÞ¿×ê ƒ{Â|ÿœí!0;û_#ع» Á nî`5Å¿=Ð*¢ÿèÀ(€ˆ   ˜v€½l~%7ôvÿ6þV£û÷÷u…»ìÑ#€ý!ö`ô‘/ä î`ßÿmø§Dì ¶(€ Ø#úOv´lÿGFoñ˜ ¢þúýûdÆ–õþûïå èšè¨*éóüøß&yy¸À—ï‘(€OHDˆ¡þÿÌ¢ ‚üÝ…àbÕ`öp€ÄŸfÑ·ô¯†=þÞ>çßÄàü3—6X0€ó?7´E€ÿß0ÿòC÷¯,ÿ€ÿw?ÊîPèo+ç/óÿa¹@ ÞÛÑxuG¡±¯G3öß®OÁ誶ƒ¸»ü·U Bs@æý÷%BÊ/°.eëø*ôF¿…ÀÀºp$ä׃à þ— Í*[gô£Dãñ· Œ&Í?K*Áláv¿Ø%$" ! o"ôŠÑ’Àˆ¦¡Øë7‚ü08 @ç°‡#ˆ~íSX €~–~)Ëè:(Oøoù…lÝ4Í~ÝÅ¿äßœƒ½À¶Dó³p[©P§šÐÖ³j9O¾ÍQé)¶Í§\|¾óˆ6÷ Rü4®ªœç+ˆ¹´Á÷äŸ>+qË.0_û~kªÃhNÑk¹ô»²JÒŸØl!ú8NÛ7öú›\m/!#Ÿ¡ì–ßµ›Ÿq°3vf‡:[¾›»8©nÕ™gŠWmoÙâpøì¦ÞV•¨Æ«²I¾8£Xóàâi¶W6¹3t¬x(>&nÊ/²éã“)Ê—c·ÌêICÛ6²æ’ „nsúljëŸ!v~Z²³IrÒÓ `S«ÅÄ®4«&»³$ã ç|R_ñRû)ÖdƒäÕI†Üê@ÅjH­z&j3Ú¢R[iïuÓƒrÓë+ýQ”^u¼jêÑzžaäí~(·ÀûIt)ýi/ ¬ž9“æK®ê:*¥J(9Ì镤+ ;x™z«™Éð³$ÎàLi³ÌÐR8˜Î€ç§ÛíšF«m«CÓø¶Rn¤øøø|µqßçnV.CǤ¢1K 2/¬tœúŸ½Óx;‘\<ª+1RŸ]0Þsß•ùòD5§5b˜M;®EJœÃæp@*δ;­3Ŧßn•IJû°²ñ ù(rD>IEæ7ô,¯…(sA%ýïßV=Ú0!JÂ%aÒò8Ã.aSÑ>hŸë½Ë;YÔ&`=uÊš½‹­ŽKž¨#ôH|!‚ˆå³PSyn»Ñf/¶1T4üShnä^ÒB¡¿!€ôæKIi·ì!!» 5íJ-¥¸#Q(ͼ¯¨N„qE3¨Æ“#GZ§éH“ÎÖáLwýÝW$‰wÊCÙ>4läÏËÎ(BÁ~ב:éS6û!Uôí/¿~5&,Ö YO¶ljì ŸŽhyÌ¥UÙþù1–Ë N\‰Ôð—IŒÉd•þ:v@ SƒQê/÷]tCìG„«§›¹˜2üµ¢²u‹·„Æk @‡¸áuåãÑ,ÒïË®$éÆ þ?c}ë‹›QÐ0Š@Ôuž•=™Á¦4‰¦4mg z¸{² Iþ.†¹ÐD‡¿mš‡ÅXº6¶WDöšÏ(L±kÂEëÑhÝni(Áî9}d{aÓz •1ùþ,¢ôŨ™¼eæÕ(ùËÇ»­ëõ3ü–ÏØße,†3&—$O^“œu·´'5oU‰;µûЫM-î(¤³Á[¦®Êã³t`â ?õ¼Rl}1Ä7N.”Ä©Î2tè7?ÑE ’“R¼=³—ózÕYb¡f6„úì]pâºD`@‚‡—Ïæ‘g“ÄÓÄ31,ÿܹ¯‹Rнo>3k…MŒonF¦Jïy_º^t¢æ.ã£~X]¥ —|‰N"K’#¾Ð²àMëd Cæb.ך¯Êº"&zФ–˜“ ¹B#ó#ŸÁ€î¯]íÌö‡ö Î]¸,PýÝ ŸA1±V^a”­ÛV÷ÞÃ36û~‰—¢jzwªQu‰0÷<~ÕšèζoU“¥Lby§[ºp#i›:m:w \!ܾ-ƒon±¡£VÿIëz´6Ö(Jöh¨¿çqS„¢îŠnuß§pk#Eq",ƒ“êì_õU’Ž@i CF)(¬ýØ–Xšâ°ka›ÉæD5l¼ÚÍPÓBÏ<¨ˆZn8ûl¢o²Gk$åX+>- ^ÎüÒK³¹=&j2À}ð¾EH‹ÕÄÄÂLj‰qþÁ2Ù©†ûY 1ýð3̾<µ‡ fŸžñª†GS¾iïU[x"”5OÌõ-ÿª¹ôíÝŽ7u½>1^±¢E.)a´ø&'ÊÆÑ©' J:^êáDNÊ.E¡Ž\ô&ƒmدgÆ#bÄëCú™bv^ø~vÇï&‰ ³-äÞ”*Ë,Øl®ôc@+nüNG)d_÷LðQ0:}“³_—ø«ÝøÊæèU-!¥8–áå¢]0ËŽqksƸæmê1mÊ 6.š Ç‘$2ÅZÚ{Ú«òïÜãvZG°³ß7Ym&‚ÐŒðw#0<ðpqR˜Ý,·Ñê¡”tÈ[ÛëêŽ8!ì1ÖùF Ýú’²PFv¿òß„·Ë)ŸðïМ;öaÊ'^O/HãÚÊÛþŠsE6š°Ä‰ºñ%„j‘qìS]¿êMXXaö÷ñ6#½ÿR3(LÇÉîÉ9£4¾eµÜsÛ|”£ôÁÃ/3“§ÀÐr_ㄯÀY&öÇà÷¬©dþ5);_®™5WyÇ»<ÂÛ îF„w¸kÊ·±Ö$/\RÞH=fbC>ÇÂGôf}PÜ${„Ç•]øÄ)“fƒ¾þDDzøî¡«Gœb˜ez"uO>slÖ"É‘×ÃŒ¿öxì¡G^ÉIô¯¶Äºª¤×é¢O4Z >áÕA‹[’ô“Ì0…¢å¡OÌT_»…èqûš­·"2ŸW¯Àn´gÛø]ÇŸÄÕ­œTw ÚΧRæõ”ÜíÙ¼Þosº°`bÊßá´A¸=s£wÇ´-WerèŸïÁ {í*–ŸRP)ùN{^OŽÆ³u/|fæYÚàïzΜ~4ãï­N †NÅA)ÆçlðV#¡x–ŠÝbg&G=™„ÃWe\[Ñiìê¯î3SSMñ®ö/:Xаî*»s|å^4ÉâŽO€”A#~Øk§R¥ûº™2Vq`Ëö¯ÚáœÁ L¾×¬=ŠG˜·½Y„³Â¨EÃg dw%²nMü…ÁzÄÐ.+1ÙT SF£žÒv7r¶ÍÜãT¥r]æÂLRÚS¾uxÌ·{¯®pDŽ+6:5«ºæ¥YŒEøï´çú#05Ö.™h߸=ß0ÈÄææÐ¿Î# ’lD)cZùëóÑíÓÍ“_g)'IÿXg’â6}ٺܕM®Ÿ)ÅÏ)òÊ=ÜŒfLŸÝ#C¯¦»—~ì}wiZÄ'Iæü*屨†{lÖ¼.´åµ¼]ò-ƒÕu$#]ë ôpdi+±ðÂt}æ%-Þ®J=·œÆ­?³ _ý(ïUª³û€¼wÍž²êR ê®&è›ÍÍx@êfTfÖã;;Om˜«-¸ôâ(æœìaø C®ŽÁ䛨ÊL©QóÄO±'â’_y}#kj¤¯±ÕÉ”B„Ìž¾UlöUìûÔÂ$ÑuÂÀ¡´œw:¾yùx4tJ—œ€ñãªðÎõŽñ¦ÑlRB‘7Z—ž+«Ýª®&¨2†Y'cœdyä´§}+Ý”f›âmycj„'DUzkÉŸÃXÚ Ü½=XEÞ-*úÍbà¾7xº2ŠªçGÂ>[Ò<Ð9ÕЬOgûÈ™}ªu^=?ŸXØe”äÐìc§YÊ€£ß¨S•ÈÆÊ0‘„zý@\Óýã™Ù)"ÁJÒ™Ï/~nÐwY1zÂÖ:|wZõäpaØÅ¥M*)jª/b-ð•HΫI“à½Æ¹· ›A­Â’œCæŸ _?cÆG>î¨Ío\}Ñ­Ý$³J¤õr€xd‡£úƒU=_–!;Ž‹‚¹‡ëÓY™H}U¦Õ,½ Å-¿»œöÐÝ÷ Âo'P²WÛoܳ ¶¬Ÿ­LÓ´|»] :„ö¸­Ut&¼UþþZlŒ·Â¥ë³Rñ×FQ‰'iSW%bªá÷äÒgèÚÀG•¾ŸÇßæÇÉO iòºêž¦,CG_Þ±wÈ“R»i[éJ“)`Í\”ŸšRô¯!ÖÜÕzB¤´ÄÛ+l[4Ûå·CtÏ?‰4’wSúâK5uýˆƾÐÕ>Vkô¥åæ¾åÓS#9c±·^z`šûJêÃö"˜úBÅÄNÙËý¤uÓ0Y,e²é,5v;¿æ4ôƒfc>ج]™kXp¦8ÎÚúHýxŽ>:4„¤"¨9 Pá6!€KÞ@›¼üHf.¡/+ w–Šê52±:·'Á Ðß8GŒ'ù’ôâ0ØcŒ@|#bÉyíSé–º—öü½Òb¦?ýC(ûsêvò,l_}c™u (‹“ñg§&·1yÑè6QŠyt›Ê+Éåz4áüÒTt¦HéH¬ Va“GR#iúkTÊ»µó¥e;m‡2 ÊhóÛ v2ÆÈ\pIê_»‹c˽‹!@ïõڻ˛xåÔ‘ÃÁžm Pܽ­²ŠwyÃn@å.=û| ÎjoKLš„yÚ÷¯²ï[³¿0c-lröF2Ö[Æf1*1áŒ×^³5¾ã$¶W÷‰þlyÿNvGZm ÖA‰> Nh$!ÚJÛR°ÿŒ’t6Ü´ñÕѵ)cÈÔ„C˜]7¡‘Ä”Àg¿WGSÆcm†V”´Kì÷ZeWІI3/}¨FUæTÖ¼ú·‰°¢Xkꋪ”Oá¸%µy¹“âªî~Ù‡³½Öî©@5ÛdÇr²joS© Xæ¯z_yecvФ¾%^œFw ÆÍÊ΂4:š[AyÇþð‡¯Êù~Q‚Œ5´üewWH¬»ŸG¸)]3þYgwžùI©R!©&üÀy›ÿ:²gB;!Ž]Ö“|Ò +Vâ\8t\÷âGuøÀÄX mz}šmNvà¤-ïN?Œø(³³½mŸ•‰ûø¦Û‡šS›3o´û² ;Óz?‹“¯¥lÒéÅ…èt ·Â`VÉŠen"µ êá„e›þÔ­ý$c¦a~ìf·6UøÌsÿ„<«®î °/„G¶l#ÄÚ¿hÆãÜÓD¸;¥‘M2Îs…lFòp^b*U¦ yµRöªÙ69àå Ãü¾}úÉ$Ü“lŠ•ô¼£µíF_7(çuûº"ŠœðR•%‡k—íïáš9÷µy:t5×¼I b‹¹K»cºñ`U¦ÕÿîG̃í ܾÈ#-¥EKqêi„úDärí&"V”i¥J|YÏ‚¯c9(²C"UÔ)ºÒ7Ý£6”›éÂ×ç%{ˆ5µø!9iÖ!„ÑE«Í˜ 0oó"ƒ§²Ø’]À3{V¾£p÷_Í}ûö vß ÚJšªø—ô vÔ|Ó'n`ô#™u‰ÒA„ÈäAUÊcï¿ÌmŒͰw!ºí}¦º¢>ñ ù“ª_‚·!1+m¯¼Þú%žôÐO=XŒ×ûÀX%cpW/ú¬ð³¨QÔåÀú§jœpAežÀÀRßQ}ÚzsÔJ¨rKC¯­ˆŒÜì±y­¦3PE5¾ÄõÑìä,('vú\ÌW`6ôÎ8cZ >,ç“îãÙî.hAåQ «Áö‰¥Pœ†g„Çô¹œ”Úòä¼t}h÷=,°J‰ÿ\Ï"aÈü.hRóÅ;¥LRÈŠXkã:‡¯2£Ðµ÷#Ù[Ï\“˜‹Áe›C‰³ÝQiV[Ù¶--òdÃüÛwá˜ò·ŒQ+Bƒ¬ß•¼^ÖȩԼUâ–ßq)eüäy§`É–w°Ú‘÷åãö-^l7<÷W4E„óÓ¼/w:ô1âħ ãÃxÆñœÊØÚúÖf/ç¶»n›/Õ«sƒ;kžW“uo~8¥ßÄ?UÝMlý ÂÀ/í˜DÃ"fv2kÊÄ/ï¡!"ì0RÅ¡”zºqR´²t./A,êð>f@Æî¿7¬¬™-‚ú›lç¶ÈH©öW­0éêp+ ³YMàëyGQñ‚y€m˜!ü—ƒ¥FFÍ 2 J²Øîâõ¾ÖcÆßX>Üc3V<,ªˆ‰oΦ ŸÜjòÞc‰”¤-v²æ/enHûÊy.QóiýÊŽ¥8UP*!á…€fOÌá“nðu»x‹\'xÒ>|\å·åõvLgEO¡~° ͙Ÿ•”T'³Í  ·¤“¡ÉCÔMk?¾n&º_~5*õ^•o‡5$¼×ЎʽÒaºŒÍ]-áæM'}ë6–q„ë‹x‡Ê,ezä÷4šÞÈrÔíótºxgˆlÈÞ—tÍ›¤é=Ø!pk1²ö!Z%xu@Ï.;R§’ ‰Í¿9“Æ­¾s°p ÿÖÕñŒ§L£o1;8!Z¹»æÓ#Ðà£ïxnáÛí–xôž½îŽecåtÝÔk->ÉgÕ×ëÜ)6pzE ñ~ÙÚFš©˜” “åu`ø2Ù¬ÅoÁj™r§úVS‡™ýè×8tl®-ÇÔ©\–5\¯KF ÅPøÃ‘´…4ˆðAðõMÚ7=¾G6ç²}S›é±[ÛC]IT"2VÕ´V.^ÂÛ¡ü¿ù•á9™¼ xW_õ´-]†õ`˜´ Œå=¾ÚʯÒ1AD3½M®&Ä«^?ûö¨¶-¿~){ü˜å?µg>åcAM]ä½þQÕ?³a|ï&Ç_5¸þjzh­–g4D¾\­%¤&ÃJ=^Dt[)þÀ¸Š‹ºN´–´Ù>§•E˜T mÜM–ø$m÷}¾¹'Ý…”{ªÈMË0£†Ÿû}C4C$Më'{@Í–LÔÈ B¥N5S7ø‹ÔRÛØ*ñ³³™9?¬ÅÖùzi…Zr«¸ï. ä8$xªîî7ä{ƒõHöH=æ5=ÛŠsè]¯Îvê›Ã Ï)ö~ÍYÓN8?S 7 ù-§) Ê©b ?øñ‘I#C›¥¼Ïûâ>u…ú”"ÎóžÐ‰¦ì*‹m…9¹ô–å[OQä¾Eæ >Ow›mûXêÖ3z`¨ø±ÐŒû%Á}Œ†]Òn‚·âök•ó«;1¯ú÷òŒÎE»qò*Ë-ï» IuûF½%JçzÁ{¡rAÕë”çdEìÚ«gJ. Ò–ë`^]ÔÒe|lšw3`(ö=y'¬ÅêÇ!Õ£á°Íg'ç8¦‰¶ò •Ы¹ôÍ|[qM…¦`Å e•°ö#Á&þÈ"¿VÆUÀp[Ý&ö(DÏ$•_éaˆ§’1vy”$–£Ïÿê³ç endstream endobj 92 0 obj << /Length1 1379 /Length2 5903 /Length3 0 /Length 6850 /Filter /FlateDecode >> stream xÚxTSÛº5"½wÒkÒ¥÷Þ›H !@H„R¥IoÒ¤)ÒQª€té Ò¤+"è‹Ͻ÷Üÿ㽑1’½¾o~m­9÷Þ#ÜF¦ÂÊN(G¨ ‰‰eªú¦Ö ň¹¹Íàôo;1·Ô G!eÿ¡ê c°650 ÔG!:^H’”IÉ1 Pæo ÊS ö†;ôE:($MÌ­Šòðó„;»`°uþ¾ðAø )¡ßáew¨'FôÁ¨;¶"Œ˜¢ p(Æï)øî¸`0²¢¢>>>"`w´ÊÓY_àǸL h¨§7Ô ðkd€Øúg4bn€™ ý—ÃÃø€=¡¬‡@‘hlˆÒ ê ÀV˜jë = È¿Àz„6ý+ÝŸè_‰àÈßÁ`åîFúÁ‘Îjè‰`|1B0ÒéŒ@£°ñ`o0vÄ~·h(ÀØ ÿ̇†xÂ=0h4ñkFÑ_i°Û¬ŽtRE¹»C‘4ñ¯þÔàžPvßýDÿ®åƒ ø{ƒ#`¿Æpòò5GÂï{AµÕþ`°&âÛœ¡€PFRR€Þ@}!.¢¿ ˜ùy@;›±3x <0ìÐ 8 Šý!@ƒ½¡Œ§4(à?ÿ\ƒ@'8p„:ÑÄÿÎŽ5Ca­±çï ÷رô€¿>ÿº²Å2Ì …DøýþûˆE­Ôt,5TÿŒü/§Š Ê ,&–‘@ $@JJôÏþ#V Cdþj»O·ìý‡|Âøg.–¹Pß¿‰~(„`¿@ÿgºÿùÿ±üW–ÿ•èÿÝ‘†ñÛÏ÷àÿñƒÝá¿?,s½0X裰Z@þ7Ôú—tõ¡Np/÷ÿöjcÀX5(#±ŒÝÞþËGkÀ}¡NFp Äå/Öüe7ÿ¥7 5B¡á¿î0Ø( ð¿|X‘Aܰw4–š¿]P¬†þYW A9ý›˜„$ìé ö#Æž5v%aUéõýMf€¨…Á†°3`(Oâ_ JDÁž¿¬ÄÿÈ ñòôÄÊì7°eÿ^ÿÖ4ê …/Ì¢ r®Ï#:Îë”™}„7G VV»b’¬û£%0æ{ïUnèr†VG½]åP¸pèÛñ+g(›ŠÉy\êqÌ:åçdcVr|ÞTËÙˇR=â[Ï>_u¡·îÊìÜ¥§̘xåü®=ÜGÖ\«˜aë{ Tž6™^fÚæãW¸à g*qŒßüÖm²†ß¿;ÐÿXü¨H··V²&’š‘Æ_‡#$e‘69Wç‡GEâTµ"=‰“±Ä=’gÏAjùûtÑ@{ò ¸W“³jèMÃoš½P³òù=ËG,ö9fßDIZRb\„ês©p×:áœg~®GôâÓ±º–~êO£ÊÊϬõp›ã„‹Û}œ`8wˆÏN‰Ù¦Ë#¤?³Z˜~+A´õ핲ãÈÊ"ëÄ™7EVFê‡zWbëöb­7kZ+PZéÄ zß)Fš¡]Þî/ÆÀvéùé…¥;«I¶zÚQéAVkâ4îÉwž´õL»ÆOº{Áz”¸&. glùŽ_Jkƃ£¤ªç¶€Ò’¥>¢oØ *\6Ϋ¿wÀÞt†Pd,Gs~ª± 6©þh[é¹Añ^¡[i84•À¡}3îùôóï[ _M(Øc¦-岺ß|ÉôRâ»U‰xSF=}ÓüIn@àúׯÆA`ñMr^z×±´/~53añ&EËR¹¼§fM®cÑbyâ©jÛ0M¸ªáñ’w[þ~ŠbOC»\Zn½üÈ;¡ˆõ²ª®{œUßšÓ³é'M®{›¨¦Ï—à竹3’M+Ù åÒä’wºQÑÅ;Â[ÊÚçFv¸• Y> ÙÔ¥NÚCZþn|3ñpßïIl±C¡û¦ÃæFÚ °Ý±ŠQ4ÓC’O£Öµ…¢ûÞ¯Çm [¿Ï³µèq*íei…G¦RÝY6âMÐy:²ì<#4ÀÕÈéb^¦¯xÒ°§¸šê!0!åM6G/¿dB­k’§*¤HØŠ§Ç˜m6HÃÚ"L~Æ¥Qá­†ü¤Õ@©éSÜdoDh’_¤˜ø?¥>>†íDMØQª¹¼;¹³Q•µ¦’>²;tñr`!-ãU=ö[^«³|6ýLÉÂ&Zd’ºÏÎøñšnôåm7CyúƒUJ³æ€”òw¡÷F(õGËôÝpßf IÝdzYä Ø?»x16¿=}Õf7Çõ‚'nóøÈ–R‘ž¸ñÝÊñJ4imÍŽ?›Ãl³/LzŒ»Zýia¢a•.´Ó”³P.q;ýÒËÇ4†XYâ(KREžr©È¹”e¶NT“•X?ÞÁùpò¬‚ÚV”`T88( zr`H©`:CðK6œìÚU<æZZoœþ0PIjP†óÙ…ý­rç0€Ó:·jPL¶±Ym±¸16Þ ®È¶=ÙVœ"Á=8rÄ"R3]($“F{÷Ø—˜ì¼iI2Øáp{œÝx•Ä|Öê)yÖñJ®¤ánÆv÷À†÷<›Œ‰e]“VŠŸ‡“ÚÐÜ: Õ•ñ”;!{ha[ý>ÇÑ_SU‘“;,ú¾Ä‡c»>cT2~¤ÄÄh›ëã‹VÙŸoù‡:ÔoÍo—8ñV÷nv3 ·6“¼ÃeîpIŠZèfŽ›GOâ>ò°öî%S_‘™ôøË“…xÈÈqÓ8Šf·:6GO«äm›î»“ãæ|þ̯„÷óç– Ö~éý£í%9׈©íõßÄ]9+5©,®˜yOrÇë'N+0¦åCÅäNŠïë­hñ©ù­Ãö¹X6Y¿<И¿³­Ô±ãÖ°ÔK¸brÀ·83n'6ÏMÄU¾¼Úwhlj#ßAº‡£¦_ïWÜf4Þl£­‰(ôË£LM\ôf§ú,ø ©¸€­/M½ ’ðöù^ŠþÀÞœhÍ)+Ýfþ!Þ¥4;rÁHµqÇÛàÓ§¦dIé>é'‚|Û&P¡2}Ò˸4ÁÀ­:¾V‹™/+±šåÕ©0]³%ÿ²gýüwMÎÞÊÛ#‘Vú€R¾n†ÞôúÈÏŒþ¢ïšü§ôzïF¶Æ¨]c¸-Lþm¨~àÑËt×ô¢åXyp5ªš(ºáõ*ã|‹òFZë«N ¢«~LëªÐÇ,Ô=¦_ÄúÐ(F ñ Z‘X +íÂñq[Œb`;×ñK•'Â9ã'z?‡qYç„6VõZ(»©¨bü·¤ú»Kœ~ºú™eLJö6Y¸~|¼Êx¿ì³ê0còqòçù—mÙ×dü¯·ošE«.‹öa´%÷gF^/C± <–‰ðŸÑ~Tˆr­5?Ð=¥öu-l¹!D0z.誛}þ…¤W;¡¦÷Ùø.žxèY³‘0uÒqÔÉ{gºs…*¼='‹+ P—¸õØ)êK1*!#ÀVµRëžÆ gމh§¨6œéë®±o… ¾‡Œ–ŒÖ Ž¤ûu}ŒßÇ{ä €ì¨ÉÂDfc£óÆzöêIô,bœ¼þyyîNJƒ‘ÚrÓì‹p–:$µWØ?3~g fÚðxyÚŸÀ6LHˆNÁ•ð± OÄc™}Æÿå#K‘YáNé©H· È­ªêM¬ëûàª""f$П¾Róë*ûý˜‰{à Kãnÿˆiç­óVÅLE=âm?`_×Süé[1ý6©·ŠYÃÕn©¿ Kñð¨Õ¨*ÿZ¿œéýÙÓpÚi )…¼YL9…“ ¨eÞ·’ýÚµ¥0Ø‘-+0º¬Ç çí•Iá§¸Ê ²ж£nðO,*§8÷Öé ì†Zéöà.Y4óú/Ü=~£ÌºÈùétüfÃŒYGeoVÒ’ÞØ ™ÎÞç£;5xù•Mé¡,úNÞ»±Ž/4ËæQ98·¾IXDìÁ&Ícwï…]NÊÿŒËƾÏôHõl£³e¾”±%ml¦ ³ :{(‡Õ ½’t­“ T “Êù:C’ò9£¶éñ< E°ÈލF93óPë°(c’»Ú‹+ÂÉâ%qabì&3 yݘu÷8ú¤…jTª«_Ëýi¸«<,^¶fL»Ó­Âfqò€ëPF½¨.ÉUžø‘­" j;/Àçz­=¹„øY‰Æ'çéî†Ûy*YÛ9ûÊåUT«÷Ÿ޳¯¼\ž¼ÝDËUœ4ñ ôÌÆðöFõ±Ð¬iäÉzÇu–'žÅe6Éï_y;| éhªÿOÒì{¦Éõ³€9¢dw\$¨°uìæ›´åôïÆ»4F³Ò uõÙÉaò 5¯`ôרF:+ED·|úbL¤Ûø”eû“BZ:•z x´Ý翪`ÅñÚ=úeXi AGfù“sÊBUkûò ]`\Í¢ᢵXÝraÂäžú»q¹¹qÙÞÞ«¥Å?„ÀZ /j)ÚUñ-3”ŽFŽ¿‹ç>ö`G×>I5þ˜ƒï¸ZN+êq|­éø ‹Yêý.Ii|û3Ê”)ÝÈ=jã·„?‹ÜuxüåîÌt焺­ÛÀ¥ÞŒÓ5îå>ýÂ+@wuß*Äìòs‡y&ÎíH”H±BÌ‘?dvÒZ{¾ºVtîw‹o½Ö{1 ’™¢Œ£Ã˜-Wȃ^ñm=m©T VÏx>ú¬¾òÙ3¹èl¨Ëoü”ë‚ë¹< Ó‡°¹\Å]'%q?…­x%SÙî Ë ·€~K/SÖNI¾œªÓÓÕÌëCžŒu ׫ J&ŠîhÈC4+&ý@“÷lMõ^F›?~ ÿ)Á\{ölÊ"þú¾Ö‹œ’¦›úúmÄM ¤÷¼yšk‡ÏTW6Å pšõî¢|ÌŒ¼’éÐmãuçFù…ój* Í=®×øj~nÄÙ®;)XÕ1eÝ•¢VVñ¥ŸÁ˜™³õåœÝe^QñYk 'Å!ž}ý$ç0C»õQy‚HK¶ñÙ“Uk-VGPjÓZ»Ö`@‹Oø ‰õd6#™ñ.ò·Zj GLŠG„~“[iŒ–¹5äÛÃzT¢NN 5uç\4Ú´àkÛïF‡¨šÑù/OÁnlݸ3‘wzÍá6ö©¬šÕáí¸Z}Ïådrƒ€<Œp1ø^y嚘¬|ŒòÒ‘Ï ¦Øm<ò^Ýí> Ö]² ÈÕŸ^WœKŒ¯Ð?²ý&kÉ(GCéÍžô"óºÕšÜõö”1eVÔ‰"F«ÚrŠfÅÑ‘›/Ðtûx§æ¶ÏÂSä'­bܼJ‘h|â¢Qð“¯XuTÅëz`GÚ‰égVö¬/Dð6Ÿ÷—¦__»wr6_0Ģл^h”Ê#…ÁãžziúËé:ß^<žŒg“{áÅÏ¹Ó wñÎ4=£Ç»säðò«êƒÅnðvÑ NIs‘: Âî‰à;]ãé #çðtÕ¤ü^èôÎòA¸/JÇvu®’ãÏ¥¤á{‘ Gù!˜½‘` ÊÃ"‹µ‘ŠÁjÊ’Õ5//Y¥bÌÑaÙÏf+ü¶6‡ûR Í âT%.5=×Ì ú($Þp%F=Žã ¬KlêŽ%zþ^³rc^:ÿñ.ia-¾÷æ Ÿ+=¦,|}@úe¼ùå Çv̶ß÷%ÃCÃùd¦hw2‘¸§ 5‡7Llºè'2Qw\o}$úÁ¶Õת¡ž'{)ÄN~øðž~pd–OvšX¯xú0rúnÖm6Ýhç(üŠþí➊-rj¥¸\³ê4À /ø”“{@7ÐÁX7èCÑëõ#/µÈÜÔ² cž«>i‘«Ù²ö-G&oˆ`°z· "ÉDi4BæÄªÕHaé|rC[cKV±“6ŸD`jn8 sSu·)ùPe(¥êfyáVRTщ;bUËþük)].9mÏó²çsKÒz('×%ô™8E”IÖ-f¦/“^«t'ZAu©úCƒ ¢,§8é€~Û£8÷Ö<Ñ(Æ›_(òÛçhKœ˜¼YãFXgœþ`÷AyPŸìdqd©÷åIi(¢Æû\ÈeÖŽj8s^9§ªÄæÅõ/}J8‘S±3N4¬HÿÖ- rS¼!Ü ÙŽÇõbE{€l÷g½!ô‡Ã[böL®—+aAÂ2´Æ¢}%›ú Ð|ÅùWƒC»SuMר(ö]6ðlcK»o\í´ïVÙïŠÝ™<ÍħØÇ°ôTÖÙŒçÖG3êþ¨0T*æÖOÖ[Þ!Å”6Í{„GÎÜcju\Ÿì=ҷРJütÓÞ³”Q€eU¼PLœ÷5Ÿˆc¢š«~¶ºVF–ör–5~<ù”4K\08dC;­ëR€›`MEÛÀ?’r£]ù‘z‹;˜P+åŽPµïXà ºí{P¢•GC—r}#jþúèKÙÍÖ»’ qÜ…–']L…-ïR%’áé0ð¾¨;–/ßxçc°™×FTÊÆpJ¬mDøôÚOĨc9t—Åc&F8í6'¿9ßÿ!¬‡©ðÉypÊÿ†AæDrÜ4Ñ3ª#{¡ë±7 ¿}Ùs &*óHÉ hY)×–¤WÍнRÅõ©Ës§!¬z7lú–ë™ñw¶IU½“¢ãä:ßLŸºJYj´,ç\ç!}À±¡žª0Ø,ç€OÞOâýûœ}±ÖÌæ2K`û9 ŠË©ùØœÉ5~¥Š Â/öãí;#ëådœLçu×Ïžæ¹™gjåSGÁ­W†‘¶óˆZß¼’>Gë’VÏU)ºÕtÙ _EÁrøœ•|la¥Y#=6»Áöâ@ßvØìȕŽ«o ®æxOÕ²4‹]ó&!ö¿Ø4kY¾.¼§q¼ušsÍ&ÇßowýÕÈnŒ‡g¹›>É %¥(ÏË'â陈ÞáŒéÙÇ>nÖÐþmQ“Áóå…—•œ bM^Ä™êЉsÁ¾…:tÙÝ#^&"šúÖ²¯™¶£Ÿ3Ö™"¨ \ûOIŒLþ„ÞŒ8Ë!k¸E¨uýïÐÆFl]®ŸÑ©ï ­C-Ħ(åõéQÔü4¡:A‹ŲSLæ b“- C è¹×©œäÝÆ–mO ¯¾N&ß0ôÿÞ&i9v…¤UYó\®¼›Ÿ§NÜߕߓ¢J³fÈj<=}¸+¤,Ö^шMÍU¼|›µJj F‹4l=7kkLÊ$ýmV”7c›búÀ¹í¾`«v¾öijòÈÛé½/¦oƒÏEHm9/‡¦Ç¾¼gÛ›xÔï õj¦ƒà΂¥" ßI.¤êK3O>Îë*å<í^7Êúó¤Ÿoã§ðþ‰î¾øÒiá·“j¼:¿¼™$ç¦T×ï~ÛIYD ^äe€~¬£:Ê;—¯Üt“LXíqµÂS»:ý6@ û\¿$÷ÍÉ1´§ð\øÊ{‡`Ôa1Ýz¤ºz©©ˆá NßÂïå§Ä…ãÁ îµ…×Õø€IŸ¾£]w¹ëÞ5B|R¡IãaJq™4TC-âvtàœ4HpX¥ßò„¸.Z" V‡}óKØîÝð¼!¯^PüÃ0Œž$‚6·B6!Í;ÞèÌùE«¿¨ƒD mi ûÅk×ÕòòÿlE® endstream endobj 94 0 obj << /Length1 1540 /Length2 8936 /Length3 0 /Length 9961 /Filter /FlateDecode >> stream xÚ´4œ]6¬÷^¢Ç½÷.z'у f0£·DïQ‚DkÞ#z'B"ˆÞû'O{Ÿ÷ýÿµ¾oÍZ÷œk_{ï³÷9×>Ì ÚzOem`V`%ñ”—›G ¯¡¯ÊËàááçæááÃafÖ‡ ÁÛq˜ Á®p *ö/yW0ñ`S!5`PÀ37G/?€WHŒWXŒ‡ÀÇÃ#ú·#ÌU  r‡Ø4¸Ï`P0‡Yæìå ±³G<ìó÷ÀfÍàæú# ëv…Xƒ  Âìô°£5È ³†€^ÿ•‚MÂp=<<¸ANpn˜«;À‚°è‚á`Ww° àwËMø¯Ö¸q˜úöøŸ„Ìár Žk0þâµ»v詪´œÁÐ?Õÿtàüu8^nÞÒýý;úG0ÈÚæä ‚zA v[ˆ# ¥¤ÎðDp@P›ßŽ G8ì!ä‚8‚¬þ(P’Õ€:ü«?¸µ+Äç†C÷üæá˜¡6ò0''0Çù]ŸÄlýpî^À¿.× ó€úül!PÛßmظ9  7°ªÂ_>&œÿØìÀ€ Ÿì{ZÛo ïå þƒäým~èÁÏÇæ °}hì±?üáøÀAî`ÂÕ ìçóoâ¿//ÀbXí Pœÿd0ƒmÿÄ÷ï ñ¼ày/€ç÷كÂl`PG¯ÿ¸ÿqÅ@}]m]cοZþ‡”“ƒy|žò žò òxyù ¿ÿΣ ‚üUÇ¿bU¡¶0€èŸå>œÓß%»ÿ¥¶¿„ðß¹4aÊØþ#tSAë‡ïÿ³ÜÿùÿSùï,ÿW¡ÿoEJnŽŽðl:üxÄÑë/åº!¦@ö0 Ðÿu5ÿ9º`ˆ›Óÿ²ªÐÃ4ÈBíý”W€›GàO;®ñÛhCÖöªæO»Áïys„@ÁÚ08ä÷ óÅÃó?ÜÃY;<¼"ðiþAfè¿÷U„ZÃl~Ÿ äê òÂy¸ë$ðá}˜J°çb¹¡0ÄCà¡G?€-Ìç÷Å €ò¿M"QPñ$üÀiüƒD8ëïƒ(àÿÀdkû/V„ü‹} aÿ@~ÐÙÑ þ/^týÿ‚" ûð¿Z·vsu}xþÐèùüÿxtÀ`O°5ÎÂ,ÌZ<øeMpëE•,ÇÓï£|øýG‘'XFŠTî›:ò—Çü¹Qó²Ó?¢.WIvøŠîŒñ8˜¯ø¦F‰=Z¨kE·µZçò'‘¼Ú«»ñýPëèxnɵ±{´ß¤ûÉãDfŠ‚ËåðûLú–²KSÅy¹ý>&kÃ/n<”ј(LJ~<”à6Ùô¶ ¹jÙ©évU&ø‘Ìèn"ÒÖejߟà·þ/%\ȵTším|gµ“ôm©w?»…¨Õ,ÇSÌÝŠ”×ql'­Á¯Ù¬àÃzÒOÄ3T7ÆTŽ6bTuíšTVQûRPåWãV±e?xZ±~3çèP(ú¹¤ŸïÍ/ÈZÒ]ZªL*©„Û;­4ñ+¸†û±š¯zõàD‚¹><)c*5Ÿkè=iƒ¶Þ±Ïï„5öPTk,„K®n=@7)3ó圣Årà¢Ú ¯µ‡P—™0òðúñΓ@ÃáµCBÝþû+Ò‘Ïô:jJzkÝO™ÞÖž@j™k´¢qrÒè?.èÄKï -ÿÄâC:*-ã*qËC.µô#©qóÏ­iEúö¸|=7Yô´ã{Oõ“ É"L[n+’£©O¥ëÔ-øÊ§ðwŠm¼ÎžfT£Ï¥!ùrõ¡$RM5Õ¬åhÿy “µ¸ËJ&Þ«,@ADFBÅóœitkÆØšÃ(³£v·­À¶7¾3§ÎçîÑ L ¢øøcj¤zoªôãvè¯&¾,H’~EÑ{M·–†aŽ3£n_^Qp­ŠxäGDžÀ\'cißä’Õn¸ Ô==ø¥é%x%ª±¶>¾ùSÞ–(RÇ“ÑZ":ñËŠ¿¦}y$3Ͼå—0…ò﫜a±.{‡_ xâñÀÃ3ãú¬¢t ¤HxÏmª üû݆Q©?9™Øg|¹ßêžïÅZÎ+¿(%÷›§Õ…³4 Sº0cqHÎ5œ0'Þ~ ÄòNÈ}Ư$˼#ç;I¿z ã.!Ù±m@á¡lzfv]æÏVË" /‹³‚„0èöÉß×»` )ê<•§Ç'«5Nß+¼.?ª7- ”Ôå§$¿²‘b0YÝmÑשÁMÎØÔ®U c-wsÞÉm.¡W^Q±©î.Ѫž:gÈž’Ús4z¸ŒÐ«z~ÓYæU8ñÍ*³|A8pÚJ0[èÛªïÌ7¸Ý¢X{‹Jï›×MyÝT³‰—eóU/ínŸ ?¿ð.§è3#:}=²íZ^È¢“4Çó¢ýý„¬†Y¦íŒñéO³ÇQæ‹ÔP©«ý×9KÌŸ›nÙ&:õ¥ã©‚RG¸ÉðA¼êhÜu ÃPhÈW•òÒ»­ó'ò1O-í$©)0+l—Ùqôk•C®Ã(ÀïUÝÉ‚`ÒJ4v¸S‚©]pÑ’ø7u ¯NÆ•M\{™f³ö?«otö]µ‰$Ú‹í¼¤ƒ`§+|·¦ q å¾ØsÜ­ì&ôuô%&ŽÇ+®–^,¥‰³¦²ñi›I`¯Aϧª§/pM{åoæ_­Šå&­E§³ú>‚z…Ï "ƒ×‡ ßÒƒ‰¯#ÆFjø¿¤ääÐ&]ôòä&Aé?¿r/—zÃÁ`ÀÇ@¾qnàäCö_Ýëpd&Þœ6¾úŒ¯~{ÒËŒ›÷k‰œÍʳ¹‰dZ´M¢Ñ†£}óÚ®s¥¿ÿ§§Sà¶ë[þÙG5Åd„±›.ª:}ú,ÑNàPQ~ŸÜ´òw´Øam'¢Œ^û°ãÆ]Ç‹r+ÑÏM_/5u‹]ƒ[°˜yÔ¨W÷¸×[cY‰ôêç¤ÊûDri“»íŠâ¢13â´÷¿ç%éÿH|b¨f@¬ºèÝ\ôaaÃör­¾ù©ƒµ8U â¡ÌÂ÷Ù*ŸJAÂø áé¸ÊèyªûôTà®”qŠ@è%Mß4Ë#Â̽݀ÿhÐ%»¹;ì°ú<Áê1ßeÀA³“ÊË^?—Û–R m¾G¾Ë ‘_ùƒþáCÃ5Úkg°Ë‹Í0¢_´ß$%¿“Ç`§æ»¿ŸŽ;Ž!:.\Y¹0|Ñl1E°Û5Á¾uÆtú¼võ9Pìþ¶‰w:†Èª_¡@ô–ÂoHÉ2 u¶£œçÜz³qš£»Ô©zî\çÑ“öt'ÖêÙ¸݃O ‘÷ø:Ï …b×òR¥`ˆA¾ÃÜG­ÏƘî:4tÄ´ÇZ‡;M÷:G= ÎZ€Çî2/›$GïW-Ô“dBóÏK’Å%ñé–ý›É;.ïw—}ÞQã1è˜? *™y’ò²ªjCÝÆnoN@º®¼E+ë®77U¤2òal¸æøˆ†µ{]sž‚Ш5ɾÏL¡\í5ãÌJáù¾‚íÃꊤoTB±ÎêºØÍa"[ö‹Èÿ"eâ¸ûã—©ŸJµqíh×”µ’³„ÇgqfH³º’¼·éñô÷¹˜ ‹'D‰_Žì->_©?ysODw@*ø­}¥±<3¤ã2\±»:©ì`=z¶¶ç“—í[¨ûñåV™÷'E¿™»¼¬ýO¦~B6Ál/Q)‘YØ6!ïÐEAUɧˆˆl½ÏZŸðdÝ¥¥£RÞf­´Ì ¬7Ç:À%Ý­¾Žå"£ˆ úÖ|ê1m³`ö9˜,ª•bañ¦UÅ$O?­"0º2lÓ»‚ÈÆìær.#M%0}RðKÀk=U>½ù™–´U÷%ìpˆ¢2Ì-ÏK·–TÝH6hö„÷_Ù«µÖrÂ[²¼³øà‡}èEw Ûœ][ííߍd¡ÎWúÀÙ…&ãûØéÁüåìEýX.ý qRÜ»óâiª{U%ÞŸZ§ Wm{ƒgαP—¬%½NA—*–3–LÉg½ÄW„8cQ«$* Êæé@V–ѽÑíÄç›ÍQ7ZA«>TLJÑÍoƒ¨1u,Ó•~_Ÿdp`-áÌ _…Jn†}¯êåóùÒ_M=êdðMùEãðiU_CBFo"08¦¢ÍA[Ä–ª´YJºôçqyÈ0à»>ß+5`ýÚf‡Z‡)¾Ô ] SÊôÂ`äÜünµºž&¾`·’äWöˆ~†'s"È`ßÁù‘Äi»ê$ ÍŠY”&ÒÓ%1ê좌BôôÄESÙ›ŽXt  ŠÏuË8k†ÁâY_G½w(NûÉõþ»¶gásóÕf;§®Ÿ=êC…ÙgkÖYR *ªåÔB8­EeµÅõ¶É0lIå€Ye Ë6"Ñ,À‚1d yV0ŽSTq|’„O¿s¸éÓùºƒX­æ¡µ3¤SøG“Hv—’a2«µ|êýæ¨í3…Pó‘U2þ΃ÒwßÎ $¼=wl¾ßè7†e³yÞÂ]š/›¶lÖb/X—­1æ|Ãf3çZSG¶ÁZ]sÉí’ÒJë« ïç…qtïò‘ÌýW¯î0÷Z¯Á::êÂ;û¤ -GrçE¤l³ñ|Âø„Ùö •ž_ײÌ[¿šÑÖÄ]ÒÆŠkUî°_©=ŽSY£ý1;º°ŸE.c*oT‰ —|uÝ_WjB¦"„ü•@ ú› 9²].ÏÑ*¿lpAÏib[s³w©J|77ú¿‘Ÿõ¨>2&š3ðo+?µèB×Ýgýdy„²¤Xæ¦ÒŸ£²¯Þ?fsþ ß–÷À>î¹|´äÜ‚=‡uSb )ûñ{3õŒ}‰ªNSÔ¿úªé}O™j>òIÝ$ÜŽIjÉ“(PvçB.Ä[¯²½”âu„n …ý¼7KY:à u¢L}`ï~sîÃQÛ©ò5qÆþb‰³ ”Ë+ ›V`öѼù³XŸ§æûú Š­ 5cß“+¬XT7„[ÃÍ< U8¬´¦n}8ÿçÜ7©–þ/¡¤\J_¡Ç^f¶*·æâš^* èÀå'ŒìgîMûÜÅC¯Š;ÆÞC<"<3ßRÑùlãyÉŸ,ãÉ[ùF·S–ã5¶¤ŠW¯' “:t%¾ÍÛȸWÛÑã=j{·ñ $Zï½lÔ Ïz;f£P…Že¬rE’nj³˜‘ð²=€ßs‰zËê@j'PÓ*¼ªtÒ%3]Vt†kù JÛɘ, n$qROt‹Þ~kškL䬫Es‘!¸‰¨Ä 9«â"pI–ìN\BQ؉hÞД+qÃ:ê\÷BŽ{›9—5*|˘›Ì-Ý=œ0Q9 \r\zá¸Ì’¾IFM¡ëÿÆÈCŽ!÷$áüjÖ/©*èab¦âNºTÓ&nÀ8ðŽþ$h5Z“вk ¤ù@àè}èØ2Ç2F賓ÏóŒ_Bo`œêÌ#Ë’·U€L––Z÷Á b7¿RxU`g—η*¥JiÝve'P:zÇÅd•ú{¦´ž×ÍŽU縭…zÜ#bó<ÂPƒ¥§BàÅ­…未jû“ F¶Tý{N²šÃ­¯Ô×NÖ›QoŸÏ˜L¨/jä{=+ÓId§íÔFFåCb’0hµg•ÇÖz\…6NE¾G_ûHúc"T¬3þ0`?Ï!ÉŽúêòx'=¼Ç^Nh¿ÖüeóÖZÏè))+éÀÕ²­ÞדoZÏŠÎóÎjï6c\S¦§P#ÄBD;4ßñI‡Qê§¢íq]é˜lb«6_o×Ê)n¡?kgqm}n…ýès•–^¿ø´¿‹’¨õ§'¥ÖÖ)TgSÛmÔò¬xú“‡:ˆ£Ò¾Ú÷=Ÿ;¨Ñ "{V8â˜V.ÁUz³@µî#.Ï vTµ6vs¥Ï‡ å̦²|ËQtJ9†R¡Åpë*¯ßȆ‚kJ‚‘úò¶øRè|qÔÄSª1‹'øR¨žqu× —ä9±xø¸#²§©Óâ•çó‘~V÷ëüøí9@¾Å7ápvvsÒ¢%´3ÈYqòרt^rݾùSÛe_rÅí›ø¦Ÿôvô5ŽÀ®>c]TÎq_U[«`ŸlûQ<Åìð@3Á P®÷¾"f+峸(Zåf 94óŸO7 ¦Ø½­üÊaY'}³‡™‘¯)+Ü’ytÌ®>£¨ð…¨{irŸZOo FвŠÀ.1MÃÔ—.\Ÿ\¿‚šè;íë¤:k@”JËÔjÛ*Qž¥ a/qƒv“ÙäæW¬ºN±h‡ßc({R/¼dÞmš0ÙíëÞW3ºMà=zó5y3hâ€iÏâ <ºôèÑ á>µÖC ð½K ôãÃCªt3°x3l]ÔÛSNõ„™S¥ëX¼Ll{_ÞI%•ª¡ž_¡¥,‡¦Û)ñž`Œí}ZÁ§÷K5ÕkJó ¤Ìb)•©m¥vëÞ/š äò_gQ ô[ðĉƒõà†$Êšp”±Êç$"²Boߪ=×°§IvR–-õú¶äÈ}Ëg¯ÙÑ21C2Ç"Aräûû¢‡1EæÛw G^Q⋆K, r@~fÊ©fÀIY`rÖùzÎh¹øç¥È‘µ ìcÐyä U_Y’ÌiYÁ~±Âªþw qºvË“Ã*EÞµÕ-– è=‹U S%Ø6,ÈYóË$ÿކX´ ¦P¦÷Œ@{,×d‰è>fèš’_bK løZÝô»­D]¸Xà8Y¡:Vr\ëç3µ=•ABfD-ü5Vvæîús žæ&^©¯Yá`ëÒµÝaƒ¥:÷®Bj‚œÏZ4ÙaoCrl^džohÖqœÃÞ†,o5 'ÙÆxarhÂw©½ýI¾ÂÁ¤Ù>ÞYÞ8Åž¿‘Z(³û鶪…ÎZm‘eÜ>.•sðNh´j#‡éTñ¼½ê¥Ì¤³¼{$¬OÔ¾´­#M1%XPÿìá;U¿[fÆHÈŽ¥1ï¸T—0sUP`_cü\ÒÞñÀ§úÀÙÆØn|[@éäŠLAFãv¥s–¡¯ü¦/Rf‡vå¶ùRM=¬v$©"á­~øÝ›ŠðWvg€\ŸT‘…… áGAã÷e_KîúW)­Øa ;,LÕ¯:Šñ^âé6º|-K‹2¶­ôå_Æ)uùà¼ÒjìÉM‹£õeDwæ…ª„9–Ô“$ý¬cP<öè³á®ÐÆêwAÍ—¯og*XYP7& |€¿ A³é¿€žÄÐOÆbí;. &wt6Q¨¸[“,”wé‘)bZ°)¾Òw¥¸ÓßwEóŸ¡USVy€ˆÖ)ÃÄw­4ÅÑ8Ç>†¯Ä„søÔWÙº~žY…OŒñ ›ÜÕƒ[VYp@ïùÕ–ýóÕ_|y\ƒÚ+¾žò“ØB û%N#°N€XezpCͰžª‡¦zU­jN 8j‘L¡ñýu¸U³ Ãs™"ß;`8mŽ›Zû#ñÌd-;«¶£6œQ¢æÌÇ•ž2fÔÄ”Öà˜E^3ÖmgÚ-bpâPyAýí ÖáM¿íö¶Wï JÅIÈ(¹ýÄ}Ñ\_'S³)+ç@v!^XäÕµýÖÁh¤•nQ)dÑ^ÐóµX¬ù.»eeä;N•§jñ¸vÆT‘‹=ÏHÍ¿RMÅkÐâU9¢¥UÂQä*u©–}‡íÔ5p–îÒßÕ×ó}Vº¾cЄC¶"!±o’¹ÞÍf.Û¤fe?…Ü–×xºl7ÚF¢È”¥ùQ¼CÏcW9„„r±{祂‹¿ŠBU+ŒLÃÙèæéZ`à;uç裴x23ƒfx*üR!ß9‰†­v¥­PTc6ÙkÀêIëǧ…”; ÅÆ}H|‹¥ÛQ&z¦s­0”òßÔ}aã#-B’kˆE–ø)¯sSôF­E¿¬¬ý×/žÛò±8ŽúòÊÏ…ˆ`×M×÷sIÆïE™%Ð šÌŸ¦jiø")>”µ ÂÎzŠo›ÖeJò-\ºü…®ô§|CÕŠÙ²óæw°Ùº% ï•9ª¬(s&ÀGÓÆ¨è_µ¾¾‹jÁ Ö”Z^¸àUõº¿åšÝpU»‹c5ÈbEKe«zìÙ“+‰dü¡_œ¼p¨*zì¸ð£i; ~³ò-müÓ8VÞWYÆ»†*üØO§©¦=ñ\ß~¨à+²ûÉ~ñ‘c°4„äÿ¨¥t-ÐÇ'rÅŽo×°ï¾G„àÔß?‰íc©Öªó’ú$‘UK–åtRµngÈã 95½ž÷}å;Í ¦ö~¾4;Èô»Ã' i 75ϋ颮âäþ%3=«kž”Iš#°›ÿ².03ŽƒRïì‰k¼×Z@\w~7®ï:Á³:$O{žø\që£DJY;ãdÙ÷8Aêu ¢²¸†kã½5“­‚)Œ> Lûø¨Œ]ƒO'ʨiŒC3/"'K±‘Z—óSœí/Pì±qfÕCgTñ$T.ô•V Ã^Ž‘”Øv8ØT;á„Ų«êÅ/[®m »†aäFHÅYµ›¦o½VeöV2ê~Æf™}TX^oÉómØÇ›^ÜСÉWÇ!xV.}…‰Qš™K|ç4ËÇÀÍ¢´j `„ Ò¡9siÈ‚M§0?¬¢£Ò#L‡S[(›ØRY{m[‰wÉ o^SÜÙEÇõ.°}Ä1ù!ê‹0× ýª6ö8E·®ì]dI½TTù©BöšÿàXP ¿#½ó}b~Íûg ²Í>’¦F/)­µ§ \s£`LLWðÀÝ9Œ™Nxë%?–þP5 u*§ÒJJz¼y€þ4ó¸þ€‰Nàȯ¬T"œ¡º&œæX÷Û`Ùüà 7°óXn;íD.ÏÀ±vý–ÍI“kõô´H%âÍüõV‹Í ÄšãM-u¬ŽÀà«ëhÚ°é]6djn>9üÝæà=Q®G¨ÖúUØ×3¢ø Àn1ù)eð#½ù7_§1alþãÚî‚ÚHÙlûaÞhÔ ÈdWPǧ?òÞ8ÛL˳Õ|’ÍõõùÖ1j9ñ˜…»Óe‘X+æQk˜ÏÍd¿¾ ÒÞh}[Ë2zÉýì+j¡oø[අU$m¿Çq޾鋼h?Hè?~\5"D›¤iäfà³ß¼=ézïö¡ìÉ»i:2áœç›:zñØknò¢ÚÑ}s.õrÉ!ƒ?6»Ý€Ò¹eƒC¤Ùåmü‰©—[–Áï4šP¢yc=¶å(!>ž;fJèËTÁó ¾Li™¡ÃäçC$wáêÕ¼}¢f™±{?_£ÔP·˜U¶àXé/´Y_ö½?Çó£š.´x†b(œIè;»±ònutêŠÇ¡+p+ÊC(HèÛI zþ'œ|á_)aÙ;ª¸qaÁ\¸>‰±PÐL³çnRŸ3æ8·¼úQl*½ÝI÷f0Œ:ê0.û&šp6`Nb]óLÖ«YE\‹(ÙÑÔ »2jke;Y5JTŒT–Óu%øQÄäîHeÓíçi ´ržcnœZëÊ ‹œæ*2A¹žÎd ‰•"Õ•3¾f5]#îÆÓ(ä±hž4×áz“Ìn!«[ÖG%úe¡Dœm)Úþè¦;‰üíò•ø Æù{W•yø°ïjQüMM‡ï3jÕ´Ù=è1ŽÓ»bŽ[U­”/:y~ ~{îd´Ê¶¦:²H¹`åfÈd8v{ôÔ6‰ÂnGDŠƒ\2UXÚiW½*WEb¨'AÎô‹¢sG–1yÇonƒ1>-öcŸœO"²j"t( ÇÍ仸6 :æWQß`¿ÆLëÕDÍL¦‘¾Æ:µccXîÑõ=ÓüUûkŒ,+`2LNäœSˆ¾húÂåç+†NúÛÌd¤v'L¸nÓ{›F†vT VýÌ}»jöûÓq½ÃsêÂOKóþââ öê§oäoü#÷–Šñ`Í 6ëgRiýׯÏ3~*»%jîÃq…:žuî2¾¢yjZjH¥ãhóí!ñÔ|WÅJ9KÈtþ|¹Iñø!yÚL/òæÎAÝVá,ùíRLI`ľs2V´ø$êª É"HÒg‘X’£Äœ”Cs–\Sm’=/aðptï³~›.Õ,9áSN•äâלÏÔ'gk«au{7üÄ–MŽ™¢ï2%´E|ãgŽ5æíêÑ8D&ËNYÅ1ô¤±ÄŸrµb£Æð}“Ò¥ÁñÁБøøB•í¥â´W‚¬¸†ßcGÕ´íZ’»¯XOÓÑñÕˇBåå´ è2ìð7'ÅH^£Gèç¬?Ê*;¿ÛIÅÂ8J|øJzEM`ö€Œˆ2 )¸jrÒG.CPE)ø0°ïÃ:‘)þ×£7YyD¬NqòKÑŽçÍãÞ6tj´:pôþiÈÖ&¿ò´¬žj4zã¾æÖIÖ¹òs¾ÇÑÚ,…j¸…ÍÓ¼ÞÃÛ¹I™âN1/.À„|÷=9iUBS’Ðý°ÌÞgMNÿÒF€‹ƒRÏ{`(ÙÆ“9`7¼C¤þÔ¨D\ÿ›;‡)<éö®íŸÝÿI]™ endstream endobj 96 0 obj << /Length1 1779 /Length2 11233 /Length3 0 /Length 12354 /Filter /FlateDecode >> stream xÚ·PØ-ŠCp ¼q îžàîÜi ‘nÜ!¸»»K‚'8 nAƒ»Ü#w&÷þ_õ^Q½¶®}ÎÚ§ jre5&3ˆ Pvbbcfåˆ)¨Ë°±XY9˜YYÙ‘©©ÕAN6ÀÿØ‘©?A0ÿob@c§›¸±ÓK  u¶°qظùÙxøYY쬬|ÿ „8ðÄ]@ff€, tD¦ƒØ¹;€,,^úüç#€Î”ÀÆÇÇÃøg:@Äè25Œ,¶/MmjSÐÉý¿JÐ Z:9Ùñ³°¸ºº2Û:2C,„é® 'K€*Ðèà4ü12@ÑØø÷hÌÈÔuKã_5ˆ¹“«±ðb°™ÁŽ/)Î`3 à¥;@MF dÿ,ÿW#àïð1³ýSîïì? À&›šBlíŒÁî °Àd(IÊ3;¹91ŒÁfÛ8B^ò]ŒA6Æ&/R7HЍŒ_&ü{>GS“#³#ÈæYþ(órÌ`31ˆ­-ìäˆü?qÐôåÜÝYþ¾\k0Äìùd›™ÿ1†™³‹dï ”ÿ;æÅ„ü¯Íèàbeeåeçí@7SK–?¨»Ûÿt²ýa~™ÁÛÓb0è 2¾üAöt4vœœÞž¿;þ!³±Ì@¦N Œüoõ3Ðü/ürÿ 7€.ë‹üجüüóIÿEaf°û¿á^1‹Œšº¼¦èÛ¿GþÇ)* qx2qp˜Ø¹Øll¬.V€÷×Q6ý̓õß\°9À÷Ý—súe—¿5@÷÷‚Ðþ»–"äE¹@Ý¿B×cåb5}ùÅöÿ,÷?SþÿTþG•ÿ«Ðÿ—‘¤³ÍŸ~º¿þ?~c[ûß/ÊuvzÙÈË.€ÿ7Tø×ê*Í@ζÿë•q2~Ù°Å‹¢™Ø8™Y9ÿ²ƒ%An@3e“©å_ªùË®ñǾـÀ@eˆ#èæ%‹•õ|/KfjýòŠ8¾HóOðe‡þ»¯ØböDz±sqŒŒÝ‘Y_ÅÎÅðd{ÙJ3 ÛŸb°0ƒ!N/)€—½æä?.–› À"ò‡é/Ä`ûñðX”þA¼µßK¤ñ¿ˆÀbò/zÉ3ýý1‹Ùo Àü ²X̃/],~ƒœË ç YKw;Ë—·é߈è7È `±ú ¾³ù ¾0³ý²½0û­ÔË~²@~ƒ/Ìì~ƒ/T~ƒ/}ƒ/}~ƒ/Çãü|¡áò|¡áú/d¡áö|¡áþ'ü¯›6uvpxyöþ\ÉüÿùÆn@SäùS@«šÀÖ›j"W¦­QvN´¾_áHš›.;*þb‚·çs"ÓÛ·«Ø쟞­µðX­ V¼Ò"øñæëZáÍM6½Æ±…îåÙ·å::tŒ8Àfx'Mª®ï§èñí϶f2÷¤iš*¯+,Oi™QaF£"ßðòr Â¶‰d¶UŠ~™šn—¡rüõ~ô(Drï6­wˆk½o¡”´–F´¿f'w‘¹/œºÛÍM(g4˜¢Þì–xsKçÑèGgâ8¬&ؤªÃ,ŸðѬeßÕgS&ÖßNšƒ÷mäNÊYünÀ¢±Øúhn;}—Ý… Ûä-6­{BÍd¾Žùþy†Å)T™ÜjK„´ÌƃuÇ=F?Æ"é…¦@EîÒŒ¶ÀkÅæåw³Ë6Ó1ü]g"ÏÎ?Om÷è^¥l„íóvÔ¿6ÍÇ»?R㦇 ©’„9ãíÐÍ rç[ uL–|#ÏO÷݉H×åO†ŸiZ„W·aÌݲ/”\Ý Ç²NC,©P›|g™ê—V–œtë·k9º· ð*¿N]ºíP ñgø’ç”í{òâ¹Ù ª}…ª0Œ¸Àöôö.¬RñDÂGìz  ìj~ò€{DS"•rb{~:?…I¥ô^TH„>$ŸÝÉ#ûExœÜèú[*dÕ÷¥¼òe` ‘ÎU¦cNFHµcJ{„²‘r0ù(V»'AþgKld7m¢Ëˆ‰y-,$ïÎÜ`â¿ÊðrJï9ìÂ/že,¹I†1}„‚ŽòÆW{÷d\ײl¼Þ0Ù§U¤Mãæ5€øF¡­Äå¨ÿ ´* ¸6„›#¬Cq®æÀSû¤û){«Š£Ò@*Ò³-« I3âMkTqè­£%…bÆ!\Àà&.™æñ—[ë:2J•Ë`¾ìy3¢ÏÇÙµn«vŸµQe[’d¿âC+aßVÂ7 ]Ñí i(àúˉÏÚ5”àD)# yQšÏo£wÊo~|$¥„ü¢ÇÔÙ¿dî„¢Ò(õ§Ãü¤U(BØ,Å$8-oà`.Zß|·Aé€ r×"œÂëNWÅáýyÉðÕ®`ô5ʯífÕB1"çbZ«ÕwãK2)‡_êÅŒÇãÙ¨s8ãiH‡¨ZÁª,™3dؽøó"U> n¦ÏåK¤§ý§ð¾†%z§Óïz «ãÊÚ‘r}Ûl.Üg%ô¡‰ÙØôã Rp&‚,Ç r¿væ /¥-ªÅ|ݹ‡©£|GH‚ò–ˆÄtã} y:ÌÖ›èYèN…Î:3]Zrjànã°Öc¬æý»LÿGs¾×’@bjªˆWK­X0ãG£þa`þäÓ2ñƒÞÊ| ñ-NhÖ.NÄü"ÎFû¢O#…2¤ýúQu9:º]© …?·elQk<±æ§u‰FÛ>~·±?dî…ºýAa^…+kêül„–Q΋…¼3á—ù<õÆÐÀÆ®¯w9|£_”dkD† ù• &X¨!/® úùôc8—w@ÄôÛ*Ô÷¡\þŒ[º&¸ÐóêÐÝÚnP…e­wª·¨ ¥?IýR C£Þà ^©[%D¾T±*Ñ^œbë*¬Lß— ø^"­SÓ‹0œAìª4P —¶1È…•&–@Ρ¿ß`ÁhúFd¾›8²ú.æx2»¥Ýªëö€_L9~®ˆÔ§Øumå99ÜÁ’ùçæž]Ñ_ކ›¾š|"!Uâì2+‡šWrŠ9_8@"ÔNþþèŸQàPÊš{˜!n¨k=”4Ðj_-Å¡(Î˸<ƒÀ„}WŸÂ¨<™…øÃ櫼õEb÷î+4@¨7B!W…Ìü~ë?\]àOž¹Q`ýÂpÁ·¯}Þ}˜ë»?™R¾ÀwQ­Š²áSågëèJŽá†bÕJ°ˆ•Ý€#ôi€¾NLäÃ:-—® £/•æPã0°&[è=Pdô~ýˆ‹\CÁœ;×§)ÊSê©­ã(\¯ß'”d¹Øà_ŸEPEÙ±4[?t¢øé¢_h”—Àºù—šÁ®Î¨ÿˆVn[+ÜŽ/R´Î9é)æ>*JWž0’è Ø"½Nú3­$5¹ K›¯í ¤fÌIÁàx4‡#ˆ„_f>ǰÈFÞd·ÎçUeÉ›Mßîj5²¯Â3Ò‹ß‚ï.äÖK?‹|øŒ†¿ïçÎZ¾ªCß~:{ßÝ’“(€¢ÑQýcÅF3Ö ¨è³æ˜ƒ¶&4ÿ N|BÕªˆõÕ lÐÅ$´!­?tùœ?Ër—¨!ÃÈ‹š‘H ðï9ÓÂGï1ëO›ýÑÈÚͬpUiÆ~|Åi°/;§e¿èyÙ[ÁÚg¾JQÒïÚ{ClÝØ­ :>¿•ÀYž<ƒêëñ~›ôp‘ Xµ¡¹Hd£âÇfeNbé°&ö1!ÇÉÚ!–wg+~B5’U˜n4å׎ÑyKZXO,Î]]×ó’Áá"{½OÏu÷Ž—iD(ŒÚ£—£rxZkP„ã¿fõ- ª§®>qÐ2ƒ »O­Zœ†ÈW"Üôß| ¿ÄaoAÿ¥±­ù qY³($[’þ:œ¯ÙÃÚ •'nö ŒÆ¢øÖ—vÍ$ÀJ}†§ŠyqG/ªR†UÖRx™>]%`ºZ7NŸâ ìÀ=ê\,:Ú‚B‰X1ÙØFoÒÎâHpâeí ©Æá½ÙÃè¥ß(ºsßÊWëÎÏR8ðFè®",­ž¥¥# Ä[‘09áÆâá §Ö©5gV¯„%ÄŠˆsß®!Œ¶³o„½ý2ç—Œ¥HÇsjfɓ˺¨zcògÎÝyÙg»òço‚f+S£¾¾ÂM%~Å÷óc—ȇ ;œóµA)ì_j-ÓJYäƒ ·>œã{ mżó:SWÂMŸ”жÑÒwH¢yŸhhœ&ŠæÀMe9v“wu8…âP’42ÓÿÜFH€wéÔ‡¦¸# Üäõ 2® ¸€ÄSÁë´î¨|1V1œªKÚôä3$ìàÎä"½AɲyíO›-}º ªekh‹œðúA¤B•ÁˆKô»FùI£C#Ù;QŸ´eÈe¯‹ÌÁüo4 ôgzS¬GÁ2”ÝV{á¢Á¢.~.ó =ã­Î’×RŠLؘÓ6Ãr£¾I :Ç)ï|i©Ûæwy­þ,¯ÍSµ·n&ðþŽ„ @Ž\aþáYØ×¹‘˜’Šèm}aEù Áˆ¶ÈµÏ—U¯Åh _ë?, ÒL¥…‡hú£ôˆGùu>„o]nK³¾íÛ(ºù>×wt,c„æ‡æX! 'жÒ}DfÇ)ª¦½Px¬š,aeà C‚)yx­ ®7:PÛñL!üJZòn£öêÔÚ,¼OtЙaÙc, ì¡„W,fƒÙX’î^Œa‹žUÓ^­ÃðÀԨ𛇜—: ¦ZÏšš“)Æÿ8è¹nл† 1%sovÈ|ÿtA©êªG#ÖŸ±¿nrGf¶vzÌàC_¦¢S Å—P«ß[:· —#ž»šþèç N©ÚWΩù­ð¼cT¸@>Xÿ!`¡÷â¼h y\/¼>~ÔâfgŸŠ=-—jîÆv¿Å9ƾÿ¤² ögˆ½Y@sïNÚW¥èÙQ/VçNhæH™¬ñ=ÞdÇÊ+¡M]Ú s´ÏªÞYÛú7Á‚0Šëm¹x1ã~3³ô”G¬öC§-aRì´VÁ€@ ‹…Ç6àåÅî+h‘È»*0žqQž0œÌ}Šž*liý÷‚Œ~ÞÛÈ <ô¬•ŠŒ çôÀUNZ§ŽˆN?ÀF •=ˆ"åÞârZ¢R€Pf|u¸!‡®è¹+s­¯7ÌÎ5´fì{Om½…Ãþ§É£ïwNj†88äà-ù’(2©ŠÃóbim³JÚ˜O¼ƒøHï6´¿î-&Áø¤2DîÂ/Þ˜µ¯ùúiá«Ë é ýò,ùÎ!)Y¢¸ûdç'FÏÆp{¨ú¡¤ÙÊ–R+äªV†ÄƒƒF`ÔE‘P= kpdG:‡j?‹çøV€bδc@»A8Ÿ¶J‘Ó1«ßkd¦d¢ðƒ\ßtÐ+ì+îh¨Þ‰›…(Ì ¹ÔÜ$'ª&–©©ý×ýÇò ñÓ&lˆ¾ -ÙWùvR4ÔðǵڮÉ_¶«²½Ð›j9ÊQåuçŸ×F$ÛäÇôA/æªÇ¯@Ø@…ü™õõ×SË:‚üùƒ¤Œ¥ÌyT;jgN§BŸÔ¬$ç Æí$ Ö·=Æ–ü½+E¯!ýçŠMèýpŒhîF¿æ86[€ â4ø·Ü ÑÀ1;,1ÔØ÷¶h(¯oÚfýâ7aœ÷¶*X™^··ªØs´ˆ½£èªrTîu Â9[\æÄ˜Ü]úü(£OKÎÑ.Þ&3Ål×Avg¨‚7ö³6^b2»žÅpPGq§Á,¡X”""sÏóó×5g(YðÉÄI~2ÔW$t·5©óå¡|¡€®Oš<…!јܧb¹$+,Œ°ÔŒXç‹¡ï"&²Ü…çuC.'oœ˜–ïÃÌ«œ/iö¨›6ã´0U ¹Âä—§?“=#âù´‘t†Ø‹æGgBEÎVÔvÒIðûÓÜ!+5|¿|;ŒÛf¾ÿ •ð^ÉôÇ¢Qnþ'š¸>CQ„ B§‡ì¥ Õ'pÓ™I¼ã>=ãÛAÏ] Û?ÚTp±}ØG›UÆoU4oÊåÃs²P4¤aòOáÓ¢‘ä5ºhem¸ø-¿êw¶†‹Ã«6ëNøãóu´.)zžÄ ªøå–à uÓÌA²B¦=²¼K1¿EºnšˆÏPb-ž-a+¦×r5> ͽ¡›@]ôE˜#æ^C|óM² þ<é—ìÃùy³l‚ÿ£$‘ž’@Ò(ë=öÔ h­%ñÀ.'v;h^‹õâ 63¥GN…ÆÉìƒ e|ÿ|èö¼˜åFôë8óH¼Kßžj¿²_i|`?·-£œÓ¼Á°h_êwÃJ#fqgYÞþ¨ó£ƒôäãj)ÚâÆ„3•LʇŠ6ñoÎŽ‚5¯ïUë47lΑˆRLKÜDáÏuÞɃvìÛn•´PŽ‚A:ÚÒ›H{RwLY‡Ä!_Ÿj±V>Üf§o+¼g3ò¨üvNßß÷Fø6Ñüzê:0S_ûŒeÿ:Ðõx®Œ²¿ñdjÉõðÚW º(úf?1n–‘[ÅF‘‹Ý7ÍnC·#Õô„êо4Jy¤¶7¢£Ýñ–ïp™múÈ›ê—=ÅšòdØè.f†I )äíLìÈ“ddŒ£ ÓÔÆû}=ÎÅç E[ez$­¨«j•Ÿù[>zbsZB,% ÐøÄôµhCí|9½†æ~!•ò‹òPÊñ„Õ`7¡¯÷“(xk}†Ør²wC–˜·]ñjó‰4|$%o×F~&0pËž©õÔz²Ãž=…KcÎ.h¢{|•±ÓÜevæÁ ·ãûÊ®’”ö³´:Ny»&™½:Ÿ®Õ@dôÀÕad¤@1ï4}ú’H"rp9Æ}úfnöÌ‹d}{ñ—…}R¡­¦ÆPQ³c ª97³¼Œ>G„pDãr Þ± @vƒ‡§ï©ÛæçåcÑyâ64ÕõôÝÒ±{Ðë«>{Ø(o/Ђýƒk b -Ç’ÛÚcí=föN±àÄã’–%Ñ­OœžTБ㫈Ú`е~çLØ^æ°ôûéRa×u-³ÜGÔ)ÎðÀ£ùiq“ËÏ£Dª`á—ãç¹3ûç-$=-Û[ØdzEë ¨jé}ÂË}LL¸aþ;u½‹FIb,ðZ/ìíLßjèAz$:yh@ÿ5‘l ²°’¢Nn(2r‰1oyÅ.4ðJgq~\ÖŒn-nuq·ÿÁ$’ÛH¨:šyÄ–Ÿãv!N;YŽÓÝÒ¼Ö¢hÄr±èZYÃÿç¢)m«™>\œWŠTmï@‚KiK§‰\E”u— &1°Ódà;áiE&.øSÀο®!¨ÇãÉJd2έ¤Z`׫âƒÒ(¬—ö‹ófVh¾ˆÄ)¼TZ q6…sË=Ð2h%wtÄ›sÚª´5>šE/*bÓ}tþžGô¦$Ë’Ô=%ÚkbÞ·Þ¬·½Ë‹Ÿ"¥†‘Íß•Y1év¥¸\o¦ÅXçIÄù>€Fã3óç~6\šlå69”Åå*ž¶³´!¦7pþUkÔÎŽ„ø8Üc_)«ÏÉqsòýg4\™÷˜ÞG´h‘œÔH˜ÙÕ‡þPœb©ZÁlnöóK4ÄÂÃÀf1ò!âú®1úÐϱ·au‰ÒØ}:é®t4ljôÅÖU^Ü¿‚Fzxšóý[tω+C¯ÒÓÒdG/"£Ð×·­˜KíÎßý4pVçoõ ÂÙ-]"°|ÍÌ ¥•2©dôÛ—ÔR§© úÑ]´ëû¤Ë(`FÈ@ý­©”0‚Ë8<¶qX¯;ûU‚&0áB ­è ›­¯z('Z<¦Ù›ŠKßËqíFIxñ‰ù/¶â3^Áñpìe›T\hñ7’¡uEŸ‘"¤v‘F’(azÕ`f´è]Ñ÷ È@¾ÌØlÒ¸äØR;Êaœ“³îyª›Áll8Ù³¦ªûà=h´; „Åzñ“Q²Ú¬{J½žoMë‹^符oÖ]È*_]6ë÷”Ò=¹L7Àf0n@ ¤úYg({Ï`kwÙ‘3$ãá¡/8J÷Lã¥>5¤—ZEõÙè³9,ýå¬ «[t«Ò8˜g)ŽÆ—%¦xȰ¤áÑ€G½•W•S¦€žÊß22f¯U»ÿYàÚ;œYJ[X> ‘ ?9»qWÅÛ|ýÀÈBÂÚHÇšz'²†£†!>3lµ,&NW_Foª‘g‚5¦®ØXòGWËcL˜Uqy|B»Gªß° 6ëŽáŒ~håz»ÝŠ#'Ø¥ù“!»AzQbßö«­/mQ%§1V*­Uô4”»¤Y+HöÏW¡ôÝ&_6Hž¯È|Žw¡ù ÷Ò·«+,‰x¿Ê~øJúå’p%(_bsx_Ô$Ï+ øs³F]¼ñ䈡tF`þ€ðZÞ§b²ñƒ„Û±kx½ko+†5ȼ€â3ÐÍ–€.®+¦;Y¸u)X‹»9’bQÐME?^zd“¯Áúð.˜Ó |ryÁYú`é8Z1CˆqY‡>èCêÝ<›m÷s\\Ôò5S 5!ø'¼ñ`ŠðaîalYïW€q÷¯æ¬@¼Nn-¢yžÇ-ˆÂ…¡;…nw×3³=œíˆðæi§·£)×¾À•:Ç´VM3¸&¯™=úªìšåcÍ#ªuXy«¢fvVÃËÿÁCpõú¼í•;œèíãÝÞPÄ7g§)äúêmyDVï†7šD¾:(~`ܰ˜·†íü¢¤ÿì32Zâ‰@}÷e9wÆ+×B«=YnZÒ:¡ Ë^üy½^ܯ‡î"[¤•ºÌã /S8A»Vpd`ˆà&!æ,âú‰\h-™Í`s—¸.pÚ魺ݩ;¥–ÔÓ0A g‘ «e³).9½·/)04n8éYKTv:e{&MNÎ’ûˆ¨˜§ñyºyЇp{ö°¶6&õ1´Ò¿ÔbA¬ÍÈ Pô¥¿M/S}_4m±–±òJáB ¾b¸ËÆîF#wÃðh¦Õi¬ü§Lßçfüž‚R)e[‡+ÀËU †þ×|A=mQÅ1LÛ§o£|µ¦øcErÒ5u?½…Þ}ô¥Bˆ£c·L¹œr¢¿~\ÝPç;ஈ âRʼ¬$í"ÓÖ­l} øŠõó`i@…ý㈞%ÿgŠí .ŒƒèÛ€ÛÚì'uXKg‘´ÖÌ  ”5<ÉüÌ.ÙqB기¬nZd{s÷èØ’DsºÏ-c«Ú*¦ƒøa¢â•hBÅìðƒäÛÏÁ ú›hÑ¾õÇ1¡U)¸0â»NºnQG—*ÔH[ä_çA¦ä]^3®6&ØwˆŠÌÑŠD{†t}>èÄóEl2ßi(¦¢·0aÖ¶é’Mùl ì¾Ú‘£Aãø|rˆ16`êÃQN ÒÛ6Ó¶èhû5>®Õx'•öK½:0Ú¶×ò\ÌhâR6Þød7f¥ufR÷\ìÕGx‘ÊÆ|9‘òQ×t»ž²Cü¦“ñ²` åê-ú^ܺ°žÐðjpY§E^â¡52"†.µÝ7#ñNÃŽ2{Tp}¶ð(èÛÂNv¢¿¦ë%ðíæ =¨AÂä³ î,žì£îˆ†-„ ª!¿Ê®sƒ÷pä)ÏÖ„*¡¤‘$‰®ð–C}‚RZo· ÔÎó žýMÕƒþvjxÃÓøQ£$ež­Ìs¢eŒA" ö Éâř頀L%‡5tØÌºÍŠžŸ¢MšR¥ð/}3ŠC˜½)Íœ\<ƒpIdÞsQ$^£¦›;¶cdbš±ê¨á%ü±SØ›’<žÇƒ--âI¶è*Ý£ü„nì¨qŽü›ã ž¥žzÜYô: ·"ƒ¾4v…äCŃf»m^‚(µ4㇇‡Os»6Dd¤ýö^›%”ÚHÞòéWY\Ö ï~EýâÐß±&DØÔÃ4?ã»|¦PÈžÕ9)¨àdžzsNÈà¤û#=Üc†íQJÑ;\?YÒÛWK^[à ¢½¯7ãn¯ªô¡Ò,ñ­lsÑAî1Ói<œìüˆÿ5e®‰Ü.-*/¯™¢ÐOššÊ×T—Õ^Óˆ¤QÂH#«¬‰@Z _žw”¹'žÖ€À±³ìåw.ö¨0ó½;“ÂÔémÖ{"ëŇƒÁô!T7‹z°?‡ «ŒðŽ;퇆çÙd(/Ùׯ|f…˜ÆE ÂFB±î¸«DÔë´ßK¦~¦øg-ŽB¦d¥{Ðê“ Wõ8÷yTâµ|Û hÜÝ+‡_)ÓO‚ ¾Åñ9©Ër]9Ÿ/0Aâz›7O› ­•êÖ^ö+æÝ[b¯zŸÂØæX”šTªI,ñ¶€küû6GïïÕgxK…É}#Îý‡IߎV·=‡ýÂ#x4”ÄÓïL$A™B…Ó£Öžxæò•à ¡%°'–ÑvåœûºoP2÷Ê(ÂIàÔöÜ'\ ?¸÷ žnž}ŸqEÖ:”³–VT!ÕF ñk/s¨µ$k¤ÿ¾’@ɰ’Â[T“’"˜<ÂTšø~J`‹ª·y¿7Ù+:Ò…ÍÃïÑ$9:&²OMSå¢k¶í–­mš¦aF0oⵑÝf¹>ü^¼s¶ÿarøùZqCxù$¡‚%î‘®c óRœ.­ßb¿ÎámýÎÌ­Ê ÙÌw‘ìígmf<ðò2šû ©òqÒOI¶›…‘$˶€Í²Q£HLŠ„âÍÐå·eó¥rR]¬I¬aÐ'L†TëÛüBaehôEöo× Je+œ ÜƒÊEAÂ\±–éшޥý¦ãw3­%êT¡äO¡¤X±6Ÿöºb|”Ö$üܾ6‘ýpñ©K„9)пçs«‹VåúÂôˆ2¦Û*8†…ÿ)›Þ*&H`$ÈËÉÁ+x7ë:PFø“*iÌW!eæ›e„y{×'jMôÈú˜Ï9MÌOç€à Þ¦{ƒRݽû‡(Ô±R½ˆâ?”v~ìw*VÌÐ:VÖdUêO9Ù9WLg Kw2xhβ0…ÛeùI‚½[ÃÝSÂæ¿\Êí ï[;(ŒMè QïÉu,ñ6¢ä Ÿ”#":}³mŸÃŒp¯«ýh-D šÓÎG¢ 9øƒU _9¶[ E•TW\†åáÎô§ˆš‚­G$Ó”‘€ÑIgQomã/؇ö4ˆ%Ü\ÓRKÖÅ À"¡à^L}eߢñÛ2ºâURuµËî&[¨oòÓ)§Þ(d«Fô8†:õ¶Ä2N•IŸèL‹_ë+Ï![¯‡OfÏywèGšdX 9M‰£ª‡IužÉfÑkówlÛ¡Í›N–ý³0©“l^ƒj›WÞº•ÑɱùÖ{bó1eEÁ0X„ˆýBº_HmúÔf¬”;—4ûÞÿVîÃ1:Î>¶¾åÁ¥P°¿€©hn?ŸÕQߢ´ubDÚ!ëbƒ#%Àt¥5æ3ÌÚ[pî© ì› ‚ùåkv†Fœ&ûyéƒvµÉ/ª `M‰výÐ|KÐÇ–ŒXÖø¬ÁA>wýÎÞ¾HjÎôÃ\W×w×ê@…€;¾¬ µty ¶Eùý Kœm3×\-8âdPùáɆÓ+âB¾¾ØÂc§A*BƒQŸëú8ŠnmÈ(à£ÏpMÅ ¢Uÿfñš[°*‚¢®ŸÒLfÊ2×&Õ©´üä<©E1ÍxP]Ùêd;øHÖx´"-ÙU‹ˆ ¤±‰"H3?·_D"̧М7 _ã[]/ÞCj$˜Mº÷èî)F~æëãPŠÂå˜àìÅ&iJÝéï˜{EðpSH»šhÚCù&ÿ20á;³)I¤tÂ+ü¦3ìæÃyш4®û/µëÜi-¼]ßJ}nëd@Í´>(Ò­ŒÞZA6qrtô~ɪÊ[v£;̬í¯vøvuágÌWÙñÕ<Ö2Æ)òQ€£¹®›ïgŽr¡Durb«Š ö²t²ŽgÛ;òÞÇ0DÖqö]0ß³uZ7çtm{NkÙ¸ (ºOT¢6z–ßšÍ%à¼}å-]X¨C.ò#2‘]>Í}´Q3 žUR¥32¾åP»®HÎ`Vïýa Œ â 9º†ìºïLt\¡o"×ÓÌŽ$*c½[Wö„Ó§65-ظ4ë8¸OÅKNåucòZ—è¼ïBHC¨TW"Hpkª óBü¿ï¿óúiäÀê›OoÊ{ô¸Ø^{›X´¼Kyâ!Qªz"Ú‚}þ šÀk1Æ·ž•à ‡ÛûŽ¦Â¹sð€  <]¡ñëÃ@Cjе’ÚzÂIº]ßò2æç]õ>_h'k.A­¦;äêN[þÁÃT_^O 7½ÁM@´×½ª±Eœl™&³q+ŠGd::Ì OÞ›I§\4:§N½ŸUØŽFæä¯eJ:ÇÄß°¶t®˜+ú[ÉLM[Ð2ù®EÖßïîÜ?ûÞšÒ£2 ]£óxK+º…ê—"‹šÉ½O¼mÛ#À$D,O>äåjz ¦¾3ŠNÒiý¼ õD1½1}×4æ—›é¶TN$ÊZIÔ>,~G:¤4¾ìTq-ÌÙ#¸Vlnq™tžýÓˆå{½òT._(ì•èù·¼ht:?šêRghú¹‚(£.T幃;ã ²é¦KøbÑâÞeIüé°óE\ñiZ™OaIVIÊeŠT’Rø~Ò‚ÜeûjüY‡@7-‡"6½Ø«ÄÔ¡’ÂÏO=ºEµƒ&;£=sén1ÀO»±O¯u²'Õl¶Ý4б2·D|Xnu?÷jÐ §Þ¬|³Vn~Lœk‰»,²Ãˆµ#D¢U.Ùþ‚öÅ8;!:ÞDË¡.*$á\K¯HKlÓhðÀu »î×ü&Bh]|s\~£9 -N‰šp ¢Þjè@ñü.|é ë>àËÑ”BõÎqˆë¼ëõý²©zÞúó›«Ãç±4Ø)Ü8”@gÎ"ýÝ%sµ~ïåãXÂ3>g„ÊP‡·šÔˆsÉê.,`S¤¡‚ç$¾ïò ê´ÐÆayòÖ/®"xiqîtô ‚ÝH“ GJóŸÃ¿²ä5ú6)άT ð|á¹8Ã¥K’åœk«Îœó½\—ãR áýy=D†NêJÁ˜MöjNïk\Ê5ÐZZ'fyC¶®túq™èÑ.n§ˆb{ã±&dbCÓêc·4L¦±¶QU‚m¾\„L ø ë´7‹gk_p¶Eç©F8xh˜ûUG»xFÜCjZ S™Ý£Zðù×âÚ>ùü®¯EW(çÖ±Uño0oBòÓaÙ«ÆÇs#•Ž1¤æûHhÁŠ,Ï­‡02‡é4#o¾«úÎUë¸j…ö]¿§†º—Õ 5™ gˆ÷‡F.wò!6A°º}½Ä¼/úôdá@Ó¥ô> V‘DƘ_+öD2} Q¿ÄðÝÝ—p)QÞëMmýÄ}­å¤~´[e×Up† ‘JÜQ€¦ß’ê"« Êk3v 3ž³0R»f’ZlIj¿S‘¥Sv»-?YÛ }¥.i[¼ŽGeW@®WUbêˆÐpÔ?và—P/D|“‹S]wù²X!TùGˆâ1›üà¨Fã­‡µ)=ÊXÂpjod<+tŒòYC€ÄC-h#Œï©<ÓŠÅG +Š Xrä}\z›5È%Npãï:÷¬ê;ŠæpŽm§blˆò£/Ò/ÒÕÅãø¤UcŸ~ÉÎ ,3ç\ƒ q£ I=ú Ç]åß[ÙÞҘ$ÉÜc<ï ŸÒ™Û“Ô5Íh:sµ*ëzyN@RðÇ:5êÚeÑÜ ÄÎw cpC·M"éŸÚÔa´“»BX´ïqÛ^iò ©„ÞŠ0d£Ív£SS˜?f“ôdxH{ ¨<è‰Ü9±+â eŠuÊ1µûSœ¸€³ âÆIcGñÓ>™6“3€QÞ-«*¹Yiá”Ah{ç`1é8h¹˜³ã]ñ…5+#«)u Pî†Èq­ÒÂÞÕê ‡i£æVxûM÷¼ézÓÔ‰© ìÚ 7á+U%§„¬Ñ¢çi("wú\úυƘ?©˜åï ]?mùZû"Œ"Ë1ÜøpóÇųdŠtgØë-¿þ±ÃÂ$þ¾I‘K%MaZØÅßù²Ã@ CZ+€C¸z¼72Á•a@ÇTHÏŠŠqÝqxÜêóóDŠ00â› Ò™(ëI‹8–HËq$˜Þ˜ˆ¨0¡„5‰ï|‰Ú‘°Ã0*YÏ«F8¾ýÖ^¾O& U ªu!¾h<*Þ„«- È+Àb݆X×™Pî/o»ž\u-CF’#bQH‹ŠnÚ˜ªYôDMÕ× Ë}ê†kDÕw¸}^¨‹,ƒ½±fýdõGˆï¹=€åÑÂÐÍ{ÝÑDAXJ€Uÿ´a3¹¡Ú~)LïwdÜÏa¶9éùîÐéÖ9a*\¤@Ò+ª 4÷Üïxï»ýƒ¡#$5±Y{òÍ»®RuÈr&¨¤Ü“/î,¢O‡¿l8 }ùL‰Êuï ˰è-­0mfƒ‰ âU¼‘Laf$>,Vyý¶°Ø(ý*ÏkìëiÌ4Í0‘¢©0ŽÕ]íI|Î^ø¯LÒ‹Ö)’B¹~. ûߊ-¨îlÙ¾åøÝÛÇ^ˆãÓ[SYˆ²n»Þñj™)D|÷¾\zžëÂtwKg²ÜV]Ç_™|!¤ó¸Ycâß*ÓJ{2|[‘–+#(£s Y}gå WïÂÉBä‘vù!§°ÉêÃØ–A c?#Ž‚rl'ÇT/¦ÍGüªÅ„ª!XŽÎþ•Pzã¡ðÿwhÂM¸29> stream xÚ´T”]6L(ÝÔ€tÝÝ]JÇ03ÀPÃÐ !%’Фˆt*ÝÝ Ò € >õ¾Ïûÿk}ߺ׺ï{ï}í}öuε £ž!<n U»"y€¼üEm## ?€Ÿ_—Ÿ_‡…ņt†þíÇay ExÀà®ÿ…PD@AÈ{ŸyÔ†»4<@APD(*ÁÏàçÿGH”@^0@› w…zà°(ÂÝ|0{äý:ÿØÁ ¸¸(÷éy(¹´AH¨ËýŠ`3À†A‘¾ÿ*Á.å€DºIðñy{{ó‚\HnÈòrö€ß烼@0gí=àÖAy}èžá_ü<À˜Òƒ×æü›#ßï2÷Û¬ì Q„»¸@]‘8¿ûS‚! àû}÷åûëp\áÞ®þ[v0WˆÝoO7¾'®0wO¨ºÒ_˜{Î|öP$@˜ŸŸ_LPu@}À|¿0òuƒþþvßsôwƒ»ìîi@avÐûŽ¿È @"<¡þÿø·… 00` µ‡¹âü§ú½j÷§}þ˜Àœÿ^~@ÿïçŸ?Ë{…Aà®Î¾ÿÿqÄ|OMŸ¨ÊkrýEùŸ ‚ÜàÏ#à ŠDÄEÿ®¢‚ýÕÅeª»ÚÁâ6{¿K7ìõ—ØÿÀ¿kéÀïu °ÿGæüÂüàûðÿYì¤üÿiüw•ÿ«Ìÿ·#Ogç?âìþ?q ÌÙ÷/Ľn=‘÷3  ¿Ÿ×ÿ…Cÿ\m(æéò¿Qu$è~ä]íÿÙH˜‡ Ì у!ÁhãO÷“ßsæ s…êÁ=`¿oŸÿb÷Ãvº¿=<î%ùGz?;ÿ^QÙ ‡ü2aùâðß+I@X༟FÔçøx]áÈûÀ=»@€óûHEÄ|J¿]X¢â>Ý,1ŸÁ?Ö}y¾?¹ÿíð9øº9Ü_ÿ€ø|Hoø ÷åý ˆ?ÿjì‰@ÜOïÚºgõ·ýÇU…ú@Á8 ³p°d˜cuXëåyož­Qé)–-ã ÿÄGÏ+Ì4ŽÊœÐUÄù´N¢¥Meös¹Ï ¿üšj1#›Sô[®n¬“ &¶ZpæÇ)zÇ äkzè°iyŒä¶~¹< qBoBmÓ`Éw÷#Ð{MzéÝ­êSÓS¶81»¥¿])¢‰{S6É÷$Ö"¤xš¥ÀöÕ ’‡‹“䨇púüÇIÞØƒFNàaœà[³5øŸ3~ËïŒ<Ú©™©Í¨èÐÏI†'Xýv_jPÎù—Å®JÏåòsð¢¬÷0 µ1I˜k©“Pò;#ÄU‡™[jøBLºð°s¶ mÜ8«Ý樸켽UT_ë6u[m÷Gb_D!¸ Ú^ ˜:¾þÛë ÎMÎ5ŽªÇÌýÍí6°q6È—–•~Eº’icОm‹µ:f—2Wùw9ŽºMùlû~ì-WþêI€ƒY˜–IHDZ˜U/Ê2t^E*d])Þb‹‚mÑÁa>@ýYåÉ"¯ûÉö­ÐQÁ°Y†˜æµŸ·7m¯sêX‘º°-Iƒ#8éÈŒüAf4wŠh^áì@™f•Äåc9EÈ{¹‰•CÔíÈ‹벂kñc{®ê«é†]™ƒèÓf¯"AA 鯴Ñ:çdÑj¦|Ÿ7¥Ìª{ w "{RP)h”GÞš²æÇ©ãv íÎ\üÀý‚ñ’ÊÁÍÉ®!JǼ"‡…Báf`ð´R¥SÖÞ S³´ÆòÅH¢”á”^hcûa»·ÒçeæÃ´]) –?Ë6›ê0›÷ô鯌­Ž¬ê 1fU2OšÚCÉf%©Ûjž‘d§m × üø)iµ­kt>ëÈkýk4.ÿóCݲëvœÕþe¯wÂÀ”vçKã Ŷéût²a™Ã%|^Äé»D7;~¥ö¹ò¼½W’–û|•ŸÆÆy/‹ ä¬ |МFwÉqþaµÄj¼L³ÜçOßðúø—‹J÷£åoåt¯jÓÛh>Ïd&ªh>S§ˆx+*Ga$*¿¤}­«GÍ+¿œ«6È‹0©Ê• ¬N¾Ì%Ûvì159Wžó,gh}#Ü×⶘¨ ÞZ´^m ¸)ÍuÓÿ'ÄFUËœž:ö4?Ä÷6ýØõ2+wë•@«9r|r`ðåç7±µ9²g™Ñ¶9ë·œ thÌÁ8Þ·6Ñ̽p¼ðì!DL¡ù'¥ñ¥O&¾õ–ÄÚQbü,'Uª+D^MCÒ;‹ó¥ßeç|o ⢩/üê(ÚÁr“»K§Ø í'æ Fˆ2âCwzôdi\e¯ê"± ˜ŠT lX~-‡?ñ:˜HÝõ¦ZÅÊ@ö%Ï«´W§Eîa˜V9Œ×±hœ@{ï‹ö!¾¢ü¼FÁ6¹ò ‹¢~‹ ¿ý íNj޵Ìãï!1Ê>¡¦lÍýeûÂQ*à iWÇOg0fÁd»‰Þ@¼¸›Ëá]Á`Û,Ú° jî—•A  ®:p¤_)â¡;ò\…c…uꆉxûy&ÊÙ>ÇŽéÁ†ùÔ‚{—m‹$¬ˆöZ|õÃ} ’ê„ÏMÖ2ÄX!ø@Ã}CÈÃ3ª-Sæ¯á6…çÝTs£)¾¶¥[â^XŽ«¨¿7rò9Îv´·ÍUK`ñ²Kàtl|+Ï¡åGKg)tso+;“¡z'cµççÃýÙß*yl‰ÈÞ¿oˆ¨k:/è_y‡TK1ZRü56HÓ•wß±ûÉLæÛØ ×BàûK۵׿cf¨\örž?gùÉC@rUv…„x¼¦ÈVDÕñ×·d_‡ «> šïlÌ…öbè¦!å´$¨Ñ›–¶~lmý[c cùÚ²L!*.œ_hEž«ÒôF§W)jQä¨b%¦ë ®¤ãcþ7U_"ïÝç;ÝhŽvzJ»ì¹mÿ%(õWAÌìW¢@6!ç´ñÔ-¹Ÿ•mÖºê«M¢ÔÙc|þ‰Vü|y ˆ*|;š‚à W$¢«³'—asSíµ†¯J7ÙòÑøùS7ØÖ½;éÙb=ë A™Çá/¨êìº,ñ£ÙTŸª` Ã7zÞcPÆ<Åý–>´ä/W¥ðp#„U9C¬£&³ïFÛûÉEΡPúüçnîœ5XQ¤©Íj'tÞÒ”+ÎýL;©³áÕ³fšv¿¥f©ß'ÛŠãré¦o"hò”,›‡V]<_EŒŠ\êîQ+óÙÖ™Ï4=Ë"¶Œ~úºö+u>F-ÁSEaõxÝþñ:~)ÃwonÃQ\GÝâaF¯pœÃÌ2!EJôÏ/Zô¶ÓäÜ•öº®lbä7ýeï))OG°IÒ݆)‘›9ƒAlÔßAf½çÚ’©w?D2ŒÚMʽdÒ§IõvuÌ&O™q0^ÔH²—Œ?¬µ*r'”cÿö=èªCXµ7 *FdµÂ¥a°Æ†¤s9—1ùÓÃD>X{!žê.R¼ŽÀBM´Ãx¹“Zæð|Õž/Ó§¥àƒÎÄQïÔÙS{ůdú!ådÝpMÕ15ÍCöDqšºÏøf 7Ì€©ç“º06BÝJ)LÄ_;°‰BŽêF%ëõf9'ü0òç´à7¡géWø¼•¯“W-û?5ÝúîèVë¸6Õ¤¶ ÿóÊO¥TÆ– („Ñ*4—2#Gýò©,½#uÇ«R˜¬m¿9GJÞ­dgÀÕ–Öƒ¡Ýy”/š$‰ÑÝfM»¸Äg-J*WTjíw[æ¨T¦t~¨Šl<>ïoÃl+>¾¢«-ÞÚùÐÞÒKXæ¼Cp^Mó3sÐQrf(B@ñ3zûZøµ£Q5KÁÔÈž(ãÆgŒª@ £#PÆhThT^ùšyö´}^QËôí±I‘52X À!?Kà¿Zrùmü|îC~Ry‰Ÿ§þPiºáœÁ„“aÇYçˆr>Á–Ôq ²” Íû£§uO1:-ÿ*•à[ë6—.it¾ÝÕ ý“³O»³×8'lêØ:^·lȺ;–drà ÆdMUsåÖÈ“ôMÐ#^o´”аª§*ŠÏº t‰"ªI¾«þd‘ˆ<Õ@ÜÖK­°—Û«Zuv×Ö<«ôÑÛð ÖÜX™¦¦ìX3½2 WJaºlLe&“µk¥OÿœµHÜ”l2ô¾µ#x“öÁe =–çs)®ò)yc0Fæ‰3ü-#¶‰å€‚#®ƒ$¦¦Kmñ„·=F¾h{ã€Íê;È2+ö›OÐâç ÇÏq'™.P®«×>õJ> OòSY7úaŒ9oH«6˜¡±^œ»Çñ쎌%§ØÖ¼XW¶ë¤G’<ÏÀ;rµ©O¹Bø,S®ñV@°äÌ{u‘¯qh©&hlè]ÍŸg±ÔþúòÞ4ö‘˜&kñä0AÏXA4£lwá$ÛúgWÉR{×í¢Ô¶òá!y™Þj™LëŠì\ó±¡ÙH0ŒMŸ|D«m«M*¡oF%?³UGe>WåN»Ö¶ñ TÝ/Ê¡”å'/=\ùþ2ëNt]—QLaðc¼3êïüœ~Œ¢nÆ3Ê G³!ÌPv„ßLªŒ®õTÛ*®Œ¶>û-_Ê$ ‚jâ[=ë[kæÂf$ø´&å¢ÚäçkÏ/.S\ËDÜ+:²¨€Ž¾S¯Ç3ô PP7jˆ™ö:%Y€îÖ0`´8y93TÀ.ùÝÝŽ?âèû L à›jWúQ5™^~';Ù=Ï¡Q 'B 6%}ÃÐRÛ‹ŒfÙò§l• Ÿcrz¼NÎõ ì¾Ô–g1Ú[ŠŠg¯_¼O=çŸdBdÑxd*¾ßF“îœôÄ»6Ÿ¾ž¶’bä)2ÖJ]Ñ&&V瑹¥˜IUÿŠŒ„<Î!ÑÿÊš©ž€þ¸ 0Öc¿ZælQ Få*© _R1v…DhŽ˜zfÚê¡7„Vxeí€e­íµ„ÍàÝðe²/´%y5Ï'íò#ПQ®©vÊLßÌ׌Dqçå¿ËØ´w°DS#mEÏÈ›·EéðÙ¸aîŒnì ÀÐK®CØì|æÝr›’ŠE«(– „ÈæŒÉ9~˜q#7Z«bL4 Š.Åú‡/LmJvl4¬*×èЧÝOöHÅð%xOÇúhÚ8»Û´´/Þõ}ÛɶmK-ÒÖ¤NùÛÂ5³Õ·]'ž„Ái¼gìéN“;fâ’ >¹ÓÉ—³]•n£^ÍÂÕgŸZtc.ZÂfìûcâÌ­WÍê¬#hß¿¹M.¬,aÓó&ÔŽbÁäR–ðŠÅ‰d Coœ*ûV´ž*ò¡3Å‹·©qÁ»¨í…Æ~ûVÊdë±s—áî~dæ:H×U’-¸Ý f[eß;¿."oH3ül¸Ë«»]zwõ°2 }CCìX&Xj'€£“\'!¨¨˜(©K4èÅ$DÑ_#/+.Ý6 Jž¢ê÷'»ºÒj‰®ÿÁ¨µíêùª(ˆê­ÐbÞSóá5.Þ×Öá¶û%ÌÈå‰À}ÞúÀÙ¾©ðÄM¥ÿ—r)©l¯Ã‹¥ÆUŠa¿Ù³H©+Ü”“—ýão–Qć+Tu!L9¶¡ÈúÌÁ fß½ñ²Ù‚§‡Kã—T³“Ó2o–7ùÑs‰Ïƒô ’Œ9éÌz³£us÷ C‚±økö‚g@ ”Í¡£³íÍ[†aU£i<¢/B±¦{)x:²9)Õß'øû›"ä£3Vͺ¿àí>k rçÚ2EÐD{:ÛbÓv©¦§‘ÅFä¢4W±·eÆ–ßeúØ QµåRŸëƒÀ…Øã Ŧý¾ÜX÷ξ0L%ÅN¦_&Øv^wò1M±qׯ}yì-ë€í1h𼻞\o9ÀëíRÖáÜTw‘°.ðNåm™ö”°‡*i9|C§yv²w˜^«ã½ºài)<·xClÈBu93ÛѾ®[¶ÝŽ¥cÉq;>áU‹–eÍj‘Ò|±ŽÕÌ‚˜'pTˆ²°ÅœS,Ó&èØ¢7jûëêÙ¯ˆ7„m?Cu¬G2NR>,“­& ^Ž7…>Ö‰rÊ7ÀJ8&'uQ*÷D5Ìx°Ô½Ñêú†7Q÷„¿u`[öHž+@Ýð0¢IøU©Ò­¿ÞE2Kgb}=i: Qâb²›gÚ– !päGÙ}IàÞ “ˆÎæÊt%÷¸€ ëÇÇð™xI|Ìb±Dö˜¢Gð;²Ît¤ã8õjíœÉ¯ço¿„Œs]ÖÝìEõ2ß)MNŽZD}MX´Ý)U7Çä Ñ¢ž‘L[Aqß,oMIN×Áî”—ÉÑg*xäF ´×[ìDO=Àœ«}J?À¢NûªœšáHÈë8~¢•~«2 Šî½g‘M*òžâüÕe•ø"Y¨$¸4«aÝG1Œ‹ëYaÔ ^Ý'k’ëÅm5:{E5¢Im[›o.¾ž]“G;ç“ýc=?~½ñpþuˆá’ÞýȺAq(m“ÇË7t¨ð=)‰«…9%FmûáÏC×åž›;yõ û€¯¬è¬¯¦çYAùÛ†#$RÛã ›YCØSI#ÌI­¦ü}:Ê·f [°ŽQ`…'Ù/?«OëãX>\O{‰OðþÚ›Hï&Ë´µÎר{È,K¡wÌ5×I ]#ÎÖ÷$Tª¯éêôvÑ^aŽb6ú°‘L™ïgØs²D„5Š %Ë µÉ»&8Ï«ïÈz>õÇ?¶é)‰ˆ ðü’“ôV°{m<Â6PË4. SÈÜs”‡3Z[Øs‹‹ÿž¿ÿ;1ä˜ymuö¬UôÒägwUvÖxYC„0ñiKºí“]©¼°gÂÔIs¯üHH2ƒÇƪðLkváá–u!!#2ë¦- °´ÏsCãLˆ<¹eÈÒÉÞ¥3›÷ 'N:.J?›Î–z´¸+]Œ¹þF½:§Öí=.µEëÙ¯€Ž¯¹M8…¢:¯E~©¥l:ïb³ðÇ›JìÐ&>ÕÞ4U#°ºv-/þ*z¡êGEø}öÒkfC³‘Úou-)F•´Žb“¢9!!™ã¸¯7¾àˆ³ÓH;¡&§µ‰¿Ç(;¬ºæÚíµoHÙA¸é?V¥¥m.ca¾˜’Þè:EkrüГ…²ªÄÌË–(JRϺÓ_wé–=0¬) @¥êÔ dƒÅ5~‘ öU’ªžï•rJñÓ Œ(3{WŒ0ýèXOƒ…¤f¿úìéÖÛj_Ç=ÃQ¶È–áøínµL°ìäÔ1»ÖF«Ó,©&¹¼PŒS ª\ãüºŸ›JNl®§›S¸ÔV(óz­5Ä$1Aߌ2°y—·^˜|IŽCqÖ£ts¦ÅÛÎ N´&mþ/Y–Ãe=øñvZŒZ!^W†ƒ¥¡"ÝŽu¬Jp77÷IâÙT'ÏLÙJi@®w™'Ÿ¿Læ}¨š[‰a˜ºÐ¼"vYkÁ[/,¶7[E O·jÁ܇ñDá¢SóD† Ÿkû¡”Ù²åÏ èË:SÞ‹~ÅN™Šÿf®ï “Kvˆ@Åo’¢ßsŒÕ) ºceŽäzqzu714gøŠÌûõáËÈ[@½QÑV{^®zŠJõv…ðí¦1åB‹:õ·koº„Íè@ÔØ¹òÙ™-5Þ=—d1´³ò¯'8…‡nOÌçj®·Çò39êÌØvDç7ý«]ŒŠs/¨Œ9®Ó(ØUm …-¯›˜‚TÅ•·èv<†ÏÞ]èëGûDòì~Í%Û‡Sñ&… -xbÖqï‘-|^ _ƒCŠwKätД Â7upÃXA|‚ž?”õeÿ»á­EŒ,ymy~.¹³R%»À>÷ÆQkÔF ”ßkаtNÚº ½óåNãxUïÝzYKZUd!DŒË*Öaœ¡óõkK4¥ëëÕ¥jÅ­‚u4Óz6õÊL ¥ê h“ýU­kxlõyTŸ“p?dî¿Ð€“ÌXT‹IV·øm6ŒÊÙ%R}\ôéÚ5YŸ|§œáÆ{Ê«]QAØqüC[øÁÑ6c‰uH÷añÞ—ñš!ìù7@̪ØÖ+Ç·£IH3;ÑåÞG6ÉñÓDïK»:ºç„ù†7Ã,QYùè ä&H²’4õËåSÅ(¿ ¾­Œ/>®x”^1 Gë~qƒ|±~öÊ—){†+-Ç1Oi"õèlMÛ=ŒÞuâÒ±zÙÙÆÞD"ǚؤH o7Ãø¤ŽçØ8'ÂF\]ÜûÌo3ÿJ÷Ú_ýS¬×–)ý\ýI!qëêñ‡à!…¡ω'¨ÆÐL)< +ë C­EgàGȫ祸1«Àa«k%SãÙN%‘¬"TTr›õ3Qéw ¾’ŒcùOÁŸùd鑼‘F“çDÅ:¯‘æ°£E¯À£o¾cøª-éUX=Š(»S'íÑ„õ­§,Ôä­êŠÿÊ]~Áj —`O¿fùÙa¿© µüƒ§°\zk0˜nðƒö ŒÑ7™-`³Þ|†u2ÕÆ!ÕÁƒäزH„¸Ô=ŽS›óÇÆ¡ÂØP¤Ÿ³ ë2ÚR[ z­|ÉÐýÔUÒì¬lÿ ‚?&Ãíåõ’’OûcßHrE'çPM¤œï[òîR=Ó­>›ªtLm&îãЬ»zö‹Ø‘|F<1l‚­W”N[×6T¬AUóÞ Œ2ë&¢öfÅ%ÕéNÛYj¦ó-NkY×Â^îÑõ>VÆ"±ØddQ­ÔlkÖåÑ®(—Ù ö™ }¦F,ʹÍŸã"vø )Z³QñÈ>2iògâZ%x'ñòKA­j#÷§ ½n½[6è')“žÛN_R3¾í-E‰Ì¡Ý¹àöDѹ¯BU¥Ÿç9é|*£®åú‚HB¥Æý"¸´0ÝðHÏÔXýÕ…¿þ¦ð¬S÷IE¸},»º\V³û–¦qNN|ù&ÕMÙ09ÆøT3j¶Í%?ìÁdèÞ„âc”³Ö=ã•§3d:Øú¹¯Ȧ»“vu>OU!Ô §CQB5ƒ54º`|’Š6×á¤o!´Uì7 $AI¸,{=õS“g€vHdÖSÐ/ ±¢¾5­þukR.ùðüÀ¯Ð´ìfõ@[è$ÎÚK>!Œ¹`ù3Â'bÀíaÄ]w‰7JûÍίB@øÈÐ-· Ñ,‡1ô]^W¥¢Ö·n½çÃÊ~Úhn—Ø‘}ø7­Ú‘¨ñ8ý»½C|ŸÑaÜ‘Ji*}Ìÿ·{ð endstream endobj 100 0 obj << /Length1 2710 /Length2 12716 /Length3 0 /Length 14253 /Filter /FlateDecode >> stream xÚöTÕ[÷ Ò©„¤lº»»»;¤6°iØtw‡¤t§ Ý-) %t·Ò w{Îyžÿ÷qï` à™kÎùÌ\ëGIª¢Î(j6Ií]Y™XøâЬlv&6dJJ +[ÐÿäÈ”Z 'g+°=ßâN   D&t(*‚ír®¶Vv++7 €……÷Š`'>€ÐÍÊ  ÈÛƒœ‘)ÅÁžNV–.žÿý  1¥°òòr3üeµ9Y™íŠ@K„Ñh P›Z\<ÿã‚FÀÒÅÅ™ÙÝÝ hçÌv²¢e¸[¹XÔ@Î '7àwÊ% èŸÔ˜)–VΨƒÍ]ÜN D`ke ²w†˜¸Ú›œv€º¬@Ùdÿ·²Âß €Š`ebý×Ý?Ö¿YÙÿe 45Û9í=­ì-æV¶ €²”“‹‡ hoö[hë †ØÝ€V¶@ˆÂ_¡R¢ª $Ãòs6u²rpqfr¶²ý#óo72KÚ›‰ƒíì@ö.Îȿ㓰r™BêîÉüOsmìÁîöÞÿCæVöfæ¿Ó0su`Ö´·rtÉJü£!?Ë,@.NvvÈò0µdþM áéúëõ·’ƒ¯·Ø`Iäke‚üAövº.N® _ï?þ‹YYfV¦.…•=ò³wˆdþ7†ôßÉÊð–2~¬–ß?ÿþg™03°½­ç³ú_-f–ÓS•Ò ÿ'åÅÄÀoFV#;€“ÀÅË ðý¯ Õ?Q°<[ÊÚ›ƒ¼ ©ÒÿvûghþYZÀ})!s Ð<¹> '‹)äëÿçaÿËäÿߌÿöòÿ:æÿ7")W[Û¿ÎiþVøÿ9ÚYÙzþ£™[WÈ(‚!›`ÿUµA/®"ÈÌÊÕîÿžÊº!» joaûo!­œ¥¬<@f*V.¦–ÍÆßbÍß{fkeR;[ý¾YŒ¬,,ÿç ²\¦6ÛÃ2’ »ó_FI{S°Ùï%cã䜀žÈ,Ibãäx³B¶Ñ äñט™ìÁ.$;_€9Ø ùwK¹8Ì¢¿E#.³Ø3â0‹?#³Ä3â0Kþ‹¸YÌRψÀ,ýŒØÌ2ψÀ,ûŒ | ϧøŒ |Jϧü/âð©<#Ÿê3‚ð©=#Ÿú3â0k<#HîšÏ®ý/â… à¿ˆ ÐÎ2÷¿/¯ÿI9 L@gȨX9Û<Btyö±4yF  ©³-ÐÙò_)+$H' )Èdîò‡˜óñßKô¯Ö¿Å6 —ÿèó²ÿ+ÿ?Ú™þ‹8!™‚m!÷o¿%vvÏùþžDæçDÙ!m2ÛÚþЀDzv Ñý‡”ë÷¹£+d£ŸM Ù›?›üF`×?]B°xv9·øý˜‚þT„ú\8H,=,Aöh@dV@H`Ö@H[mþ€Z<ÈIÚö÷²=ŸC*g÷ Y! ÏTœ_ö%}.„ÚÞÕÎä÷õhñGHûžü4Ä'ø+VÈ]Íìð| áp€<Êöÿé-ë?Òÿv–d*!ïª\ɬÀ *¤°¶®$ùpav|v©ª£+Ødfò\ vÞ„ÿ¥de…(ÿÑVHÒÏŽ9!FÎ ;«ÿçoÛmâ„8q†5Ûèà²Ø®ù¤Góá.4tÀ™›l1øL¼¼ÿî¬àʶ+ßÕ¥gÌnof{Ò¢öÅýRdšö5ƒãÙÎlÖ´UKÕM¥å uÓ&T˜¯1Ñx<<ì¨0!ŸD³>U‰ÕŠNÏtÊR8Ÿ‹|=zO,up—Þ?ÂÆ¹9°XÆmµ‘Nxxˆæ ™u(”¶ßËE o<˜¦Üî•ÄûOtÙHcâ<ª_ÌA`®qÞü½ØU™,$Щå¨n[f¼¼‚mkJøRCíwÅÛ„&ŒE1ζM'¶&Äxš]FɈ ?1‹ª±ëbar]g‘½kêÌÖ’iôIÓ5l¤½NÅóÝÆÇË-§«åWÄ9…\Þ·®¾„4HT±NÍ q— nüE-¾@ú@{÷@ ud¨‚ÉcZæœ%™ªo’ Rø¿Â¤ÌL°rÒ –ªù=R¯îå _*!Ým~´'Ñ3Jo“5 àTÝE(§2ß 8ôoæê“ îˆö'ûŸ¤$Žtf·›S­ñ)pÕöï}K“jï;ìͧLUsÆ~ ên¤»5ËÚa^a^Á ¥îÊ(;™ß=¨•©.tü¦–›$Ûé·ÿI´¤2¸ŽzìÊsX;IެÎyµzØ„Ÿ+ÂÕ»Bî,±“Œ˜'=£\ÉO9·”¿L–T܃}'À‘8„ ­›Ž(\Ëè–¹w™9§f“áwã~tuY{úa³ƒNzÔWXÚ¿ ocI5ðu% ;8Y²!ŽçcÕׄ‚ƒí SÏ÷g¬C]•!AÑÔçš9®³;oâ¡0Ñ~\e9ÚŽÐB©läÅáu|­¦›Êº~[I[úqZJ{î«u͸`nôþÎèábœ½p5oCÛ»‰5rƒýl)¥Ëú®Ä$É×ÁJ‚ùøºóÊ 3þ¤XÖÕJÈC”ò€«~ós¯ÄWØãh¥Ê½êüúy 2½ÍúA-Xî|œª# ²øY÷ùÇ’¢zÝ×R¸ì†zgU™~l˜¢×¨mݘªÔÖp`©pº˜¼ÔÜ>ôG¦11%èÿ(îa’ ¦šx¡ê2Œ»ª‹&)®s~$ZÔ¹rœ {e±!ê«:µ@UÜõÑÿÑ|’*gü®²šâWaäEÅ{404Uê2ñOކX ‹Ú—ôY$R¡•ß wÎÞÅ›é|z—‘€Äýs °/¶K[Ê®f•"¿1 ›ƒr‡]5ZW |8èt"Ì7²ïí%Á½CH5þè°ê·ùg¦Üp“{"!²÷Åhùf+úއÿÒ£^)l»_c$ºªð…ì j4Ý](YÂk0óáÊ Äë¼CNïˆÀ"fÞ542$3”¯*Ët"䌎žB¢4’3ͨF÷¦Yûñ21Ý(Š8ÃÌkƒê=1»©írjl¯D.EÖ aé³ÖÇÒû8©¾z·Ê¢ÃŽÀQ†ÇYÜ;ã³·_·Æµæº”f­måÌ&ÿxå;`‡°îªX£4>ðraüŽ“•^/ƒëW£œ·ç(œÄɆü-¥ ÆmçÆÙH®yX®GEOg«|áøå:ûì:W×ìkØ«ôúVTÜQlåzÄMM ó[`„^ÌÒ CC/¥i²O™ W¥Aÿlº(s%7¾DE8˜#ÎQ±kê|Ã7¥™•ñ¾è€‰¶wBû%âÍlŽ`ƒûPÃå `'(V4G½D&’++—CDÖ¦(»ÔFÿ¶ÕcŠdd;!‚Æ.'Ù6 MáÚ¤±‰*D襢²}5"ÓpÑê†,RÙÓÿr;4,îÍýz‹ò ½9Üyܺs}`<Šëº¸Ñ»?ZØ;×ÈÃ3´¸,|T/ýQº<Ç¢7Å2 ¹B‹·3¢9 «a©0AȘhÌ‚­˜À‹¨ ®að•r4jÀP“7–ÔÞy6Š“W̯}Ñ=ƒ+Ñ\hÍüÆ™£¡£\ÊmŸ¸7ð¤ös÷ÊvUåp’ª»°ñDG·”)U¡¾æ.™uÚùÇÕg4zg1t‘V¦%\AIµ~ge¯)WË>_X>Y³{…EK^ŸåLP¾®ørNrë+¾U÷ësè“Eù›J–ÃÃô <)åR8ñÂkT\eE±êküBTZäO™¸oËFü¥ÇÞ |{Za‡'ùxõ!ÿÔˆX×ù=ËöëŸeX:´Weôy Ð0£âÕ¹Á5Œog uÍ[|` Îq¦Ï*ïqðr—„xüz±&ìBíð6µG¤`û.טæÚ"yÞ"8j¦¢¾ŠCTrÛ_ØÄКÅôhš£6™“fŠ ™±Ä·i£ gO ѱî 7™E0rœßæÊ3¼òjÉ6û\Qʱ@xª{óLŸlR7dñ› ä5;Ø»©ÇNáöË:–áƒeÙ^`®uð2øqÓç= bƒeŠ  WÍEô¿ú±+¬1¾¼á‘ñØnJ'V†/ÓJ2'Ûð¹ÏŒuÌÈŽMpÇ$†Kæ(õoó”Ê×¶¯»I‘n‚Æ2WÏÍ0¾Šõ=XF•—¹¸]âà­tô¿E~âZ0¼O:i¼ë=s˜GøŽ³s¿Ñ¢ò$»¼¬”ÙiVÚCºaØè}¾yΘ£j‘èäfpmuÀÏÒÁ/oª¬òaû÷ð–,Ù-é?¯à;ž/_ÌôÓçÏËßÃt?…«ª|ÏȇCAò9*X1ôfrlû®¹.ê’ÃMV± Ú^-½{7·(/];!½¥áÎy¾¯÷ÒgêÕ|€òš½A¦z™E4mñŠdq²‹2O>ǯi¾ÂóTÛh® Çœ1ªj!ùÁÇ%1öOh Še`>)‚ƒÁE²Í “ ª:¨.oŸ‡Ç1ÿXqópÛ­Š`iŇ|c }ô™íÌ<àù©^ß-lÃìvô£U]¨4ç}FÛèr»!á/Dc3Qs?ÄZ‰o‘ç¡Þº¹}ðƭ튽RBºMÍæY“¿—+uwÆØVãí»èÝi‚ë™.ƒI9ãºûì¥Ó)œØöerˆ‰fqÙaCÌæjl’÷l柈 ~ ç V—ÊãˆÃ³NÎæ>J¾O®ª•AôEˆ2_PÒ±äOèa¯ö‚‡]ìëLˆI± 3女t2%®Ø3ÅÙãâ”Áª†6$ƒïeÅàb·©EÅ\ê?çk»J˜óGš4µÜµÛ0çÀ<ø8í´‹ 'yì)b*»¾i¼Úº¤èÏI÷”ŸÌd×ãÚ¹€ªZ—ÞÃa-84Žs‘“Ð;îfzœé‹gITáࢴ¿'í­Aó޶}2Üj"í;\pÿdäºÃ²n âþVËïLQX üu0Ðóô ¥ TDKÕÕBÙkÝ—!åPy3|dLîå¸?°©# ŸÉ–£h€Ö8‰?º8o úr\r‚{=Ñð‹.ê¡Y *æÑžƒ˜±òR½‹aÎâÓMT /‹PÖc“4.‚¢…Ãêç|ܾԸ†R¥_äÄ^Z¡ïi/^|b¹ÊdÂ8¡98)”âWwY»hgo³Å<_·ôEØ,â¬VÍr¼9Wîqƒ×Û®]cøB4†é<. íbH¢ñV¤e…FG“~„[¹žÊn-‡YnG|«Z?9 ß¡—ªÑZÂ!,š7é’{Þ†`ãR/vß ·¥í‡ÃŽh׋Ãs¬û‘<-ëó„äõû>‘œö¤wIク٣¨IWài]ÑOÚÐæÉ~WM»ÕÃå—ÁR²×BÿÖœŠ«€%œWêKµ9.ÚGÍœÐy.=&bÇëŸ×‚„,F‘Ñ”»5¬;ÍŽˆbš†iiº*ï}D‰Ý LrN¯ o²•h£î‚J>sáÜEXÏ¿zu’5 ÁÒâ HÉÛèEÜžÒMIº=I-w?Œèx=â™Ò¿iOÖp*Œ½(šj!ð†žðÀñšcõå÷ŸB ™|BµE]ï[ÚKMÛÒ‘»ËX³ÏæZ„A W5–Gº7ø%uør‘[ôž~¨‘0·%_R¤mº§i[Ó¼™Ï`+C¿Y왩*áàë¸í}LQQ³ .C JýöÞ9 ‰Åó)Hñ6< á¡j?½‘_×ñû—JºõyÔÛ•Dú,š2$S§¨¾zì^Î÷ˆ`ç‘Úì0tO¶–ZÕ©¸¢÷ 1’T<ñáÂD õú,í„‚uÒ%õì¸W©ïÉ?sjø‰†ßÝm/º( ^¢ %Ku¥ÑE46Óû(ò¥Ätå}˜Rrb3ý!>«eδå|'¤õ È–gp92~,ã-$×Óó«M˜ûu×ÂÖ!Eß«¤¤ÚÞØštúªœËÒÓÆ½m ]y¥åWRJyp–˜AƵ¶ð ݼý¡5õŠ"ß<ã‘EµÞ#u‰}eA\0ålc¶rð'ŸSÄÏ¿_G'¾þ(u·u†¾~·µT]à®w×±ÜjV,j®Ø.C•*Gúq ®X!ŒPŽe9½›*øc[7šoδÓÈâÆ ’8ºÔöIºÚ¥Š–ò¸¦²êÑ€;ø|˜³Ý`ŠÔKg¼Ô’}#õ÷}Ñ”/(O+ü‹ß»c~(T£½¿ Œ8¡ðLÎÎc*°íç±.gû…ŒÅt5‹n 'Z­¥8ûÜ yG–êÚ¼´gô“4Æ8f/>¥¬;åc¬Ž½1.œS!"~ú\æhJ..ÂT¥y‰4Úl?ö9£QªÚ|4¢Êv¡ª…glúw£„¡ën|à+JY9°À‹Ë¼›ÝŸA+Á¢–»Nâ0¿jq9a`GvPÄgT xö… ÷q–ì±›¡“EJ2W®üºhcOm€Wœ€75Îö¤ƒgH÷Ãb*wBȑߛÛ7ꜹ±¯FYÆM;ßÙÉ {è&k²y/é)5«QVa29ß ³«sNiΠA¦ógU¹X6”¤$kp¹œ“Ê-ôž«*ÚžË@„#ZŠß|# çµ!Ë×h¡fBÈ:6h*‰3솓†JŠv³Å"ˆ° šä½ ~Ur‚oÒ^! )$¦¶ò:±²,) óP\¾+ý^iø¦r.oQëÕLAOSúºe‡ âx@*›U’ª§rSÙëÊÅâB·H$-<:È·{º@m„ÎÔ^‘¼Àn¸ãœÔ8ý*Ru…ì §-|4ºê;äe­ ê¼A«jsë+"Ø(¬¡Øî¥™Uóa•èµ½Sbx ó9†¹þ°|¹´·OôHO¿h¹7{ŒÉQ5+àËI©ÀëV9“` Öë&­»¤­N›58YïRëM¸ú2þ1÷ªG¥i-Í'i¿¼¸-}Žm©¾cåÛc VÃn‰C®à;ó¤IÞ!¡ˆßxÕpæiö{nó€ŒÊ‡ï/H<çÚ{üKìësp¢_ω?¸X¸hOK[L«-ÓamÌà$‚ÖagÌýe{µ“àî¨+/M¬Û/Þ¿mÍ&›*+W°ž&=„&¹È*¨EÿY4¶-;%(F«°+¿p}LÏ'Oâç¯Uz…Ó¨Ía© +.]€.¢v§H¸hN.Dþþ=Lö-bwÞ¯ä¾iÔÛöVÙž˜—>Odtitlð°…‚¯ÔkÓä¬ôíÈú:¤¢—çæ²:¶~½ ¶ñRÂb@»éKdÆÊ´[)‚ÅHN)îá_>Ðô-”¿¬óã}*NzízÃ>Lù=r5ÁŠ)‘$¨>{ü#\zÕvòÙ¬ˆ«òf ‹61^%3}e´¥ÙÁQ…ŠW.6ƒê•Óì‘”3¼!Òñ±$òa~œ*{ý&xëÛI+Žõ+7#¢}¯ )äjåwìNƒ·ìvñóèùq¾2êX¼ñR shL•а'¹í”Ph®~M*^ëéÛN6G}c>öãˆ{ÑÜ6küaGžC1~ן⣊ò Üi¨ÕCSgØùEÂ€à £¨(ÖL–Ö‰¯_ƼóÒ<+Æ€Zã[^I6ôÐmíÐdq¿ÿqáîg'M•œ ²€ù‰µˆ>þyvRHIäÃÚ„¹ïç§“u|¯—–¬¹Æ¨Ð£_I]Ë>æñ¡£€q76ÓÏß Úü$]:Õç1ùø@áuêK%µ‚^ãq*U¡\býê4‰ý„ø3¬?StñblH'VuFüxщi5ï'l|:ÛÍG—u8º2O©U°•ÞàÛ‘›4ÑkQ“k.´³¹„úÍÅZHF‡`7Á«“y½£שXùã§ú'S?Ë+a„úÕCô+øüŸ3CÌZ¦ŸTÊ|7è Ûñ²WðëíêÆÒaie3j·¥Þ©ÂeÇ% ´ÚÔì¸DR¾ëõ}ßJ†…p–{Uõa¾Ís{BƒË覆äÌôñõÑôÀ‡ÈQ“¼ËèpÏ* |¿«¦­¦ôµëÀ\£¦E qÝt8'6RÓøá:~ÏD¬ò<õÖö%e)öì2R²Æ°Ì}˜÷T%¶ï¶[cÙüKÔÑo¥ÈvC(ŒØRïÒy'b¬O“LÝ&«|Ip|H宯‰<±7;i$Ó=b>e¼­ZûT¯Éán›ßôsPºOØGl¦­çKyÕŒ$*~äôvÃÚe¹ô ‚3Ðú¼Y>F2b*3ÕˆP|m¶¤»"»Ñ’Òùz䪢ƒ3ÎÅŒ=Æ$ä°Šó¤²á"ak„¹ùî²®Èçœ^êɶ.`œÆˆùÈ*ÅÄCºžf‹Ƹaõf,w°gJõ˜’[çÛz¿Ó#<¦Àeô %ÜÓ²îfuAàvª$ŠÂz~†ÉlúÉ·ŸË[ƒ/§zƒ:ZK¹+û ]ó]üß™*tùøë¬¢‡Yë*ß`Q xÝyM†¥Á߃Q-Š‹»D¿ßÖ¿)rÚFg•·âôtnçÝó¡‰Tn§¿*›–·7t·Ý“DKu_¶^¥¡Ç-°¼Ôá'-D[‘ùf®ÖisƒÒ%µpûñq¤©Ò%šëêÛkAËÞÐ.ç·ä…:í`¶8¼ ´Ø4ʱ  ODÈjåÀ0Ó[%¸=K»S်ÄóË„}£q©Ó!ù]¸7*P—x+?}Œîa×`ˆÊh˜ R¤ìY )ø„XS­K¹zîÐŽû¹KyKv6ânmé9Yz”XïWM Io2i¯¨‰áU6.c^)Æn.!ª&S>¹“ßDáÖ¢&M~¿&q×Å¿÷›õõ\9Ì4ktÇðE.à-AaNݯÜg¶(á*+!¾ N4ÔšŽÇÑ”§~ñw%ÙDV³ŸhˆPzg£ëCôèÁ®?¨ª\•5£r&C ·¼T÷§˜Žêl¥á^ì£÷ZS!”z8WŽ\’`–s!4¦³—“K¬ûtfˆâîéíªðµë› ꣵ¶3ªÌ:·Y!a-üC‚þ(éE™ã¦G³AØÂ[¿u}ïé­³íºX9Œ/^ 4üRÃÿ®[,`´Ç¦bèkÿ«:y´â( ,jSmÏâuëW4öŽ&«±}ž{f½…\Òš VwÌ´§yš¦ÈšßhFx-^ضûwÌœq`6ÂÔªNðÃGÛ«Ðê'˜. ĉKîµö£q±×–z$ðãž§*ÔöÅÍŸ)ÚOW¤Þ‹=x¤+,¥°e{ùhÍê5° …©.,Äm’¬k'„SßwÉ“Ž"ÂoèÕÌò‡= rŸ­!å}qëÿ¬…Ë2Çu(gü¬/ài^Œo¿C— ¦mº¢ß¿}¥msŸwáâþsšÙ0ë"ÞZ‚¹‘ på0³¢~™û¡>ór´†EÔ‡ýà#-rÖ¡Á^ƒ«77°UWhãs~ teK…Wá=é …“e×w^›iÿ¾,b]Æ/]—+¢TnCGL ¼}t5ÒÞÇÕì9YFQ %šÏ›Õü&Çèx$ôoaöÊТ¿8Ð,†nDèX6\]6?ê>ž?™,‘„¹Å ç›(R”Œã÷µ7t~Ö*ðš·(Ó0ŸÕÄÙ`Uá RŰ&ªäNpwõ ~ ‘ŒG",áz»žñ¾Ì*ž3SkAp Wîqñ¸‰u§î懱qéØq‹¶h=u4›ÃʪÁù×üÔWÉcΘܾ4ª_Àå –M‚>– "i `Ö©RžÜu(!åc{×0Þ_OÚ¸·¯Ív’uášîA¬.$Í•z/‡œ&}îÔhoS°%·Þ¼Ô’ü5]Ф—ÅFôJvUž)¾âS9±"ÚëCÌp¿†ÏK|ã]Wâ¨CDáÝ݆Ár[@ÓÙS ™õT‡§Ü¯XŸ†|œ±”ÞµÒ,Û8¼U¡¨—/>¢'}ቆ‹í¡£ñ‹ñû»… fCßëm,%Bo?W@R¨¸51jâeØ‹!3mœ¨†&SnÕz[0YõíåÐÐu‰j§ÛbÁ!/ôzÂíðc³ìnmÚk˜ÆsüÏò”¥ ÎSú?uM]× lŒò¼³6;±ýóÚžrÍ;¤•Ï–~zåÚ¨_«J—ø«Ý×t¤^÷º§ƒôHŸ²kŠhpôÚ°Z7@+–S‹úqúŽžùÕ<Ö¦o§YòJGx”ô2‚C÷qrp vx{yh“^wêÑ•ÈnÕ-•|—ÅxÕÈïß ï ¢èùøy+6[—•y» DW°¤Mè è˵ÝàGÝl&dýð±¤ÏÎØ Í~Ë-FÁ]!È9ØÝ@ÏN‰+}qr)¾µ´Ú‚x?[ùºs±±’`¤a¶c’å"Co›T0GŽ›®mF½ŽañN†ÍZç¼Äz–Wå6Žá<\øFþ;á=j®lÚ ¡Ï@Ç5÷†# tHï¾q¹”A¤ßÕÙ_늩WVÒ”Øñ¹ NœÞ”«ÃØ­©¢MwÙjékæ@aSKmÑ0J±õ˜eG“ >Â+rô‹¥²;Ö[ªZð»õ(ÐH.»X¼UˆOÔ,÷ï  FàÕ3ðH| ò=“}¹ˆ£né.ïY=}€¡OD7¦s>Ù;ýZÆùJ”xæ-Ò‰·‰ý[oWjD ¿6êÇÐ:•ݼœî µ%K¢,Â^»Š²‘ä+½@;ÇËïÔNil(5Â3ÎTý…˜è£DÅ!×3Äv¡±Ã.¨€öp`Ï­Ã%wóЮ6ãEÝu›|ñŒÏ+2(.Ö ½Š„úákmüYþkú6¢Øl|ÏzæåúóŠØŠZúê›j¦íæãòDCý9¯»}ëDC'*¡»ûïb/é§õ:„z?›02¼ªÿ§<âOçîE‘Õ´2™M¯Îrám„’¿ g!1ÛïøáÏÄý²å}}UêµûŒ?ãôØÁÃC´ÒΛ¢i’ƶ Hõð¦QÊ÷úÁ„à¡ÐR¯Ø»Ú3&am#_"yþ¡7~Q‘‡Ä° jGRçÝÈ&û‰ <ÄÉ]ÔùÇf­¤ñ·_“€í(kùˆõO¸0;ocQ$<̰Ø|‚È\f9÷äñ© ˜yñ9‡Òj?tä ì5ñ#»»,½<+ý(|m§Ò/Sí4‡V%AéÇàbG–o5ð Š«ÓÞ8S-ÂŽØÙhBœšeêªt åœ“ÝèIº­ZêÃØÓR{{‘á8ÄøqáŒò4Ίrœ,¿f~ê+ú†žm+}QBp­wq(é±êÙüêbRÓ>‘¯Ç­ :ï* .1õÜ»ÞäGÑ(Fö¡QàæÞkQYÁo¾$Ò›_˜m–ŽÊ˜tñ¢[(NÐ5:‚ª~kIg×wþf-·{•(ºÆ@®§'½®ÎO/)‹jûlàçPú—G‰Ã$»èo^Œþ[ðãRCf’ÍTûÚqG”-ßTh€ï‡ßIèà%ç© Ú°ÂုDˆ4´ñ@Z†ù&|µ‰æÄŒS9ÒP?¾ìÀë«ÁW64¹ÜtÀ»~.¦€Áå²ÚÕ¿c3•dˆ÷$§—_qó/Ç êøp‡SôtoYÛÔlÇ…T¿S)¡ãr½°–=cß2Ê6@a›ì;žS/ùÕs÷x“éèÈéвjÍw:+F¥¬™Â!°ëŠÝš^5“hßrœY7†€#‰ o×쳿Mxâ¢c Üå®}}Z½ ]#ÄM¾±ÛéÞÆ’Æb õú& DwWe%S&A”ö³ gjäùc™ Ç…"²`"ë'µ_óQpÆúÄÅ axÊòÝ–!j4æ”΃²_Ogfl½]Yj1[›5×As;È?ç̼n‰E^ŠN å¾ó¢ a ékõü£Œ)é“ò磑œÖÝc„ŠF“|%µÝ¤¥SØFʶÑþlš¦ÜØ )·¶èto· ®o\öÎkœî¬Â½…¬©5ïÞŒ| z¡VY¦Ñ9IƒSÁ%¼C=×V‡]Ä«b!`öä¡ü ëIE½#Æ­ëBŒÏðë¡wU]ºEä£ñNëò¿üöCžÔÇï¥a÷Iñ-É<ŽAÿ~Ò«uuwk[[a<ãÓT‰Ân[¡IüÖôµW:œ°qX~ EÖ…BW~ÀYUÛÃì— ÖØAC §3xj´}}•hOÙ7•ùx|û'0·ööVQsügâ4–+ß·ÂÅdýð¬~°¦%"‹Ë;ÔÀY:â,æõÙ|¤4åQ{œ=³Ø%¶Ånå\P¹Ã©[r:]¥>v[ßnúg™VÁÖw´çã…&Kq… (‹[qþó¼cGº²ÆÂýï{N‡SD²¦rB-áy9ÚcÈz_’‡«â‚Ôd(“Ñ=‚ öuØéSz‚¿P^\÷¼‡"ëBÔˆUùÐ~ÕŸüÇIs6yêÖ1¯Q§`=Lõ•8Ý*rw½Ú*¡VìtA*¥n)º{þ+NìŸàr¾Òâ¯ü—ir“¨Ð°ˆV+í«†ä/"¯Ã¢J?¿îÂDÔÛ0¥ö%ƶ¡q)@…’¬§nþ""wû¦nîWó+âN2„{ž`jse_üÄÙá±V8aé)ÓY[ÌEu.Pgé{bc¶½½Ý,|1ïœÚæŽr¬‰÷ýHû²¹NäMX³%ÃÖyE£I ¥wãX&ûyàšöt—àIöê÷ûÊ ëÏ,à©×ìx4q@á¡ä·Ž¾×ð)`±h·gÜ’ q: øï²Ú¦ãG½ç œ1£Ü&*ùOÎîžÍÞ«s§=Ù_] ¾bíÔûEŠü5ùdºáJÏ5G±›ÝTo%.T^Ể„¢—X)MÀøÚéq…@®–È[¹¾µ›0Ž»êÀ‹¸bé< F³˜'ïa:üçkíÎÑÚOï¾c¨><Ý”ãrÎlo~Êh‡WvpʲЗÙÃAýµ¶–©eeÓßwlÊÃÝ3¶B"úHÍäÌ×0îõDk ”¿5% Ë*§ÍÅd(ñÈJXôK¿Ä…)1þ‘›Õ¡5‘+~&ë½ÁëW%pWÅÎÐñ¸0Ê]þfÑoJå.*[£Õ´ïž$$p¤1kÜâU üç>†£ÂøÈ8Ñ8hÂRè%ÃïáD SNt– „MǯvD 9'Í&Ì„¾Ý®}õÊ9òï· Œ¯Ò=Ë÷BÍFûžh$‡É^ÖmS}72snF%o8 Q+4'Üþy]æB7ÜØŒtì5(”´ODì&Ÿ=úÅÜÜ8”|Èô«|:¨ˆS±VdãkÄÐÆ;˜‰?2è\yÒ|&v§IO½µ‚DK–ˆ×[ Vü¾í»Ýæö‰Ñg3uòS¥¼^h;‡†¼îcù‹Ó—7³Û–ƒR†vcïùìb_Ñã¬"KM¦ž…à‚·åÛ‰¢?° ¯HcÀ¬Ä„¾Îæ z5é9X{¿ ƒ1§;ð0!ZŠGü6'ïÞ…´ªÊ—õÒt¥Û·óêä½Ú !(>Ç´âëgú‹­ÕÃaeXËfo —© Ýx–´èºµÞ-$õÆ›t«ÁÊœÓqw¤üìÒeyEXctÉÖm)š,DÍ&—Zf;›[Ÿ­Zp0_œ}TîÔcrôzõg{â'&Ajϧ^f$iÙ˜ÕóD:ä ÑAò! +!€çCU“R²)«£…ˆ9pûG@E~6F<Åf¶vÌÁy‡¤RNéŒuü®oLG'¹(û–¸×X7nDrŒß±s&pþãL†ø`r V ¥C gÏøŒë/èþÎë "rή_˳óŽ`°ß¹P…½Á,úÈêo{ªov÷¾£í!D׎Ÿ…-Ák‚ó¾.ÓBÖöH}å{†Ñýœ`PýtºIͧe_Æ7ál ôŽ—ê›ÛÇm\ΨŠeRÃw⣗ŒU€dÂ4Ë"ñÞN§‘ó‹Oô®ží(‘âD“r?̤±è)¼Ôö\µÜà3‰|tX¯dTœéZª?oÒ\wL´Y-] ‘ýÔzlOe`Ê÷V•Á(dÚ·5Ô=‡ÌÈtYÑw©PY]<˜Àí&ÌI&Ó_}FÒæKfÛ”`Tl®d³R0UŽÆèÅuïüÌÖÖïu§¾¹gyA·©6ÊàÚb/dœMCeþ­³Tæa ‰³!¯N[{È ›ý¢|–§Þ¬P™4á¢ôhíŽh[¸ø1˜/²æ,E<Ô¾¾¿ [3 l°áÍcñw ļ¢p'xÅMí©«3ü#¬„…¾@Â)¿{~ãi |í4O)TC9ñQ±WsÍ _ÁdƒyØOáR½„&¯º`Ѷ]$§ß9Ìmc|žj{º7ƒ¾\|Í ú®Í>ÐûjùÌJSú«!ïkþwÎ(_œÅÄ]eo‹Ò¥´ŠqvÅK›j‡z¶ãÛÜbílb듊¶x@#z‘JãýY›[\c¦Xôú'ŸÙZw£“q?å¦qÅ¹Èø·º¿æ$J¯#Ä #éÔ³?¨Ù]—¾ ³®=™†?ÊIJ¢tÆP¯4¼HWï™ÖG8 &ÊuRaï†3\-­h¸${ÈÑ @í¡iÆtÞ"vå9N#Ñ]cU·¼ºTÖ\LKÃ&™Qµž¯Ý‹–v¨ã}<-½mÙ÷“ßg¹ÖEôrrrí<~ƒnFä›[uý(S~|©ºè†C4 öœì«¿ï$ú©{Ք»ƒ§=š,(þM ÒªÊé«#~pH ;œ)o!W಑^P®{Û6ª¸êUÙRìZikæ=™ÔònÄôŽ_3gÃŒ-iëÓnçÄ ’d?.ïCÈ ¸h„žîÏaoåКR Šõœ˜k™¸W:øÜ>=¸ àß¿®'¾!¤·Añ5]\4üÀŽª{d:|Èß8Ö6B‚ÂàcTÁt¬Žç’Nœ2#¡LôÂoÂsòê4Ó óÖÀEãAmÑh¨¹83+üÖìó!£jr6ÉøQ©ÇâO9[ƒv†m¸ÇçIJùöµÒjŊ͆6xðKBþÊð™ æ= b–?e¯å¾ô$ ®ÎùI >Öbö-r—§¯tQ&Ùs;”ï -Q'&‹j"rQâDcÊÉÕÚãQˬV;õ%NU¥Çâ¼\,·•E&$4OzdK@Ákmè—,,HÌk/ÉâØ;›#…ˆò©/¬¾öB…Ê¿H^4¦ý0TÕöZµÒ¾b2:¿ós½NR¸A™ã …S<+w§lŸ¤w0¦zBmXë †@¯ükª¦êù±á¸1=cfö@:ý5BUÅïRŸ+ÑH»LÛ¬´¸ùŠM›_¼‰BV0̦•ÕÉUŒ(+-kf¿Ûí±…;rþPTÕmIVÔKþ²:dLp%µgæ:E$þ—Y՜ЗGŠ‘~ÓÉ{™oÚŠv›>Z”¦\¯ß\Òö¡.?Ù¯Ðj{ÙHÒˆ/%]ZXlÎfêWAc‡*Êz‡¼x×§‡4+„ϬY4o°ÿQùÙ‘€NgfsÕÉîm`ô¯nµ+m7TgÎǘ“„÷N û‹)о°Ñƒ%ÔáèøGkáé*òL¾æŠl uZ„\7ÿZœRB‘ªí×#’Âo°g-ai_í4ƒñ§²™¦@ò2R}_&4}r¨kÒPôZÝ_øìe÷.ýXú˜Š£jïz8Úž‘bY—bçÝlñm«…<:Œ½ÞèQÃ5²Š÷çj'6…èË;r)ŒøÆ«)ò´¯]©rg”1¹ @KGH‘Òfw¸îED¬ÎØ=ËoO¾Ð‰Yž–®ÅÈ€ÅSO%bM«~ôxtÀ'ê‘—$+ ¬`Þj¥åŠJ‹À7˜»cÃkˆøÉœ¢fé‘hŠêgêòwqëyÞ¯Â àŒ¥í¼;bZHÐç“€•syd0Þ/ÉLr\ÐQž²åÄí–ŸÎ&f` H/x°W#©LZÔÔ㇤_œ_ìaž7>¡©´gZ{ Oªçÿ?åQ!w endstream endobj 102 0 obj << /Length1 721 /Length2 5243 /Length3 0 /Length 5832 /Filter /FlateDecode >> stream xÚmrPZÐ5ÖâP*P¬+·¢Å‚»-RBB‚§HâRJqw(N‘âîZ¤Å] Å]úñÞûÞûæŸùçÎÜ9»{vîÙs—™^…DƒÝía¼œ¼\<¢ym5^>?3³Œ#Ì G!eÍÑ0Q€> ÐÙxù÷^f€ ÊÞÝne°ZÿNôæP¸Ü ‡B \àÖ€×...R.NÎ\ŽÎ\÷M:0m XÂ0€Œ†¦¡’º€UA] CÂÍMgnP…[ÀN0 Àå@ü,PH(ü/MN\ @ºÀÑ÷Â,Qv59°´¼†: 'à –˜#¡UÅûv$ÚIôž ³p´ûk:ú?„0ÿAþCÿUÝþA\¼¼(Ü €À¬àHî¿|SBZ¢‚ÿ¤¡Îöÿ–î9Ýë°Þ{@a–÷lgBÝÜ`•AÙÙ;£aŽ5æˆh£ìÌ‘ÿ²Ìíà÷ÿ/ïJhó{¤‘V÷Îñü“‚;ÉÃÝ`PM8úÞjKsĽEçõaÿü‹ w¶û§vïÇýBQH„ûÿ>y?Æßrƒõõµ@Êìÿ-Àße9¤ GZtÐ÷^š;BÿKü]Ö4‡ÿ³=ÿŠùw›¼ÿ«™£án€7<\­Ï_ç_dò,åæÉÉ+ü ÀÉÏÇ฿DøÞý?r-œaHô߆ßÏòoü÷"Á`n0 ‚é)”…X€M|͇Bo¹ìÑ¢ì£ÃouÙ§x1 5ï¿!ƒwZCÍÖö¨ŽÀT®D´#~ñ¥ÝE¥£jó(ÑÆÀ`8}°ÉÕE.c‘•wéü•VæeE°éo=J; uœýCtâÌô{M¶Aä´Re‡|q2Þð·õm-Dÿ?A*MX'ÝÁVØKZfý†H^,Oceø/í3SšYgúÙ¯¿b­YœøÆy tdWïz¨Ñg}³.VbC}DJ/aàóÄÑUý˜Ö²R¨ä­çÛÆ+}Õ®‹P[y—W6œƒõJQ G8£[œa°àÑm¡š0 ]V˜ëüøo¹Iã™Y¢k‹ˆ»‚û¾ 6}|ö–nèzÈ#òõMØ ‡H}øôÀì óóëjó]AtŒLé¤KHd_ò,ÅÛò~çáRÉ?‡ö¤ÐÓÀæ«â&³gf¼ N,1Ëö Gbtòw×ãÖÛk#–Òñk´¯¾uã°C´•WKíU*1OšhÍh.Ô;/v~F§plï`í¾JÔ¤0 rþÄ€£8;.ê,¶íˆÀ½ÐW4»™ \vu÷ÞŽ8‹˜ª”}l0æìrû|–Ý5ôUÍ—|>yΓúä«—S©j\Ò]W(Þâ/ë‚hïÇ@x”* (bA,n ô‡Ò£·‰ñJc·oN<îJ]Poc<°~˜­³*öRûÙ­ëúvh.ö­/–ùBy@'±õZLæ™ÉäÞŠo1¯ªá­Œgãìf/**n̶Á‡ƒ¼}ÜBåçâ4Ò}$œ±Ä>…¶Œ:VWR´õÜÉØ´Ÿ™º´@$ºïtÿl=ßàÒmƒ‰0±Òe°]󌭉Nt) ŸoÚ&•éÖÆ´©Å|æÅnÍ!´3i—4m]¡ ©°|)x¢‹µ¯ZBµ°fŠF?aovðœ1ìà ùPÿñH?/°×B3˜<÷S^Œ56Ñt.Ù;.›°zÍlþäÊñ1 Yš?6?NÌäGYöÃBâžý4èçd»ü&d‰Â"k Û¬ÖÁ”XÆkH© Šó]S©FÝå¿Òh6cœˆo)ºç³ˆjš&‰%ú[÷SPïÆn2^h9>«‡g˜•Ë&<˜<îpÞë w¼£ ®2æØ7¯Ë›dÈQJŠq6øè 7­¶JE梕HòÌo:?¦ÓŒcÅÏU|Ÿ®ª5ÔD•w´¯7'Ç£úϨS)÷Ä\Ì E1ÒwZºhR8¥m`׺òVfø7]ͬA"{’^hs[„ëû²A ?‚î7«ý®´À7”z›Ä uÏÈ+Ÿ´ŠÜÕ9Ïîy³m*]~7c|Ùa$ö\¨3¢–îDªQvì31!5¤åÂ!û^QyêJÃÂL~s{EýÀuþÂíÎ,òzÎM~²Òï$ãël¯TäÈügÏ›#ºwEï8ó’ˆNã|1²‡ù©V·ÚÌó&>=7Ïo¢p¯›܉»Ö(òÊŽ´T/(Á ¹ÇQv Óâ•l(yòâ .Ewùrß9_º©¿gR.U£2.Š’û#óõO«t¡7)s—ø¾ÞZC…ƒÂË©/óA3óS¥¯Â¯PþÔ¶L¤Ä/Ø!Æ°Ë ‡TÙþÈÍô/Tóž¬Æ¡-ôrÈ[§½€!+Ô‡e¢6“ÇÕ>oæ”;VBM¬èåé)ßîiÞáñi‘]»f2ÓÀt;}"•ðì4´Ú–ŸÕ¦eîy£)ëXÀÎ’õÁëõ`úlßî+É·¦¿wùç§Ny¸³ů¥\¥žéí©6ßÙ+êò¼7ð q ³5m}¼:é·µw\x‚(gÍ”òuº¾2’ø0F+ o} IØ3Þ(±XâmDY•büˆD&#CLý=â6Áàš×1`u—Nü6?N½A[m¯÷ºïԺإ§¬âD‰†‘-W.]%#¯,¨n{ý@ðvà¨ðÝ£fñþŸ¬øµôïh:öÒÅI¥^ň¢€Zƒ’è\E.Y•;¼¾qA§zèÜ‘CfDØlK×*©á†ì™ðŒ_‹‘¤¥”ëç.Tæ_|'YøiWþœñ0š<«cd‘l’ËïêôTìå™ùƒrœñ-­ ;q—PÏ%ˆ®ÐÓ =’dÙpûf¥†e‡K»;JÌ©‰ä<Â|p7':ý‘BjUõݶÌ^…/ãI$–GÒ6˜ƒ ©Œ¯»LÖ¤?Xa›¬H†”†ü®?O¨å_ç“îúÓë_rHù1*©ÉïÍ1) ¦Nû°y~ÐŽ9à“Gr`nYðÏʨ(~7ýÓoÀ³ìg/¦qÝ.§Ì”0ð‹åð˜„C1†õwžI²qýÑÁW§Ç-×:ƒ¶|Óc‰ŸgÈÈd­Øy› XŸ`ÊÅ}­ÈJE wfpì``Øe“ég“¿tºB@Jg'ø®ì*ëÜDC‰Ô­TNG©—ni7¼>ºy”=}0Ëtxù3sL|t½Ú7#°k•e0ü¥Ë½`¬ü è.Á1Ñ`A›â8hAR$¢£1o'=œZ3ªdT„«Ðì)?µ0ñ©}r÷UcøžÌ %¤sÔåjãõ>·wV"-8¯<>ÿéjPY,õVÉÆ!›}zj.>CbàÂN‰ ¯—˜“¢/ïÙ\ÍcÞ,´ò IÂä2&îiŒOíö\¤-²b ê @œÍU¯üôãÐ:§u+ó—ÿÑ?ÒÆ>ù8ÔW6ÀÇôÑ1Y€ÙNE¬CHC'óÁâà‘VŸ©¶PÝ×r¦È–î”Bgqò_Ý$cÜÍÝFeãìœOî1®4ã‚Q@ëTèUÏÞÒ0ÌÓ}í0Õ¾Oî}¦î•~/¤sù•ÜNÊ5)zJ ûc-I”6cx£?ÂekÂÄÓû+\ŒXyÿ`‚<‡Ï¤>'q¬«$æÕ„Í™ðîÌH÷Ö–ÈÜ¡ïii¨(òÙ3?tOPƒìé¶!†cëÆ®†óªB“ÏùGUê–Q~ð?_ÞDðOAf–ˆkí¬öò»Kò+$¢µYW×À7‘D°§Û6uwNr4qÎͽÌD4u2A]ijÓOŒvóWmš#“@@ªý¬{P/^ IÜÃé®p¬Ôs7¯4À`ì!môdX0òlÓ©iq–Xô[å9mµ©Ûé‹‹=¶ªjáVz¦õC8ì:ïƒÒãîe(óDO1k²|1‡k®‡Ë sRÝÏh<ºœ•»4Õ`4·)7ÂLûhÚäÒHdùR/wRƒš‘+uKÃ6 C•âcõ· ¹fk‰ñ‰À4äe‡ÅÌÜÖ¨ƒ$)R0arØ¥s{ìm+A=ŸQÐïrb{ŸÑ+V?%iýëè5ì+pð}÷ߟ¼æ°bF(2ÄI Õ/_<¢YóÜ÷÷7i ÌN0Ûnëö-3Úïm}áÿÎõV§¤t8(É·Ž®gNefs^¼u€:§ùÇkªLÙçÊ,òÛÚ»ÊÆ^LÙ$LÕÞ/'Gò”`Ü2&õ|„ln=B=µü"“ ©²2?Èõæ,¸M^qS4—}ß¼ÑgW8ÊêÂDß— •TÖy’>t¨ ÒõTŽ{ý“Ó0Jü(@SdòÌ’4á¼¢„k±}µ­ì`®d-Ì?̉ÃO§3XÓPg{eh/ðè·ê»í •¤ÚÓSyº¯-Ç”Tî2Ь!ýùïª@SJ=î³1 ©WŬIxŠ.þɾžÕÜ©·ï‰“Å'%7ú’¹Ù7à\¿ØðEj»2i\->Ö]É o³ý>ha´´ŸHÂÕÄLú58÷¡6ºòuÏ‹bœoƒú>4 ¦³ÓSŽ‚ÎDH¸ï¼ü>ôð%õò­j–-Y Ž ƒ®|ÙÎuQ8'-ØHmšw‹jlÒJI·Õ¡¸\xp<ŠUZúÌÁù’âØl,Œš:Ñ s  µg“Ãÿ4µVð!ÓÎäç„dn˜ú{uw×eÿsüÎëGf»-,@OåYòlYQ{Q-æÁ ¥ro (qZ•™¢ƒ¬ŸXè\¿f¢ü9ha•u›Á£gLÉâÜ$¸ÁÔ ?2*ª*ÿê jܾòˆ˜úøvá…uÀ)áɲšg £·åGI=’"y2Yò#ze…0ì©'!þ…ð^jOåP¢q%1g0Q+` Ý(³ú^«ìÿI »Ù=”Isòʺ BSUDðÖáó–µ kñ­Íã<âÖäÖ|SµéÏc›syßœl#ÐlsJ剮Y \üKiÕƒ«ç ïRÃ侘¹È$E«³U.‹1x££ÝŒm—FÎæ[ALþó唸BèׂCÀyä0aƇZïFó%]‚?¤³<èmCA‹â/L½O5ˆ?‹¥0_–Ÿ$t9`@0)Œ¸ÖCo•ù¡9.¾[œÄ–úÓ±§’|•­òüxs=6ìžt-cÏÕ¸]]!*̤^ö`Å´R+6oòG>f>û44èrã`púeMüYŸÅŒ‰AÎH¼òå9,}÷Ðù-Õá:‚QkƤh÷yîà¹6Aî‹E¯+»Ú†>ÚËP¨&Èׂ Î,6H_8Y­Q^÷Ó/êLÌn¨1ëqb>Ǫij×3#˜«ä¨s¥¦,QPëÈ–)mò‡þd´‹:a3T¸P¾ÉT}ÒÞk%ã™÷UﻥåÁð4?ů:7´ª36WÄ€qŒ­ÔR)vV¯i~Π|²“|T_“Tæ!nAkÈ}¾'`¯Æ'²Wñ& “°/’Ä™ïOŠ€i{Oüdc7±<å·× 'G­¨¿ÉWÍÄs) *fnÈk Ÿ2\šÍëáQœXÊNÄó í‰z«ÁW÷ÞâÜmZÀKX•î”åLG>Å“ô«ÝžcR¨´áëÓi+.|wµeÏÛo‘} Œ‘Ë뵸ÙT|²ðþÓnÍâ|‹@f:ƒºKÐ>ËkÌì±Å& ÅéA¸ö~½ýå^f£}sm¸æ¸V) _„©1‹L/SMw=¼)cH—¨O:IùÝ­Į̂\¶›Ž¼ƒ-å CyAnþ7¿ EüWÇA |§é/œlíŸûTÚ LŸa×)v·§Q§Hµ¯ öÅIúý¶ƒ1ž endstream endobj 104 0 obj << /Length 741 /Filter /FlateDecode >> stream xÚmUMoâ0¼çWx•ÚÅvHB²ó!qØmUªÕ^!1ÝH ¤í¿__‚—m ñóøyÆÌÝ·—ÍDUíÎLÂGÎ^͹½t¥™¤ß·§àî.kËËÑ4ýc*S³ç'öÒµåÆôì>]gë¦î,yÝ”‡KeFÖ×$mÞëÆS°»3¿&åq÷GÈÉîRúº™pßêþ`I_Î3[d·Eæý4ݹn›'&9ç¶7UÚaãL)l:ŠÛ×MÕ zØê!YU—ý0rßåÑžo>ν9®›},—lúj'Ï}÷á4>Óç®2]ݼ³û[ivjs92V+V™½íhýÿØ ›~éñÊyû8&ÝX®²­Ìù´-M·mÞM°ä|Å–E± LSý7—ЊÝ~¤&–Êçø U´ –2´XÆ(p‹m“¡¦ÂÜÂÂ∠ËXXœ(W°8X&˜LR4â=z¨Åu«kTÌGEåïm7hçáË8KÉc`Iu(à!a <#œG´Ž »>ÃÎn-tJ!]O2Çø`œúñãÌSŒóø#§¸­'œâ,<Ø“L€%q¡O8\Ï€™:Žó 3ht ‡,ª+à9­uçgŽCwËpÞDÿ‚|ŽOžRÇɉ#ɇÛW ºmè—’®1NÃwH=8!õ Á éŒ4ôDCp&q"p¢œüBCT/ôŒ9ñ¡!ɨ~Bü }ÒéîRqÒ‰óTÂçFIŸúܨ™ÏŠ|nTìs£Ÿ¥|neEA¼;~æó¤òÛ<©â6OšßæI‹ÏyÒòsžtèó¤g>O:òyұϓN|žôÜçI/|ž´òyÒÚçI§>O:óyҹϓ.|žRîó” Ÿ§Tú<¥³ë¹_¾û¥ãmÂKz}öÊK×ÙÑ=·î¡ÃW7æú"ŸÚV¹{ÊÇÿŒž‹à/znªb endstream endobj 105 0 obj << /Length 711 /Filter /FlateDecode >> stream xÚmTMoâ0½çWx•ÚÅvHU„dçCâ°mUªÕ^!1ÝH $úï×3C õz¿¿Ì¼Ìï÷íÌÔÝÞÍÂg)>ÜÐ]úÊͲ߻sððwÕåäÚñÕ¹ÚÕÓéð"Þû®ÚºQé;4mÝ_%‰= ”uS×'ü¯N¾%¼ýFwÚ´‡.HS1ÿð‡Ãأʧ`þÖ×®oÚ/ñx§ÍŸm/çóÑ!ƒõZÔîàKú¼îNNÌ~Íéóûì„ÆgEʪ®vÃyW¹~×~¹ •r-Ò²\®­ïÎbÊØ&jâ©r ¡‰ÖAªCu é±Àad)°ôXyœ x¤ &äI)RÌêVÔ˘.L¢I@õo×_¥Êpi k-cÀšâp¡ [À Âàˆn€cÂXçz3æ‚N­4Ö´ˆW Yf„‘ŸÓË%€ Ä9%bë™*Ô©Bˆ+Ðé›|¥© A…Ä_F:CêÔ9èQÔYƒ5ŠÀKÊEê—9r¨ÏèW8f•a¼D>éÏSG&ýx¯VôŽ _kU8!¼ò8ºŽ0L5#àD½ ÔJÒ üXê'9ÅŸ?‡: iÀYI WFñÜæ¹›çn endstream endobj 106 0 obj << /Length 696 /Filter /FlateDecode >> stream xÚmTMoâ0½çWx•ÚÅ$ !Ù ‘8l[•jµWHL7IP‡þûõ¬V=Mžß̼ñ s÷ëu;ÑU··õÈÙ›=w—¾´“ì÷îÝÝå]yil;<[[Ùj<=?±×¾+·v`÷Ù&ß´õðàÈ›¶<^*;²~&ûQ·‚>ìþÝþ”MS 9Ù_êãP·ò{=éÇsæ@öd”ôÇöçºkŸ˜xäœ;`ÝVY×`Œs4½JaÓQÜ¡n«þª‡í¡.’Uu9\ßèY6î>¼ý<¶Ù´‡.Z.ÙôÍž‡þ“4>DÓ—¾²}Ý~°û¯ÒÜÑör:-d0­V¬²WÑÍÿ¼k,›þ8ãóþy²LÒ»ðºÊ®²çÓ®´ý®ý°Ñ’ó[Å*²mõíLrŸ²?ŒÜÔqù¥ã• â5F8@ šˆ=@Šð)&°  È8Ô¹€ÂÅRx u€Dº\j2H—†ª¡ÐVÁ¹0CzL]ø Âb°ct‘I ©g$`htÑ‹0œÆ\F„áŒ0ä†sê‡á jd< —Iê6œ»õñzgóñºË»þê W ¤qÈ’£+—Ÿ#ö•ñÌÇkÄÞ .‰bªsré…¤šáæÄç†bïmŽXú¾„Kß7ǵHß7Géû„û¾nb§>&jÊØµäuœ¯¼ú•ñ1ÜV™÷•âÜãâµÇ‰Ou$ÕŸqWèS/%1{\øxB!€§ÔK(hH©—TЖ枃»J©Ïϯv×ÜëÁ=küÒ2ø¥UðKÏ‚_:~é$ø¥Óà—ÖÁ/¿Œ ~™Eð+7¿èË¢/ ÿlì¡ÛÒ(/}ïö -+ZXukoûìÔE?Z„ãæÅÛKý£ûƒÎ endstream endobj 107 0 obj << /Length 739 /Filter /FlateDecode >> stream xÚmUMoâ0¼çWx•ÚÅvHU„dçCâ°mUªÕ^!1ÝH ý÷ëñ#xÙö?ŸgìÁÜýx]OTÝmÍ$|äìÍœºs_™Iöss îîò®:L;<S›zœ==±×¾«Öf`÷Ù*_µÍð`É«¶ÚŸk3²¾'ióÑ´ž‚}Øý»ù=©½à“í¹ÙM;áà¾7ÃÞr¾›f¶ÆnjÌ-ùeúSÓµOLg~¼À8÷ã ãâþÈ)okà çA„8 ö$`I\èÎ×3`çAfŽã<ÈZ]ƒÂ!‹„ê xNkÇyã¹ãÐð"œ7Á¿ _¥ã“§Ìq âH`òáö•‚nú¥¤kÌÂðRONH=CpB:# =Ñ%8“ˆ88QA~¡!*ÉzÆœøÐäT?!~Ž> étw©8éÄy*ás£¤Ï }nÔÌçFE>7*ö¹Q‰ÏR>7в¢ G]¼;~îó¤ŠÛ<©ò6OšßæI‹¯yÒòkžtèó¤g>O:òyұϓN|žôÜçI/|ž´òyÒÚçIg>O:÷yÒ…Ï“.}ž2îó” Ÿ§Lú> stream xÚmUMoâ0¼çWx•ÚÅvHU„dçCâ°mUªÕ^!1ÝH ý÷ëñ#xÙö?ŸgìÁÜýx]OTÝmÍ$|äìÍœºs_™Iöss îîò®:L;<S›zœ==±×¾«Öf`÷Ù*_µÍð`É«¶ÚŸk3²¾'ióÑ´ž‚}Øý»ù=©½“í¹ÙM;áà¾7ÃÞr¾›f¶ÆnjÌ-ùeúSÓµOLg~¼À8÷ã ãâþÈ)okà çA„8 ö$`I\èÎ×3`çAfŽã<ÈZ]ƒÂ!‹„ê xNkÇyã¹ãÐð"œ7Á¿ _¥ã“§Ìq âH`òáö•‚nú¥¤kÌÂðRONH=CpB:# =Ñ%8“ˆ88QA~¡!*ÉzÆœøÐäT?!~Ž> étw©8éÄy*ás£¤Ï }nÔÌçFE>7*ö¹Q‰ÏR>7в¢ G]¼;~îó¤ŠÛ<©ò6OšßæI‹¯yÒòkžtèó¤g>O:òyұϓN|žôÜçI/|ž´òyÒÚçIg>O:÷yÒ…Ï“.}ž2îó” Ÿ§Lú> stream xÚmUMoâ0¼çWx•ÚÅvH U„dçCâ°mUªÕ^!1ÝHDI8ô߯Ÿá-Û@ãçñóŒ=˜»¯Û™®Ú½…œ½Ù¡=÷¥¥?w]pw—µåùd›ñÙÚÊVÓìðÄ^û¶Üڑݧ›lÓÔãƒ#ošòx®ìÄúždìGÝöa÷ïö÷¬<õBÍöçú8ÖÍŒ÷½ŽóÝ4s5vSc~É/ÛuÛ<1ñÈ9w…¼©Òö†`~ÑÁ擲CÝTýE Ûƒ´@HVÕåxùïòäo?‡Ñž6Í¡ ’„ÍßÜä0öŸ^áC0é+Û×Í»¿Qæf¶ç®;ZPÁx°^³Ê\Cçýyw²lþÁ+åý³³Lú±@Ue[Ù¡Û•¶ß56H8_³¤(Ömªÿæ®Ø&ªrT¾„¯PGë ‘¡Ã2†wØ`24XXºBX8aÁá ‰…ÃJû‚ÃA¢`R¥Ðˆ è¡¡‡^]wqº&j9)*ÿìú‹v®`‡ÆRò°Ä:(à!bx8ápŒØ÷¹ììׂN)¤ï‰&â>0Ni¼‚qFãÆù?ü‰SÜÖ€'¼ÂYðàNR–È}Â{àfØ{©çx2­¯AÃ! …u x‰k=Ç{ã™çàäàExo"ÿ}žžRÏÉ‘#£¿¯xÛ _J¼Æ °B ¾Cì©bÏ8!ž‘=Ñ%p&r"àD9ú Q¾ gÌ‘T†uà+ägÐG¡N—š£N8O-(7ZRntH¹Ñ ÊŽ(7:¦ÜhE¹Ñšr£1+ôè‹wÏÏ(O:¿Í“.nódømžŒøš'#¿æÉ„”'³ <™ˆòdbÊ“Q”'³¤<™åÉhÊ“1”'“RžLFy29åÉ”§”SžRAyJ%å)]\ïÌÿòý/Þ&xG¯¯^yî{÷ úÇÖ?tðÄÕ½¾Ç]ÛÁ*ÿñùô·£—"ø »s¨s endstream endobj 110 0 obj << /Length 740 /Filter /FlateDecode >> stream xÚmUMoâ0¼çWx•ÚÅvH U„dçCâ°ÛªT«½Bbº‘ ‰B8ô߯ß{ .Û@ãçñóŒ=˜»/Û™®Ú½…œ½Ús{éK;Kîºàî.kËËÉ6Ã/k+[M³ç'öÒ·åÖì>Ýd›¦yÓ”ÇKe'Ö÷$cßëÆS`vÿfÿÌÊS¯fûK}êfÆúVGGùf–¹û\b¸à·íÏuÛ<1ñÈ9w…¼©ÒöÎÁ|Á擬CÝTý¨„íAW $«êrGø]žÜIÀâíÇy°§Mshƒ$aóW7yúÔ÷ÌŸûÊöuóÎî? sÛK×-ˆ`ãθtJ!±'™ˆcøÀ8õãŒ3?NaœâOœâ¶<Dg!Àƒ;IXô ôÀÍ0z)rЃÌ@« kÐpÈBQ]^ÒZä 7ž!‡î /½‰ü òU Ÿ<¥Èɉ#“ÜW ºmÐ/%]cXß!õÔÀ ©gœÎÈ€žhŒœIDœ8QN~ACT/ès⃕QøŠøôQ¤ïRsÒ ç©…Ï–>7:ô¹Ñ ŸùÜèØçF+Ÿ­}n4eEƒ=zG~æó¤óÛ<éâ6O†ßæÉˆ¯y2òkžLèód>O&òy2±Ï“Q>OféódV>OFû<ãódRŸ'“ù<™ÜçÉ>O)÷yJ…ÏS*}žÒÅõÎð—¿tx›à½>zå¥ïÝ{ˆO->tðÄÕ½¾Æ]ÛÁ*üà3>ýcÀè¹þ¤C§~ endstream endobj 111 0 obj << /Length 739 /Filter /FlateDecode >> stream xÚmUMoâ0¼çWx•ÚÅvHU„dçCâ°ÛªT«½Bbº‘ A!úï×ãGpÙö?ŸgìÁÜýxYOTÝmÍ$|äìÕœºs_™Iöss îîò®:L;ü2¦6õ8{zb/}W­ÍÀî³U¾j›áÁ’Wmµ?×fd}OÒæ½i=û°û7ógRúùd{nöCÓN8¨oͰ·”of™-±Ï%æü6ý©éÚ'&9ç¶P´uÖ`àL/"Øt”µkÚº¿(a[è „duS —‘û®ö$°xýqÌaÕîº MÙôÕNž†þÃé{¦Ï}mú¦}g÷Ÿ…Ù‰õùx܈` étw©8éÄy*ás£¤Ï }nÔÌçFE>7*ö¹Q‰ÏR>7в¢ G]¼;~îó¤ŠÛ<©ò6OšßæI‹¯yÒòkžtèó¤g>O:òyұϓN|žôÜçI/|ž´òyÒÚçIg>O:÷yÒ…Ï“.}ž2îó” Ÿ§Lú> stream xÚmUMoÛ:¼ëW°‡éÁ5?$R. ¤d9ôMðð®ŽÄä ˆeC¶ù÷³k›m‘CŒÕp¹;;†wŸ~>Î|¿Ž3óEŠ_ñ¸?O]œ5ß¶‡âî®Ýwç]Oßcìc]=~?§}÷Oâ¾yhÆáô9%?ŒÝ۹׬“B|Æœ‚>âþ)þ;ëvÇw%gÏçáí4Œ3‰ä§áô–’>\ ‚‚6ý§ã°¿ õEJ™€õØ7ûÆ8ó 1¿’{Æ~ºðÏ`W(-ú¡;]¾è·Û%=°ùñýxŠ»‡ñe_,—bþ+-OÓ;qü\ÌL}œ†ñUÜÿI--=ž‡·B«•èãKª˜æÿ¾ÝE1ÿpÆ[ÎÓû! Mߊyuû>Û.NÛñ5K)Wb¹Ù¬Š8ö­iÇ[ž_®¹uÊ•MúÑzQ­Š¥Ò)V†€Ú(TØ€àx¿àÞ¢ žjy‹°°!ÀÐÔ•µZÔÀ2àP="¦ZdÔ0\ÃG©R\¡·”).–2*ÎШa!„U¼Ä,†³ÔÛHð° `+jÐÃ.¸5Nα@èâ°èÐVK-àxŸ%ô˜Ü3š% A°YÓ€z¡ÎšÔ>kP#¬³¦õ™5m0W£oš¦Ã¾žj­®§Üý·.†ÐZ¡ŽT$X/©)n)æ#W—„o(æ“oÀRZÞ $K¢p4’ŽZ¶-bâ\­1¦Ü°Jä æP"Gñ‘XÔQ¬‚i/8ºkÉ^€ÂZqŒ:ZsŒ½š9”d š­Bù Ž)ßsLù-ï7½æx˜ÏJ›¡¾Ò`¯ažÉ½)f¥É$†µ’1™¸ dÑŠcªCZCù<£7Ã3JÊgózÌnøþHȰíáÌYÉšäTœ¯a…Šï¯Æ,_»œ-Ÿ—Oë87Ë}êÛKÔ´Ü—Ll¹oKñšò+Êg­JÌâ.¾GZyóº‹Vðc­48¸’ï¼äØWtù]Í:P~`áŒñ±–rZŽq.nÍ1]Ç ÇàSÿæ/©ßP•ýïuö¿7Ùÿ¾Ìþ÷Uö¿·ÙÿÞeÿû:û?Èìÿ ²ÿƒÎþ&û?”Ùÿ!dÿ‡&û¿1y–¦¼ÍH·œn5þ¹ã)º½ÝyšÒ“Bï½x#†1Þž´Ãþ€]ôGoáõñÅ×Mñ?®Xê endstream endobj 113 0 obj << /Length 750 /Filter /FlateDecode >> stream xÚmUMoâ0½çWx•ÚÅ$*B²ó!qض*Õj¯˜n$H¢$úï×3Cð²íh<~3~Ï~î~¼ngºj÷v¦9{³C{îK;Kîºàî.kËóÉ6ã³µ•­¦Ýችöm¹µ#»O7Ù¦©ÇÞ4åñ\Ù õ=ÈØºñ8‡Ý¿Ûß³ò4Ö‚Ïöçú8ÖÍŒø½ôí>sIv›dXôËöCÝ6OL xû9Œö´im$lþæ6‡±ÿDŽÁü¥¯l_7ìþ–šÛÚž»îhãÁzÍ*{pþçÝɲù·¯˜÷ÏÎ2‰kA¼Ê¶²C·+m¿k>lp¾fIQ¬ÛTÿíÅT±?LÐØAù>J‡ë ‘¡‹e .1›ÊPbéªpqH I$\kL¸8HbØŒShÄ…r =ôêzŠã51Xò‰Qùg×_¸sµ‚2¥äÄ’òÀ€+Š Ä ŠsˆC:CQŒ}.'c-ð”BbOEðƒuê×+Xg~Â:ÿ?aŠÛàj îB€.U ±$,ð¨›ĨA¦ˆA 2®‚žAÃ%‹˜òâ%Õ"µñ 1ô9h¨M„ _®ñ¤)ELN 1éÀs¥ ×þRÒ3fg =傸aîCÑYj¥ VÑÝà^¬w&L˜Ó=·° ½Ð3â„nqFyÀDŽϠOLüñ5'žpÏZx?iéý¤•÷“^x?éÐûIGÞO:ö~ÒÚûI“‡4ðÑíˆÏ¼Ït~ë3]ÜúÌð[ŸñÕgF~õ™QÞgfá}fBï3yŸ™ØûÌ,½ÏÌÊûÌhï3c¼ÏLê}f2ï3“{Ÿ™Âû,åÞg©ð>K¥÷Yº¸¾Nœ0³`Â^Çayî{7)q ã„ÑW7ö:©»¶ƒ*üሟþS`õRé̯ endstream endobj 114 0 obj << /Length 750 /Filter /FlateDecode >> stream xÚmUMoâ0½çWx•ÚÅ$*B²ó!qض*Õj¯˜n$H¢$úï×3Cð²íh<~3~Ï~î~¼ngºj÷v¦9{³C{îK;Kîºàî.kËóÉ6ã³µ•­¦Ýችöm¹µ#»O7Ù¦©ÇÞ4åñ\Ù õ=ÈØºñ8‡Ý¿Ûß³ò4ÖBÎöçú8ÖÍŒø½ôí>sIv›dXôËöCÝ6OL xû9Œö´im$lþæ6‡±ÿDŽÁü¥¯l_7ìþ–šÛÚž»îhãÁzÍ*{pþçÝɲù·¯˜÷ÏÎ2‰kA¼Ê¶²C·+m¿k>lp¾fIQ¬ÛTÿíÅT±?LÐØAù>J‡ë ‘¡‹e .1›ÊPbéªpqH I$\kL¸8HbØŒShÄ…r =ôêzŠã51Xò‰Qùg×_¸sµ‚2¥äÄ’òÀ€+Š Ä ŠsˆC:CQŒ}.'c-ð”BbOEðƒuê×+Xg~Â:ÿ?aŠÛàj îB€.U ±$,ð¨›ĨA¦ˆA 2®‚žAÃ%‹˜òâ%Õ"µñ 1ô9h¨M„ _®ñ¤)ELN 1éÀs¥ ×þRÒ3fg =傸aîCÑYj¥ VÑÝà^¬w&L˜Ó=·° ½Ð3â„nqFyÀDŽϠOLüñ5'žpÏZx?iéý¤•÷“^x?éÐûIGÞO:ö~ÒÚûI“‡4ðÑíˆÏ¼Ït~ë3]ÜúÌð[ŸñÕgF~õ™QÞgfá}fBï3yŸ™ØûÌ,½ÏÌÊûÌhï3c¼ÏLê}f2ï3“{Ÿ™Âû,åÞg©ð>K¥÷Yº¸¾Nœ0³`Â^Çayî{7)q ã„ÑW7ö:©»¶ƒ*üሟþS`õR$m¯ endstream endobj 115 0 obj << /Length 672 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öÆ6’*ŠdrضjªÕ^pºH‰A@ýûõŒCf»êô¿™yã'æîÇën¦êö`gñ#govh/}egæç¾‹îîò¶ºœ­Ÿ­­m=Oìµo«Ù½Ùæ[׌ž¼uÕéRÛ‰õ=IÛÆú°ûwû{VÇQðÙáÒœÆÆÍ8ß›ñäIßž3d_ƒ “~Ù~hZ÷ÄÄ#çÜ W›ö c Ñü*…Í'qÇÆÕýU;€ºHHV7ÕxýÂwuö÷É»Ïa´ç­;¶ÑzÍæoþpûOÔøÍ_úÚöû`÷_¥ù£Ý¥ëNd0m6¬¶G_ÑÏÿ¼?[6ÿvÆçý³³Lâ·ºª¶¶C·¯l¿w6Zs¾aë²ÜDÖÕÿ%!ãpœ¨™§ò%¼b•l¢µËÜc€Ã¤ ¥¤ÀÈ ¤ÀPÀP«[ ßuªŸñ©_õgß_•ñxû4Ž$Oˇú<X^\NB8 ë\;c®‚šBbMx¹ ùy˜%ÆPÈ 3jok:E q:¹Œ/d4ˆ8ð€Q§4ÈA2="\¤ÂšYˆ+ÀË‹ÔÏsä(Äè5$ YŒ—Èú rŠÀ‘€ƒ~ì+A¿\HÈ•ÐWr߯{ÇNøxoËøŠ‡û• ¿”$¿TL~©ù¥òK¥ä—ÊÈ/¥È/¥ƒ†p˜1ðsòQä£*ÉGÍÉG-ÈG-ÉG“zA>ê„|Ô)ù¨3òQ/ÉG½"µ"µ&µ!uN>ê‚|Ô%ùh8ùhùh$ùhbòÅ,n~á†üá°nË£ºô½ß+¸´p]À¢hœ½íµ®í \ˆÓ†¯—2ú ¯M„Ç endstream endobj 116 0 obj << /Length 672 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öÆ6’*ŠdrضjªÕ^pºH‰A@ýûõŒCf»êô¿™yã'æîÇën¦êö`gñ#govh/}egæç¾‹îîò¶ºœ­Ÿ­­m=Oìµo«Ù½Ùæ[׌ž¼uÕéRÛ‰õ=IÛÆú°ûwû{VÇQÈÙáÒœÆÆÍ8ß›ñäIßž3d_ƒ “~Ù~hZ÷ÄÄ#çÜ W›ö c Ñü*…Í'qÇÆÕýU;€ºHHV7ÕxýÂwuö÷É»Ïa´ç­;¶ÑzÍæoþpûOÔøÍ_úÚöû`÷_¥ù£Ý¥ëNd0m6¬¶G_ÑÏÿ¼?[6ÿvÆçý³³Lâ·ºª¶¶C·¯l¿w6Zs¾aë²ÜDÖÕÿ%!ãpœ¨™§ò%¼b•l¢µËÜc€Ã¤ ¥¤ÀÈ ¤ÀPÀP«[ ßuªŸñ©_õgß_•ñxû4Ž$Oˇú<X^\NB8 ë\;c®‚šBbMx¹ ùy˜%ÆPÈ 3jok:E q:¹Œ/d4ˆ8ð€Q§4ÈA2="\¤ÂšYˆ+ÀË‹ÔÏsä(Äè5$ YŒ—Èú rŠÀ‘€ƒ~ì+A¿\HÈ•ÐWr߯{ÇNøxoËøŠ‡û• ¿”$¿TL~©ù¥òK¥ä—ÊÈ/¥È/¥ƒ†p˜1ðsòQä£*ÉGÍÉG-ÈG-ÉG“zA>ê„|Ô)ù¨3òQ/ÉG½"µ"µ&µ!uN>ê‚|Ô%ùh8ùhùh$ùhbòÅ,n~á†üá°nË£ºô½ß+¸´p]À¢hœ½íµ®í \ˆÓ†¯—2ú á«„Ñ endstream endobj 117 0 obj << /Length 720 /Filter /FlateDecode >> stream xÚ}TMo£0½ó+¼‡JíÆ6„˜*ŠÄ§”öUS­öš‚ÓEj9ôß¯ß IV«ªÐcüfüæÙÌÍçŸÔÝ›õƒ{)^ìØ†ÊúÙÏ}ïÝÜä]u:Úvz´¶¶õyu|ÏCWíì$n³m¾m›éΑ·mõqªí™õ5)µïM{¥`qûjûS5•–Ò¯ŽþxêíàO£ò%r^›éÃq¿£ ·&¾\Tâ—Ʀk„º—Rº@ÑÖYwDo£·˜õ‰ÅYñ¡iëa)Þ ÙSZÔM5Í_ô®ŽÎ$$ï>ÇÉ·í¡óÖk±xq‹ã4|’â;oñ4ÔvhÚwqû¥BÇØúþÃBÞf#j{p…7û£‹ï¿P_?{+4}+VYuµû}e‡}ûn½µ”±.ËgÛú¿µg¼fjj»—”{k:l–F #Q—hJqØ ‡Ó HQ/e†Ã.!Pp #]gQtVTýÙ³v)#l-g„À!×7À'užÓ¾:[sI œr.ñ3æ§À9u¢‡•f Í*‚gQNxEq—æ°V1ô¨˜1šVå•£¡Y‡qÍ:54köDC›†Z+ÂÇ)—]ÑØWs͹8:а/È9õƒ‚ãÐR\Qýr—z\®8Ç€û]按Sp/ ¸d8ýãDœ(B®‘ì!ü4êê¹Ñ׳0û«„30û †=å;føz¡ÞJìm’«w&½^0C~±ï†Ï/nS0†G†½K°WÌçš Nò¾Ð³žýdzG¨³ž5c¾C)Õ!=E€^â”øÔK<ûŽ3‹Iò 8ûÈ¿ Ÿq‚3N˜OgŸÎ{ACšò¹ÂßtÖ~Qn~ɸ\Í ý%ø¯1“.“£: ƒ*4¸hH`<4­½Ì¶¾ë‘E ÅóhÆ×Séý!|Œ¼ endstream endobj 120 0 obj << /Producer (pdfTeX-1.40.22) /Creator (TeX) /CreationDate (D:20250505110547-06'00') /ModDate (D:20250505110547-06'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) kpathsea version 6.3.4/dev) >> endobj 9 0 obj << /Type /ObjStm /N 76 /First 615 /Length 3494 /Filter /FlateDecode >> stream xÚí[[S¹~÷¯˜Çsj+ht—ªR[ $aÃ. dC6Ń øÄجm²ÙýõçëÖØs³!ŸÔyØdYÓjõ×ÝênɃÊòLfÑgRe2šLÊLEI—é(3i3A3B&Cæ‚Ï”Î|°™RY¦§B#¾CŽù“d™Æ,òLÛLj2 ÖÆûLƒõ6Ó wÞdô>àô!èž]t13:S¹ ™…ïAdçñ°>}æ tà#ºÐ}ó ÑÅzPT0˜ QCTø³(-5YÔÎö ëhÁ*ŒÌÈyž£ÑQGb™›èÐÂ02‡   )0ƒZêXðiHGP7ØÛžž¥×1sd°GŽÇ†L- .ž9éšl©cɘXQÑdÉŠ„VÌ•ëÁRKO¡£5Ü2i£à!`¬­"‰Ú’Úß{þ¼'Nþº-2qØ¿*zbg<š£Ù4Ó𿣞8*¦ã»ÉE1…3òÀAq9èo¿fs @¨-å¡U#·B<ëËÓI ¢þñG^`L³çÏ3±/4ô„º˜=ïÂÜó.©.uáy»à"'ã‹ãb–}„ »{™8)¾Î²³ùKÈ.„McXˆ¸ bžÂw@ØMƒXÈø  G‚PyDØ´7UÒÖ0P°’›aÚ ¥¾7Ä5ß5†#ÄSÅ"ÿ]6H…è‘’kÕ–\çëH®õö¨mâº-1ÑcA¸³iKj)´Ç‚èøößÄÒ­]ß d:®eþ‡®µAw2¶#¸Þ°à§»z¨2Tɤ>Ê 3§A20s.(ML| hÛ±–Í¿èÇJÛ1‘]ËDÖoÀDß`Ç%瀺N·aÓ@7Uµ|tRoáüâÔŠñà·ŽOr‹Žf ç¦Ü¡¯5?•rK®lƒ–àcHyšæxi·\Ù–A{ÄÑÃ;¢P–ž¥¬¤Õ‚¤õ½‹D]öy}¦1yØŠe›8ÖŸjKôsn÷Iú-mɳ֦µê4iÄÒŸÏ5¤*1ÃÑu–{¯i”ét`}(ÒápÊC³!Ö81×4¿\AEè&Y¨\!Qr#ñ©$‹ÖõZ×JS!›±ÝßJ}/Æêsh4Y.Y¨ôœš^˜Ÿ’ ‹•Þ£ËÙg½„ÿÿð$cd© šô˜Zå“wñSœÛÛ×Ò5Sl+žCßcN~€3; «ZK$i™ªW§ÒÕÈ-³¯?«‰·L°Uª#Eâj<‰žÚ4BÐ|Îî˜`9BáBU” ¹)è´KnPátPm”®|^ŽñÜ’;ÜB– /ùÛ¤Nºf˜/oé…XW@Û½š ˜YiZ¿f=mØTU·äQˆfð.jéGInñ×çF"@b ì iYG{ذr pìU/9BSl$šPÒÓúäuXsèÉV2xZ›âÉ ƒå‘Ö°h°:âlЧ˜¯­Á¨C22YÄLµ¤U>ýÈá6ÐÎùy8Î|¬Þ·p¸Ýtvª<¢ É ¹’Ö캊³g èx i –Ìb(¤7žŽŠ¸m86kŽáÞ‚Ÿ7–Fr¶žg÷vЧÏ)_©”™Iƒ˜-›sÐéóÖ¬ÚºžŒÌ9KÑõY’â!Y)Ý,[/GÃY YXkºo´dqX ›š}-°U-$§K²œ¬‰—фŘ”u ­_GÞDqP@ºöG»­×¼r¼áVõ4¦©ç\ò*µ)OöŽ‘k'[$ÿ <žhx?»D~üÜr˜™¯–ÚXŸ“¤È+lº%;õé¾Ðت¯óêûœ.]H"ÐòÞ®°ò\Øz&Ê2/Ш+¹O{˜<“÷2r«ËþiÿiïmiGÒ/ ìYT-=­M|ÊÖP à^Ë+ü=Šü>FÊgL0[—{×ç\u"¦5Gcþ-…jtŠdQ‘îù'&H¡‘‹V[öƒ¦TDùÝ¿Î0-,¥Se7µ'‹…èw¹‘5¼Ëiïѯ#ô™ªYÃ9éitŽŸG#ÅÓ4µ/)*ÚôÜX’ÃîWTü,i(õ¹¥Ýò-Œô¤ã?ÎW‘#ü½y2–ÑvA—4^ÏlsxŒj‘ñš¹•V«zE=ãÔó%?CŒ4ÊÏsijÙÙ‘™S›F¥‹záQÞpyÇ×éä.š©(7A›¹æ™Š«9è=ò,=ç—f–¼‰¤û’7ÿÚeèg(·øbchnöªoÄ&™£êÕÍH£•i©èàßíXõBÌêšèöë#‰³Éɽë}…@4åÜ4Îç’R7^ñÉ„çÖy2 •¾J–°¦>?…µ"ùO4ÞpYÆ}*!ÒÁÄÇ—zAM?‰¦Zu1ä/TÊG§n?µå­L K"Éa6f¸ª×tâ :].Îú|hc§ÓKºà»î—ãÌ!õ¹Þ=«]cÑMÓn1½˜ ngãIºyú¹ƒ'û;»?ÿôÃÎÁö©Tx0ì_M3“(¶ù>ë™ÕÙ3eégvÍÞYO¼˜^Ðu–‹ Üéß¾.W×ø\OÐ2ô왤‡ofýáàâÅèjXdyOÏŠ›ßèwûž8-'á×ý ÝbýK¼ÛbG¼{âx+ÄÏâq$ŽÅ‰øM¼}q..Ä¥(OŸÄ§Á—B|ßMÄ•¸þëöº‰øŠ1c1âVÜ“ÁøRü!&b*¦ÅM_ÅLÌ®'E!fŽÅø"þ_Å_ÿNØ÷Ø»úuÝCªÜ9:Þß{UîïÈ|©.qjx¦øì}S•((šªÔ•*ózôª¦F-ëj<`eÝŠINXÎÉááéá6à¼YåZÎá(÷€gèû<ãO˜œ]‰éb|sÓÅít0$Ì\šuVÇòu0¾>Ú·ûVì™Éçóøˆ £¹¸ ù~åù¿°×Ÿ–>ŸÀ“ç“Ï“³Cs/_x8ù÷¬ôå†'µŽZ~ß{üö«e•åMŠ ¢›ÑнW+;b—5óJ¼®Å…Ã22¼ãØp*~_è RÓXŠÅè²?½Åwý!)‘õ˜ÂÇpA®&}|¿®G’Ï¥–G„’E@¡ëüañi–z^ ´ÁíðnŠPóÇÝxV¤)êÜ ’\Uü™I ¥QHü-þ.&ㆠÍ:&ܵ½³ó–MèW˜P'ÏŽ†®Iâ7›Ð®0¡Õuæu¾b‘)UT®y,!o@]+îî}xõòâîÑ ¤Ê—{X*µoõ«÷0AžšµÂîáé/¯_š°Ânn‘CòÍ që ‰kØÓÝý÷{;@süaU„U1{Y‡NCt3ÇpK"&_‰è¼ßH‰q­¸xòáèðèhNÞ¬B£íÂ×̦RbX‰†*¥D¼‚ÂÙ€2Ÿ bÊ—ʵBǛ㓷ï·JuŸRIHç¾Í Ô÷d€ΆUõ÷‰à’zï¶‘[å\\+¬üöáÝ«TŸœ¬, M—3(Å£«)AʆèëB J©õKƒ].ƒS"+aSÔl爸V¨ÙÿýèÅÞIB¸ÂÐTàÑi\Ñu€}:ÂÇ¥ù_‰žªÚþ rÇ´?ºý)¥ØégÑŸÁ5ÎûŸSJ=Ÿô/ NÏÜKY˜ºŸ‹Ùbýô ]0\އÃþ¤ªæüD(úXµ[$ ‹é´ªFw7çrp5z°h ¥-+.χ­"îF—Xüb<)î)(PÒ®üÞ¿ÿu{ÿ‡ã½£©ò;BÄ?­ÿŒ¢ÒBU.Óˆåù盯¬'Îï†ÃbÖIJ$¿]Œ/£+¬5øô©€ÎéR»’ÃY;V¿;ŸñW„‹n÷§¿©Ñ9+7TE/fó› {ƒÉtF²fÞþ¶_~‘ ¼Þ.g×SzÇ›IOÆïF°ç%É¿"Dß'OçÀÙ(¶ò¾.ÅÞ¹@¶+]_ ö‘±)OmydCAÒ-äq¾+[_žÖñ®%Žîˆ£VØËé®8~}qZǪ–8¶#Žlˆ£+k-'¬/NëˆÐ§ëÍ®a,_‰cºâÄõÅi–ñ-i:®lbM sSu…‘ùúÂ4«ð¦0Q~³0ÝmU¾ª¿–0í"º%N×ó†©òÚ¾r]Ô#öy«n ô€'ËPÉ#»òèõåiW¬-y¾=0»Ð•ç¹]:¶ä‰÷ÊT%N7OÈG„åvׇþݧ%6 ýØj«/±×#âr·”h‹ÔõiÝði]ù´/ßÉœg{ú_¥ŽK¢5½Ú9¥w;羽­^þŸÿ ÇOƒK lL–éL™^íU:}0ýÙc˜ëôN±N/vëô®§Iƒ&½jåCÜÕ*î¶äâ@…@š’Beùöpù¶jkæNÅÚøª—X,ÖÍ(ô¤} endstream endobj 121 0 obj << /Type /XRef /Index [0 122] /Size 122 /W [1 3 1] /Root 119 0 R /Info 120 0 R /ID [ ] /Length 352 /Filter /FlateDecode >> stream xÚ%ÐÉ+ÄaÇñïçÁ0ö}_cëØÆ>ŒuŒ£åæ ))'rqšƒƒœäOPN"'åH¢”¢”RÈA”(Nâù|çòêýý>¿ßsxDDþŒˆD ’"¬.â'½¤“ ÃüÌèé(‰"»¥»C¢!inÝÅ$QÇAâ$qŠ%Ýu“I ñOX’H"¤õ]Ç I!ÉÀ¬îÒH*$t¦cI‡Lê˜E2!3~ûIé!C$‡dCæ3õ“<’ Yˆü1@ÆHɇ,ëA!)"Ť„¸H))#夃¸I©$U¤šx «z_ äh]«r³¯UùÙѪ|•Z @øY«Ø[Ñò§sZMÀã¤V3ð»©Õ㎼_+ÌÔ®VÌšWËs0­Õs¾-0—–«'Ëõ›åÖe¹›´ÜoXN,Ÿ–—3Ë«Ãò>lùðY¾ªôª‡ù ¢b–å®@?= endstream endobj startxref 198001 %%EOF zgimbutas-mwrap-25008ce/python/000077500000000000000000000000001515063637600165305ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/python/COPYING000066400000000000000000000025271515063637600175710ustar00rootroot00000000000000mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel MIT License, with an additional clause permitting redistribution of mwrap-generated source code under any license of your choice. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zgimbutas-mwrap-25008ce/python/README.md000066400000000000000000000032361515063637600200130ustar00rootroot00000000000000# MWrap — Python version A pure Python drop-in replacement for the C++ [mwrap](https://github.com/zgimbutas/mwrap) MEX interface generator. No C/C++ compilation is required — only a Python interpreter. The runtime support library (`mwrap_support.c`) is also bundled and can be easily adjusted. This port is **experimental** and tracks the C++ version's functionality. ## Requirements - Python 3.6+ - No external dependencies (uses only the standard library) ## Usage ```bash python/mwrap -mex outputmex -c outputmex.c -m output.m input.mw python3 python/mwrap -mex outputmex -c outputmex.c -m output.m input.mw ``` Key flags: | Flag | Description | |------|-------------| | `-mex name` | MATLAB MEX function name | | `-c file.c` | Generate C/C++ MEX gateway file | | `-m file.m` | Generate MATLAB stub file | | `-mb` | Generate `.m` files from `@` redirections | | `-list` | List files from `@` redirections | | `-catch` | Enable C++ exception handling | | `-c99complex` | Support C99 complex types | | `-cppcomplex` | Support C++ complex types | | `-i8` | Promote `int`/`long` to 64-bit | | `-gpu` | Support MATLAB `gpuArray` | ## Module overview | File | Role | |------|------| | `mwrap` | Entry point and argument parsing | | `mwrap_lexer.py` | Tokenizer for `.mw` files | | `mwrap_parser.py` | Recursive-descent parser producing an AST | | `mwrap_ast.py` | AST node types and `MwrapContext` | | `mwrap_typecheck.py` | Type validation | | `mwrap_cgen.py` | MEX C/C++ code generator | | `mwrap_mgen.py` | MATLAB `.m` stub generator | | `mwrap_support.c` | Runtime support library embedded in generated MEX files | ## License MIT License — see [COPYING](COPYING) for details. zgimbutas-mwrap-25008ce/python/mwrap000077500000000000000000000112551515063637600176100ustar00rootroot00000000000000#!/usr/bin/env python3 """ mwrap — MEX file generator for MATLAB and Octave. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ import sys import os import argparse # Ensure the directory containing this script is on the path _script_dir = os.path.dirname(os.path.abspath(__file__)) if _script_dir not in sys.path: sys.path.insert(0, _script_dir) from mwrap_ast import MwrapContext from mwrap_lexer import Lexer from mwrap_parser import Parser from mwrap_cgen import print_mex_init, print_mex_file HELP_STRING = """\ mwrap 1.3 - MEX file generator for MATLAB and Octave Syntax: mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb] [-list] [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu] infile1 infile2 ... -mex outputmex -- specify the MATLAB mex function name -m output.m -- generate the MATLAB stub called output.m -c outputmex.c -- generate the C file outputmex.c -mb -- generate .m files specified with @ redirections -list -- list files specified with @ redirections -catch -- generate C++ exception handling code -i8 -- convert int, long, uint, ulong to int64_t, uint64_t -c99complex -- add support code for C99 complex types -cppcomplex -- add support code for C++ complex types -gpu -- add support code for MATLAB gpuArray """ USAGE_STRING = """\ Usage: mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] infile1 ... Try 'mwrap --help' for more information. """ def _load_support(): """Load the runtime support C file content.""" support_path = os.path.join(_script_dir, "mwrap_support.c") with open(support_path, "r") as f: return f.read() def _build_parser(): """Build the argparse argument parser.""" p = argparse.ArgumentParser(add_help=False) p.add_argument('--help', action='store_true', dest='help') p.add_argument('-m', dest='mfile') p.add_argument('-c', dest='cfile') p.add_argument('-mex', dest='mexfunc', default='mexfunction') p.add_argument('-mb', action='store_true', dest='mbatching') p.add_argument('-list', action='store_true', dest='listing') p.add_argument('-catch', action='store_true', dest='catch_') p.add_argument('-i8', action='store_true') p.add_argument('-c99complex', action='store_true') p.add_argument('-cppcomplex', action='store_true') p.add_argument('-gpu', action='store_true') p.add_argument('input_files', nargs='*') return p def main(): ctx = MwrapContext() ctx.init_scalar_types() if len(sys.argv) < 2: sys.stderr.write(HELP_STRING) return 0 p = _build_parser() args = p.parse_args() if args.help: sys.stderr.write(HELP_STRING) return 0 if args.catch_: ctx.mw_generate_catch = True if args.i8: ctx.mw_promote_int = 4 if args.c99complex: ctx.mw_use_c99_complex = True if args.cppcomplex: ctx.mw_use_cpp_complex = True if args.gpu: ctx.mw_use_gpu = True if ctx.mw_use_c99_complex or ctx.mw_use_cpp_complex: ctx.add_zscalar_type("dcomplex") ctx.add_cscalar_type("fcomplex") if not args.input_files: sys.stderr.write(USAGE_STRING) return 0 # --- Open output files --- outfp = None outcfp = None if args.mfile: outfp = open(args.mfile, "w") if args.cfile: outcfp = open(args.cfile, "w") # --- Create lexer and parser --- lexer = Lexer(outfp=outfp, outcfp=outcfp, mbatching_flag=args.mbatching, listing_flag=args.listing) parser = Parser(lexer, ctx, mexfunc=args.mexfunc) err_flag = 0 emitted_mex_init = False for infile in args.input_files: lexer.linenum = 1 parser.type_errs = 0 try: fp_test = open(infile, "r") fp_test.close() except OSError: sys.stderr.write(f"Could not read {infile}\n") continue lexer.current_ifname = infile if outcfp and not emitted_mex_init: support_text = _load_support() print_mex_init(outcfp, ctx, support_text) emitted_mex_init = True for tok in lexer.lex_file(infile): parser.feed(tok) parser.finish_file() err_flag += parser.err_flag parser.err_flag = 0 # --- Generate C output --- if not err_flag and outcfp: print_mex_file(outcfp, ctx, parser.funcs) if outfp: outfp.close() if outcfp: outcfp.close() return err_flag if __name__ == "__main__": sys.exit(main()) zgimbutas-mwrap-25008ce/python/mwrap_ast.py000066400000000000000000000222701515063637600211020ustar00rootroot00000000000000""" mwrap_ast.py — AST nodes, type registries, and helpers for mwrap. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ from enum import IntEnum from dataclasses import dataclass, field from typing import Optional # --------------------------------------------------------------------------- # VT_* classification codes # --------------------------------------------------------------------------- class VT(IntEnum): unk = 0 obj = 1 array = 2 carray = 3 zarray = 4 rarray = 5 scalar = 6 cscalar = 7 zscalar = 8 string = 9 mx = 10 p_obj = 11 p_scalar = 12 p_cscalar = 13 p_zscalar = 14 r_obj = 15 r_scalar = 16 r_cscalar = 17 r_zscalar = 18 const = 19 # --------------------------------------------------------------------------- # iospec / VT classification helpers (single source of truth) # --------------------------------------------------------------------------- def iospec_is_input(c): return c in ('i', 'b') def iospec_is_output(c): return c in ('o', 'b') def iospec_is_inonly(c): return c == 'i' def is_array(tinfo): return tinfo in (VT.array, VT.carray, VT.zarray) def is_obj(tinfo): return tinfo in (VT.obj, VT.p_obj, VT.r_obj) def complex_tinfo(v): return v.tinfo in (VT.carray, VT.zarray, VT.cscalar, VT.zscalar, VT.r_cscalar, VT.r_zscalar, VT.p_cscalar, VT.p_zscalar) def nullable_return(f): return (f.ret and f.ret[0].tinfo in ( VT.string, VT.array, VT.carray, VT.zarray, VT.p_scalar, VT.p_cscalar, VT.p_zscalar)) # --------------------------------------------------------------------------- # AST node dataclasses # --------------------------------------------------------------------------- @dataclass class Expr: value: str input_label: int = -1 @dataclass class TypeQual: qual: str # '*', '&', 'a' (array), 'r' (array ref) args: list = field(default_factory=list) # list[Expr] @dataclass class Var: devicespec: str # 'c' (cpu) or 'g' (gpu) iospec: str # 'i','o','b' basetype: str qual: Optional[TypeQual] name: str tinfo: int = VT.unk input_label: int = -1 output_label: int = -1 @dataclass class Func: thisv: Optional[str] classv: Optional[str] funcv: str fname: str line: int fort: bool = False id: int = -1 args: list = field(default_factory=list) # list[Var] ret: list = field(default_factory=list) # list[Var] (0 or 1 elements) same: list = field(default_factory=list) # list[Func] — duplicate signatures # --------------------------------------------------------------------------- # MwrapContext — all mutable state in one object # --------------------------------------------------------------------------- class MwrapContext: def __init__(self): # CLI flags self.mw_use_gpu = False self.mw_generate_catch = False self.mw_use_c99_complex = False self.mw_use_cpp_complex = False self.mw_promote_int = 0 # Type registries self.scalar_decls = set() self.cscalar_decls = set() self.zscalar_decls = set() self.mxarray_decls = set() self.class_decls = {} # str -> list[str] # Type usage tracking self.mw_use_int32_t = 0 self.mw_use_int64_t = 0 self.mw_use_uint32_t = 0 self.mw_use_uint64_t = 0 self.mw_use_longlong = 0 self.mw_use_ulonglong = 0 self.mw_use_ulong = 0 self.mw_use_uint = 0 self.mw_use_ushort = 0 self.mw_use_uchar = 0 def init_scalar_types(self): self.scalar_decls.clear() for t in ("double", "float", "long", "int", "short", "char", "ulong", "uint", "ushort", "uchar", "int32_t", "int64_t", "uint32_t", "uint64_t", "bool", "size_t", "ptrdiff_t"): self.scalar_decls.add(t) def is_scalar_type(self, name): return name in self.scalar_decls def is_cscalar_type(self, name): return name in self.cscalar_decls def is_zscalar_type(self, name): return name in self.zscalar_decls def is_mxarray_type(self, name): return name in self.mxarray_decls def add_scalar_type(self, name): self.scalar_decls.add(name) def add_cscalar_type(self, name): self.cscalar_decls.add(name) def add_zscalar_type(self, name): self.zscalar_decls.add(name) def add_mxarray_type(self, name): self.mxarray_decls.add(name) # --------------------------------------------------------------------------- # Functions that need context # --------------------------------------------------------------------------- def promote_int(ctx, name: str) -> str: if name == "int32_t": ctx.mw_use_int32_t = 1 if name == "int64_t": ctx.mw_use_int64_t = 1 if name == "uint32_t": ctx.mw_use_uint32_t = 1 if name == "uint64_t": ctx.mw_use_uint64_t = 1 if name == "ulong": ctx.mw_use_ulong = 1 if name == "uint": ctx.mw_use_uint = 1 if name == "ushort": ctx.mw_use_ushort = 1 if name == "uchar": ctx.mw_use_uchar = 1 if ctx.mw_promote_int == 1: if name == "uint": ctx.mw_use_ulong = 1 if name == "int": return "long" if name == "uint": return "ulong" elif ctx.mw_promote_int == 2: if name == "uint": ctx.mw_use_ulong = 1 if name == "ulong": ctx.mw_use_ulong = 1 if name == "int": return "long" if name == "long": return "long" if name == "uint": return "ulong" if name == "ulong": return "ulong" elif ctx.mw_promote_int == 3: if name == "int": ctx.mw_use_int32_t = 1 if name == "long": ctx.mw_use_int64_t = 1 if name == "uint": ctx.mw_use_uint32_t = 1 if name == "ulong": ctx.mw_use_uint64_t = 1 if name == "int": return "int32_t" if name == "long": return "int32_t" if name == "uint": return "uint64_t" if name == "ulong": return "uint64_t" elif ctx.mw_promote_int == 4: if name == "int": ctx.mw_use_int64_t = 1 if name == "long": ctx.mw_use_int64_t = 1 if name == "uint": ctx.mw_use_uint64_t = 1 if name == "ulong": ctx.mw_use_uint64_t = 1 if name == "int": return "int64_t" if name == "long": return "int64_t" if name == "uint": return "uint64_t" if name == "ulong": return "uint64_t" return name def add_inherits(ctx, childname: str, parents: list): """Register childname as child of each parent in parents list.""" for parent in parents: if parent not in ctx.class_decls: ctx.class_decls[parent] = [] ctx.class_decls[parent].insert(0, childname) # --------------------------------------------------------------------------- # ID string (canonical signature for deduplication) # --------------------------------------------------------------------------- def _id_expr(args: list) -> str: return "x" * len(args) def _id_qual(q: Optional[TypeQual]) -> str: if not q: return "" if q.qual == 'a': return "[" + _id_expr(q.args) + "]" return q.qual def _id_var_single(ctx, v: Var) -> str: name = "" if v.devicespec == 'c': name += "c " elif v.devicespec == 'g': name += "g " io = v.iospec if io == 'i': name += "i " elif io == 'o': name += "o " else: name += "io " name += promote_int(ctx, v.basetype) name += _id_qual(v.qual) if v.tinfo == VT.const: name += " " + v.name return name def _id_var(ctx, vars: list) -> str: return ", ".join(_id_var_single(ctx, v) for v in vars) def id_string(ctx, f) -> str: if not f: return "" name = "" if f.ret: name += _id_var(ctx, f.ret) + " = " if f.thisv: name += f.thisv + "->" + f.classv + "." name += f.funcv + "(" + _id_var(ctx, f.args) + ")" return name # --------------------------------------------------------------------------- # AST printing (for C comments) # --------------------------------------------------------------------------- def _print_expr(args: list) -> str: return ", ".join(e.value for e in args) def _print_qual(q): if not q: return "" if q.qual == 'a': return "[" + _print_expr(q.args) + "]" return q.qual def _print_devicespec(v): if v.devicespec == 'g': return "gpu " return "" def _print_iospec(v): m = {'o': "output ", 'b': "inout "} return m.get(v.iospec, "") def _print_var(v): return v.basetype + _print_qual(v.qual) + " " + v.name def _print_args(vars: list) -> str: return ", ".join( _print_devicespec(v) + _print_iospec(v) + _print_var(v) for v in vars ) def print_func(f): """Human-readable translation of Func AST (for C comments).""" if not f: return "" s = "" if f.ret: s += _print_var(f.ret[0]) + " = " if f.thisv: s += f"{f.thisv}->{f.classv}." s += f"{f.funcv}({_print_args(f.args)});\n" return s zgimbutas-mwrap-25008ce/python/mwrap_cgen.py000066400000000000000000001201331515063637600212240ustar00rootroot00000000000000""" mwrap_cgen.py — C/MEX code generator. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ import sys from dataclasses import dataclass from mwrap_ast import ( VT, Expr, TypeQual, Var, Func, id_string, print_func, is_array, is_obj, complex_tinfo, nullable_return, ) # =================================================================== # Type property table — single source of truth for type dispatch # =================================================================== @dataclass(frozen=True) class TypeProps: mxclass: str # "mxDOUBLE_CLASS", "mxSINGLE_CLASS", etc. accessor: str | None # interleaved API accessor: "mxGetDoubles", etc. is_single: bool # True → use _single copier variants scalar_getter: str # "mxWrapGetScalar" / "_single" / "_char" scalar_class: str # mxClass for scalar validation direct_input: bool = False # True → use direct accessor for input-only arrays _DEFAULT_PROPS = TypeProps("mxVOID_CLASS", None, False, "mxWrapGetScalar", "mxDOUBLE_CLASS") TYPE_PROPS = { "double": TypeProps("mxDOUBLE_CLASS", "mxGetDoubles", False, "mxWrapGetScalar", "mxDOUBLE_CLASS", True), "float": TypeProps("mxSINGLE_CLASS", "mxGetSingles", True, "mxWrapGetScalar_single", "mxSINGLE_CLASS", True), "int32_t": TypeProps("mxINT32_CLASS", "mxGetInt32s", False, "mxWrapGetScalar", "mxDOUBLE_CLASS"), "int64_t": TypeProps("mxINT64_CLASS", "mxGetInt64s", False, "mxWrapGetScalar", "mxDOUBLE_CLASS"), "uint32_t": TypeProps("mxUINT32_CLASS", "mxGetUint32s", False, "mxWrapGetScalar", "mxDOUBLE_CLASS"), "uint64_t": TypeProps("mxUINT64_CLASS", "mxGetUint64s", False, "mxWrapGetScalar", "mxDOUBLE_CLASS"), "dcomplex": TypeProps("mxDOUBLE_CLASS", "mxGetComplexDoubles", False, "mxWrapGetScalar", "mxDOUBLE_CLASS"), "fcomplex": TypeProps("mxSINGLE_CLASS", "mxGetComplexSingles", True, "mxWrapGetScalar_single", "mxSINGLE_CLASS"), "char": TypeProps("mxCHAR_CLASS", None, False, "mxWrapGetScalar_char", "mxCHAR_CLASS"), } def _type_props(name): return TYPE_PROPS.get(name, _DEFAULT_PROPS) def _copier_suffix(bt): """Return 'single_' for float-precision types, '' otherwise.""" return "single_" if _type_props(bt).is_single else "" # =================================================================== # Utility functions # =================================================================== def basetype_to_cucomplex(name): if name == "fcomplex": return "cuFloatComplex" if name == "dcomplex": return "cuDoubleComplex" return name def basetype_to_mxclassid(name): return _type_props(name).mxclass def vname(v): if v.iospec == 'o': return f"out{v.output_label}_" return f"in{v.input_label}_" def has_fortran(funcs): return any(f.fort for f in funcs) def max_routine_id(funcs): maxid = 0 for f in funcs: if f.id > maxid: maxid = f.id return maxid def _alloc_size_expr(args): """Return C expression for product of dim args.""" if not args: return "1" return "*".join(f"dim{e.input_label}_" for e in args) def _interleaved_branch(fp, interleaved, fallback): """Emit #if MX_HAS_INTERLEAVED_COMPLEX / #else / #endif block.""" fp.write(f"#if MX_HAS_INTERLEAVED_COMPLEX\n{interleaved}#else\n{fallback}#endif\n") # =================================================================== # Complex type definitions # =================================================================== def mex_cpp_complex(fp): fp.write("#include \n\n" "typedef std::complex dcomplex;\n" "#define real_dcomplex(z) std::real(z)\n" "#define imag_dcomplex(z) std::imag(z)\n" "#define setz_dcomplex(z,r,i) *z = dcomplex(r,i)\n\n" "typedef std::complex fcomplex;\n" "#define real_fcomplex(z) std::real(z)\n" "#define imag_fcomplex(z) std::imag(z)\n" "#define setz_fcomplex(z,r,i) *z = fcomplex(r,i)\n\n") def mex_c99_complex(fp): fp.write("#include \n\n" "typedef _Complex double dcomplex;\n" "#define real_dcomplex(z) creal(z)\n" "#define imag_dcomplex(z) cimag(z)\n" "#define setz_dcomplex(z,r,i) *z = r + i*_Complex_I\n\n" "typedef _Complex float fcomplex;\n" "#define real_fcomplex(z) crealf(z)\n" "#define imag_fcomplex(z) cimagf(z)\n" "#define setz_fcomplex(z,r,i) *z = r + i*_Complex_I\n\n") def mex_gpucpp_complex(fp): fp.write("#include \n\n") # =================================================================== # Copier instantiation # =================================================================== def _mex_define_copiers_type(fp, ctx, name): """Emit copier macro calls for one scalar type.""" # Skip types not actually used if name == "int32_t" and not ctx.mw_use_int32_t: return if name == "int64_t" and not ctx.mw_use_int64_t: return if name == "uint32_t" and not ctx.mw_use_uint32_t: return if name == "uint64_t" and not ctx.mw_use_uint64_t: return if name == "ulong" and not ctx.mw_use_ulong: return if name == "uint" and not ctx.mw_use_uint: return if name == "ushort" and not ctx.mw_use_ushort: return if name == "uchar" and not ctx.mw_use_uchar: return fp.write(f"mxWrapGetArrayDef(mxWrapGetArray_{name}, {name})\n") fp.write(f"mxWrapCopyDef (mxWrapCopy_{name}, {name})\n") fp.write(f"mxWrapReturnDef (mxWrapReturn_{name}, {name})\n") fp.write(f"mxWrapGetArrayDef_single(mxWrapGetArray_single_{name}, {name})\n") fp.write(f"mxWrapCopyDef_single (mxWrapCopy_single_{name}, {name})\n") fp.write(f"mxWrapReturnDef_single (mxWrapReturn_single_{name}, {name})\n") def _mex_define_zcopiers(fp, name, ztype): """Emit complex copier macro calls for one complex type.""" fp.write(f"mxWrapGetScalarZDef(mxWrapGetScalar_{name}, {name},\n" f" {ztype}, setz_{name})\n") fp.write(f"mxWrapGetArrayZDef (mxWrapGetArray_{name}, {name},\n" f" {ztype}, setz_{name})\n") fp.write(f"mxWrapCopyZDef (mxWrapCopy_{name}, {name},\n" f" real_{name}, imag_{name})\n") fp.write(f"mxWrapReturnZDef (mxWrapReturn_{name}, {name},\n" f" real_{name}, imag_{name})\n") fp.write(f"mxWrapGetScalarZDef_single(mxWrapGetScalar_single_{name}, {name},\n" f" {ztype}, setz_{name})\n") fp.write(f"mxWrapGetArrayZDef_single (mxWrapGetArray_single_{name}, {name},\n" f" {ztype}, setz_{name})\n") fp.write(f"mxWrapCopyZDef_single (mxWrapCopy_single_{name}, {name},\n" f" real_{name}, imag_{name})\n") fp.write(f"mxWrapReturnZDef_single (mxWrapReturn_single_{name}, {name},\n" f" real_{name}, imag_{name})\n") def mex_define_copiers(fp, ctx): fp.write("\n\n\n/* Array copier definitions */\n") for name in sorted(ctx.scalar_decls): _mex_define_copiers_type(fp, ctx, name) for name in sorted(ctx.cscalar_decls): _mex_define_zcopiers(fp, name, "float") for name in sorted(ctx.zscalar_decls): _mex_define_zcopiers(fp, name, "double") fp.write("\n") # =================================================================== # Fortran name mangling # =================================================================== def _fortran_funcs(funcs): """Yield unique Func objects for fortran functions.""" seen = set() for f in funcs: if f.fort and f.funcv not in seen: seen.add(f.funcv) yield f def mex_define_fnames(fp, funcs): fp.write("#if defined(MWF77_CAPS)\n") for fc in _fortran_funcs(funcs): fp.write(f"#define MWF77_{fc.funcv} {fc.funcv.upper()}\n") fp.write("#elif defined(MWF77_UNDERSCORE1)\n") for fc in _fortran_funcs(funcs): fp.write(f"#define MWF77_{fc.funcv} {fc.funcv.lower()}_\n") fp.write("#elif defined(MWF77_UNDERSCORE0)\n") for fc in _fortran_funcs(funcs): fp.write(f"#define MWF77_{fc.funcv} {fc.funcv.lower()}\n") fp.write("#else /* f2c convention */\n") for fc in _fortran_funcs(funcs): low = fc.funcv.lower() suffix = "__" if '_' in low else "_" fp.write(f"#define MWF77_{fc.funcv} {low}{suffix}\n") fp.write("#endif\n\n") def _mex_fortran_arg(fp, args): parts = [] for v in args: if v.tinfo == VT.mx: parts.append("const mxArray*") else: parts.append(f"{v.basetype}*") fp.write(", ".join(parts)) def mex_fortran_decls(fp, funcs): fp.write("#ifdef __cplusplus\n" "extern \"C\" { /* Prevent C++ name mangling */\n" "#endif\n\n" "#ifndef MWF77_RETURN\n" "#define MWF77_RETURN int\n" "#endif\n\n") for fc in _fortran_funcs(funcs): if fc.ret: fp.write(f"{fc.ret[0].basetype} ") else: fp.write("MWF77_RETURN ") fp.write(f"MWF77_{fc.funcv}(") _mex_fortran_arg(fp, fc.args) fp.write(");\n") fp.write("\n#ifdef __cplusplus\n" "} /* end extern C */\n" "#endif\n\n") # =================================================================== # Class polymorphism getters # =================================================================== def _mex_casting_getter_type(fp, name): fp.write(f" {name}* p_{name} = NULL;\n" f" sscanf(pbuf, \"{name}:%p\", &p_{name});\n" f" if (p_{name})\n" f" return p_{name};\n\n") def _mex_casting_getter(fp, cname, inherits): fp.write(f"\n{cname}* mxWrapGetP_{cname}(const mxArray* a, const char** e)\n") fp.write("{\n" " char pbuf[128];\n" " if (mxGetClassID(a) == mxDOUBLE_CLASS &&\n" " mxGetM(a)*mxGetN(a) == 1 &&\n" "#if MX_HAS_INTERLEAVED_COMPLEX\n" " ((mxIsComplex(a) ? ((*mxGetComplexDoubles(a)).real == 0 && (*mxGetComplexDoubles(a)).imag == 0) : *mxGetDoubles(a) == 0))\n" "#else\n" " *mxGetPr(a) == 0\n" "#endif\n" " )\n" " return NULL;\n" " if (!mxIsChar(a)) {\n" "#ifdef R2008OO\n" f" mxArray* ap = mxGetProperty(a, 0, \"mwptr\");\n" f" if (ap)\n" f" return mxWrapGetP_{cname}(ap, e);\n" "#endif\n" " *e = \"Invalid pointer\";\n" " return NULL;\n" " }\n" " mxGetString(a, pbuf, sizeof(pbuf));\n\n") _mex_casting_getter_type(fp, cname) for name in inherits: _mex_casting_getter_type(fp, name) fp.write(f" *e = \"Invalid pointer to {cname}\";\n" f" return NULL;\n" f"}}\n\n") def mex_casting_getters(fp, ctx): for parent in sorted(ctx.class_decls.keys()): _mex_casting_getter(fp, parent, ctx.class_decls[parent]) # =================================================================== # Per-stub helpers: declarations, unpack, check, alloc, call, marshal, dealloc # =================================================================== def _declare_type(v): """Return C type string for a variable declaration.""" if is_obj(v.tinfo) or is_array(v.tinfo): if v.devicespec == 'g': return f"{basetype_to_cucomplex(v.basetype)}*" return f"{v.basetype}*" if v.tinfo == VT.rarray: if v.devicespec == 'g': return f"const {basetype_to_cucomplex(v.basetype)}*" return f"const {v.basetype}*" if v.tinfo in (VT.scalar, VT.cscalar, VT.zscalar, VT.r_scalar, VT.r_cscalar, VT.r_zscalar, VT.p_scalar, VT.p_cscalar, VT.p_zscalar): return v.basetype if v.tinfo == VT.string: return "char*" if v.tinfo == VT.mx: if v.iospec == 'i': return "const mxArray*" return "mxArray*" assert False, f"Unknown tinfo {v.tinfo} for {v.name}" # --- Step 1: Declare locals --- def _declare_in_args(fp, args): for v in args: if v.iospec != 'o' and v.tinfo != VT.const: tb = _declare_type(v) if is_array(v.tinfo) or is_obj(v.tinfo) or v.tinfo == VT.string: fp.write(f" {tb:10s} in{v.input_label}_ =0; /* {v.name:10s} */\n") if v.devicespec == 'g': fp.write(f" {'mxGPUArray const':10s} *mxGPUArray_in{v.input_label}_ =0; /* {v.name:10s} */\n") else: fp.write(f" {tb:10s} in{v.input_label}_; /* {v.name:10s} */\n") def _declare_out_args(fp, args): for v in args: if v.iospec == 'o' and v.tinfo != VT.mx: tb = _declare_type(v) if is_array(v.tinfo) or is_obj(v.tinfo) or v.tinfo == VT.string: fp.write(f" {tb:10s} out{v.output_label}_=0; /* {v.name:10s} */\n") if v.devicespec == 'g': fp.write(f" {'mxGPUArray':10s} *mxGPUArray_out{v.output_label}_ =0; /* {v.name:10s} */\n") fp.write(f" {'mwSize':10s} gpu_outdims{v.output_label}_[2] = {{0,0}}; /* {v.name:10s} dims*/\n") else: fp.write(f" {tb:10s} out{v.output_label}_; /* {v.name:10s} */\n") def _declare_dim_args_expr(fp, args): for e in args: fp.write(f" {'mwSize':10s} dim{e.input_label}_; /* {e.value:10s} */\n") def _declare_dim_args_var(fp, vars): for v in vars: if v.qual: _declare_dim_args_expr(fp, v.qual.args) def _declare_args(fp, f): if f.thisv: tb = f"{f.classv}*" fp.write(f" {tb:10s} in0_ =0; /* {f.thisv:10s} */\n") _declare_in_args(fp, f.args) if not nullable_return(f): _declare_out_args(fp, f.ret) _declare_out_args(fp, f.args) _declare_dim_args_var(fp, f.ret) _declare_dim_args_var(fp, f.args) if f.ret or f.args or f.thisv: fp.write("\n") # --- Step 2: Unpack dims --- def _unpack_dims_expr(fp, args): count = 0 for e in args: fp.write(f" dim{e.input_label}_ = (mwSize) mxWrapGetScalar(prhs[{e.input_label}], &mw_err_txt_);\n") count += 1 return count def _unpack_dims_var(fp, vars): count = 0 for v in vars: if v.qual: count += _unpack_dims_expr(fp, v.qual.args) return count def _unpack_dims(fp, f): c = _unpack_dims_var(fp, f.ret) + _unpack_dims_var(fp, f.args) if c: fp.write("\n") # --- Step 3: Check dim consistency --- def _check_dims(fp, args): for v in args: if (v.iospec != 'o' and is_array(v.tinfo) and v.qual and v.qual.args and v.devicespec != 'g'): a = v.qual.args if len(a) > 1: fp.write(f" if (mxGetM(prhs[{v.input_label}]) != dim{a[0].input_label}_ ||\n" f" mxGetN(prhs[{v.input_label}]) != dim{a[1].input_label}_) {{\n" f" mw_err_txt_ = \"Bad argument size: {v.name}\";\n" f" goto mw_err_label;\n" f" }}\n\n") else: fp.write(f" if (mxGetM(prhs[{v.input_label}])*mxGetN(prhs[{v.input_label}]) != dim{a[0].input_label}_) {{\n" f" mw_err_txt_ = \"Bad argument size: {v.name}\";" f" goto mw_err_label;\n" f" }}\n\n") # --- Step 4: Unpack inputs --- def _cast_get_p(fp, ctx, basetype, input_label): fp.write(f" in{input_label}_ = ") if ctx.is_mxarray_type(basetype): fp.write(f"mxWrapGet_{basetype}(prhs[{input_label}], &mw_err_txt_);\n") elif basetype not in ctx.class_decls: fp.write(f"({basetype}*) mxWrapGetP(prhs[{input_label}], \"{basetype}:%p\", &mw_err_txt_);\n") else: fp.write(f"mxWrapGetP_{basetype}(prhs[{input_label}], &mw_err_txt_);\n") fp.write(" if (mw_err_txt_)\n" " goto mw_err_label;\n\n") def _unpack_input_array(fp, v): il = v.input_label bt = v.basetype # --- Regular (copy) path for CPU --- if v.devicespec != 'g': tp = _type_props(bt) cs = _copier_suffix(bt) fp.write(f" if (mxGetM(prhs[{il}])*mxGetN(prhs[{il}]) != 0) {{\n") if complex_tinfo(v) and bt in TYPE_PROPS: # Known complex types: class check + copier fp.write(f" if( mxGetClassID(prhs[{il}]) != {tp.mxclass} )\n" f" mw_err_txt_ = \"Invalid array argument, {tp.mxclass} expected\";\n" f" if (mw_err_txt_) goto mw_err_label;\n" f" in{il}_ = mxWrapGetArray_{cs}{bt}(prhs[{il}], &mw_err_txt_);\n" f" if (mw_err_txt_)\n" f" goto mw_err_label;\n") elif tp.direct_input and v.iospec == 'i': # float/double input-only: class check + direct accessor fp.write(f" if( mxGetClassID(prhs[{il}]) != {tp.mxclass} )\n" f" mw_err_txt_ = \"Invalid array argument, {tp.mxclass} expected\";\n" f" if (mw_err_txt_) goto mw_err_label;\n" f"#if MX_HAS_INTERLEAVED_COMPLEX\n" f" in{il}_ = {tp.accessor}(prhs[{il}]);\n" f"#else\n") if bt == "double": fp.write(f" in{il}_ = mxGetPr(prhs[{il}]);\n") else: fp.write(f" in{il}_ = ({bt}*) mxGetData(prhs[{il}]);\n") fp.write(f"#endif\n") else: # All other types (including float/double inout): copier fp.write(f" in{il}_ = mxWrapGetArray_{cs}{bt}(prhs[{il}], &mw_err_txt_);\n" f" if (mw_err_txt_)\n" f" goto mw_err_label;\n") fp.write(f" }} else\n" f" in{il}_ = NULL;\n") fp.write("\n") # --- GPU path --- if v.devicespec == 'g': if v.iospec in ('i', 'b'): cutype = basetype_to_cucomplex(bt) fp.write(f" // extract input GPU array pointer\n" f" if(!(mxIsGPUArray(prhs[{il}])))\n" f" mw_err_txt_ = \"Invalid array argument, gpuArray expected\";\n" f" if (mw_err_txt_) goto mw_err_label;\n" f" mxGPUArray_in{il}_ = mxGPUCreateFromMxArray(prhs[{il}]);\n" f" in{il}_ = ({cutype} *)mxGPUGetDataReadOnly(mxGPUArray_in{il}_);\n\n") def _unpack_input_string(fp, v): il = v.input_label if not (v.qual and v.qual.args): fp.write(f" in{il}_ = mxWrapGetString(prhs[{il}], &mw_err_txt_);\n" f" if (mw_err_txt_)\n" f" goto mw_err_label;\n") else: sz = _alloc_size_expr(v.qual.args) fp.write(f" in{il}_ = (char*) mxMalloc({sz}*sizeof(char));\n") fp.write(f" if (mxGetString(prhs[{il}], in{il}_, {sz}) != 0) {{\n" f" mw_err_txt_ = \"Invalid string argument\";\n" f" goto mw_err_label;\n" f" }}\n") fp.write("\n") def _unpack_inputs_var(fp, ctx, args): for v in args: if v.iospec == 'o': continue if is_obj(v.tinfo): _cast_get_p(fp, ctx, v.basetype, v.input_label) elif is_array(v.tinfo): _unpack_input_array(fp, v) elif v.tinfo in (VT.scalar, VT.r_scalar, VT.p_scalar): il = v.input_label bt = v.basetype tp = _type_props(bt) fp.write(f" if( mxGetClassID(prhs[{il}]) != {tp.scalar_class} )\n" f" mw_err_txt_ = \"Invalid scalar argument, {tp.scalar_class} expected\";\n" f" if (mw_err_txt_) goto mw_err_label;\n" f" in{il}_ = ({bt}) {tp.scalar_getter}(prhs[{il}], &mw_err_txt_);\n" f" if (mw_err_txt_)\n" f" goto mw_err_label;\n") if bt != "char": fp.write("\n") elif v.tinfo in (VT.cscalar, VT.zscalar, VT.r_cscalar, VT.r_zscalar, VT.p_cscalar, VT.p_zscalar): il = v.input_label bt = v.basetype tp = _type_props(bt) fp.write(f" if( mxGetClassID(prhs[{il}]) != {tp.scalar_class} )\n" f" mw_err_txt_ = \"Invalid scalar argument, {tp.scalar_class} expected\";\n" f" if (mw_err_txt_) goto mw_err_label;\n") cs = _copier_suffix(bt) fp.write(f" mxWrapGetScalar_{cs}{bt}(&in{il}_, prhs[{il}]);\n\n") elif v.tinfo == VT.string: _unpack_input_string(fp, v) elif v.tinfo == VT.mx: fp.write(f" in{v.input_label}_ = prhs[{v.input_label}];\n\n") def _unpack_inputs(fp, ctx, f): if f.thisv: _cast_get_p(fp, ctx, f.classv, 0) _unpack_inputs_var(fp, ctx, f.args) # --- Step 5: Null-check objects/this --- def _check_inputs(fp, args): for v in args: if v.iospec != 'o' and v.tinfo in (VT.obj, VT.r_obj): fp.write(f" if (!in{v.input_label}_) {{\n" f" mw_err_txt_ = \"Argument {v.name} cannot be null\";\n" f" goto mw_err_label;\n" f" }}\n") # --- Step 6: Allocate outputs --- def _alloc_output(fp, ctx, args, return_flag): for v in args: if v.iospec == 'o': if v.devicespec != 'g': if not return_flag and is_obj(v.tinfo) and ctx.is_mxarray_type(v.basetype): fp.write(f" out{v.output_label}_ = mxWrapAlloc_{v.basetype}();\n") elif is_array(v.tinfo): fp.write(f" out{v.output_label}_ = ({v.basetype}*) mxMalloc({_alloc_size_expr(v.qual.args)}*sizeof({v.basetype}));\n") elif v.tinfo == VT.rarray: fp.write(f" out{v.output_label}_ = ({v.basetype}*) NULL;\n") elif v.tinfo == VT.string: fp.write(f" out{v.output_label}_ = (char*) mxMalloc({_alloc_size_expr(v.qual.args)}*sizeof(char));\n") if v.devicespec == 'g': da = v.qual.args ndims = 2 if len(da) == 2 else 1 mtype = "mxCOMPLEX" if complex_tinfo(v) else "mxREAL" mxcid = basetype_to_mxclassid(v.basetype) cutype = basetype_to_cucomplex(v.basetype) if ndims == 2: fp.write(f" gpu_outdims{v.output_label}_[0] = dim{da[0].input_label}_; gpu_outdims{v.output_label}_[1] = dim{da[1].input_label}_;\n") else: fp.write(f" gpu_outdims{v.output_label}_[0] = dim{da[0].input_label}_;\n") fp.write(f" mxGPUArray_out{v.output_label}_ = mxGPUCreateGPUArray({ndims}, gpu_outdims{v.output_label}_, {mxcid}, {mtype}, MX_GPU_DO_NOT_INITIALIZE);\n") fp.write(f" out{v.output_label}_ = ({cutype} *)mxGPUGetData(mxGPUArray_out{v.output_label}_);\n\n") def _alloc_outputs(fp, ctx, f): if not nullable_return(f): _alloc_output(fp, ctx, f.ret, True) _alloc_output(fp, ctx, f.args, False) # --- Step 7: Profiler --- def _record_call(fp, f): fp.write(f" if (mexprofrecord_)\n" f" mexprofrecord_[{f.id}]++;\n") # --- Step 8: Make the call --- def _make_call_args(fp, args, first): for v in args: if not first: fp.write(", ") n = vname(v) if v.tinfo in (VT.obj, VT.r_obj): fp.write(f"*{n}") elif v.tinfo == VT.mx and v.iospec == 'o': fp.write(f"plhs+{v.output_label}") elif v.tinfo in (VT.p_scalar, VT.p_cscalar, VT.p_zscalar): fp.write(f"&{n}") elif v.tinfo == VT.const: fp.write(v.name) else: fp.write(n) first = False def _make_call_expr(fp, f): """Write the function call expression (without assignment/semicolon).""" if f.thisv: fp.write("in0_->") if f.funcv == "new": fp.write(f"new {f.classv}(") else: if f.fort: fp.write("MWF77_") fp.write(f"{f.funcv}(") _make_call_args(fp, f.args, True) fp.write(")") def _make_stmt(fp, ctx, f): if f.thisv: fp.write(" if (!in0_) {\n" " mw_err_txt_ = \"Cannot dispatch to NULL\";\n" " goto mw_err_label;\n" " }\n") if ctx.mw_generate_catch: fp.write(" try {\n ") if f.ret: v = f.ret[0] if v.tinfo == VT.obj: if ctx.is_mxarray_type(v.basetype): fp.write(f" plhs[0] = mxWrapSet_{v.basetype}(&(") _make_call_expr(fp, f) fp.write("));\n") else: fp.write(f" out0_ = new {v.basetype}(") _make_call_expr(fp, f) fp.write(");\n") elif is_array(v.tinfo): fp.write(f" plhs[0] = mxWrapReturn_{v.basetype}(") _make_call_expr(fp, f) fp.write(", ") args = v.qual.args if len(args) == 2: fp.write(f" dim{args[0].input_label}_, dim{args[1].input_label}_);\n") else: fp.write(f"{_alloc_size_expr(args)}, 1);\n") elif v.tinfo in (VT.scalar, VT.r_scalar, VT.cscalar, VT.r_cscalar, VT.zscalar, VT.r_zscalar): fp.write(" out0_ = ") _make_call_expr(fp, f) fp.write(";\n") elif v.tinfo == VT.string: fp.write(" plhs[0] = mxWrapStrncpy(") _make_call_expr(fp, f) fp.write(");\n") elif v.tinfo == VT.mx: fp.write(" plhs[0] = ") _make_call_expr(fp, f) fp.write(";\n") elif v.tinfo == VT.p_obj: if ctx.is_mxarray_type(v.basetype): fp.write(f" plhs[0] = mxWrapSet_{v.basetype}(") _make_call_expr(fp, f) fp.write(");\n") else: fp.write(" out0_ = ") _make_call_expr(fp, f) fp.write(";\n") elif v.tinfo in (VT.p_scalar, VT.p_cscalar, VT.p_zscalar): fp.write(f" plhs[0] = mxWrapReturn_{v.basetype}(") _make_call_expr(fp, f) fp.write(", 1, 1);\n") elif v.tinfo == VT.r_obj: if ctx.is_mxarray_type(v.basetype): fp.write(f" plhs[0] = mxWrapSet_{v.basetype}(&(") _make_call_expr(fp, f) fp.write("));\n") else: fp.write(" out0_ = &(") _make_call_expr(fp, f) fp.write(");\n") else: fp.write(" ") _make_call_expr(fp, f) fp.write(";\n") if ctx.mw_generate_catch: fp.write(f" }} catch(...) {{\n" f" mw_err_txt_ = \"Caught C++ exception from {f.funcv}\";\n" f" }}\n" f" if (mw_err_txt_)\n" f" goto mw_err_label;\n") # --- Step 9: Marshal results --- def _marshal_array(fp, v): il = v.input_label ol = v.output_label bt = v.basetype n = vname(v) if v.devicespec != 'g': da = v.qual.args mtype = "mxCOMPLEX" if complex_tinfo(v) else "mxREAL" ws = " " is_single = _type_props(bt).is_single if v.tinfo == VT.rarray: ws = " " fp.write(f" if (out{ol}_ == NULL) {{\n") fp.write(f" plhs[{ol}] = mxCreateDoubleMatrix(0,0, mxREAL);\n") fp.write(f" }} else {{\n") if not da: # No dims — inout array if is_single: fp.write(f"{ws}plhs[{ol}] = mxCreateNumericMatrix(mxGetM(prhs[{il}]), mxGetN(prhs[{il}]), mxSINGLE_CLASS, {mtype});\n") fp.write(f"{ws}mxWrapCopy_single_{bt}(plhs[{ol}], in{il}_, ") else: fp.write(f"{ws}plhs[{ol}] = mxCreateDoubleMatrix(mxGetM(prhs[{il}]), mxGetN(prhs[{il}]), {mtype});\n") fp.write(f"{ws}mxWrapCopy_{bt}(plhs[{ol}], in{il}_, ") fp.write(f"mxGetM(prhs[{il}])*mxGetN(prhs[{il}])") fp.write(");\n") elif len(da) == 1: # 1D if is_single: fp.write(f"{ws}plhs[{ol}] = mxCreateNumericMatrix(dim{da[0].input_label}_, 1, mxSINGLE_CLASS, {mtype});\n") fp.write(f"{ws}mxWrapCopy_single_{bt}(plhs[{ol}], {n}, ") else: fp.write(f"{ws}plhs[{ol}] = mxCreateDoubleMatrix(dim{da[0].input_label}_, 1, {mtype});\n") fp.write(f"{ws}mxWrapCopy_{bt}(plhs[{ol}], {n}, ") fp.write(f"dim{da[0].input_label}_") fp.write(");\n") elif len(da) == 2: # 2D if is_single: fp.write(f"{ws}plhs[{ol}] = mxCreateNumericMatrix(dim{da[0].input_label}_, dim{da[1].input_label}_, mxSINGLE_CLASS, {mtype});\n") fp.write(f"{ws}mxWrapCopy_single_{bt}(plhs[{ol}], {n}, ") else: fp.write(f"{ws}plhs[{ol}] = mxCreateDoubleMatrix(dim{da[0].input_label}_, dim{da[1].input_label}_, {mtype});\n") fp.write(f"{ws}mxWrapCopy_{bt}(plhs[{ol}], {n}, ") fp.write(f"dim{da[0].input_label}_*dim{da[1].input_label}_") fp.write(");\n") else: # 3D+ — flatten to 1D sz = _alloc_size_expr(da) if is_single: fp.write(f"{ws}plhs[{ol}] = mxCreateNumericMatrix({sz}, 1, mxSINGLE_CLASS, {mtype});\n") fp.write(f"{ws}mxWrapCopy_single_{bt}(plhs[{ol}], {n}, ") else: fp.write(f"{ws}plhs[{ol}] = mxCreateDoubleMatrix({sz}, 1, {mtype});\n") fp.write(f"{ws}mxWrapCopy_{bt}(plhs[{ol}], {n}, ") fp.write(sz) fp.write(");\n") if v.tinfo == VT.rarray: fp.write(" }\n") # GPU marshal if v.devicespec == 'g': if v.iospec == 'b': fp.write(f" plhs[{ol}] = prhs[{il}];\n") if v.iospec == 'o': fp.write(f" plhs[{ol}] = mxGPUCreateMxArrayOnGPU(mxGPUArray_out{ol}_);\n") def _marshal_result(fp, ctx, v, return_flag): n = vname(v) ol = v.output_label bt = v.basetype if is_obj(v.tinfo) and ctx.is_mxarray_type(bt): if not return_flag: fp.write(f" plhs[{ol}] = mxWrapSet_{bt}({n});\n") elif is_obj(v.tinfo): fp.write(f" plhs[{ol}] = mxWrapCreateP(out{ol}_, \"{bt}:%p\");\n") elif is_array(v.tinfo) or v.tinfo == VT.rarray: _marshal_array(fp, v) elif v.tinfo in (VT.scalar, VT.r_scalar, VT.p_scalar): _interleaved_branch(fp, f" plhs[{ol}] = mxCreateDoubleMatrix(1, 1, mxREAL);\n" f" *mxGetDoubles(plhs[{ol}]) = {n};\n", f" plhs[{ol}] = mxCreateDoubleMatrix(1, 1, mxREAL);\n" f" *mxGetPr(plhs[{ol}]) = {n};\n") elif v.tinfo in (VT.cscalar, VT.zscalar, VT.r_cscalar, VT.r_zscalar, VT.p_cscalar, VT.p_zscalar): _interleaved_branch(fp, f" plhs[{ol}] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX);\n" f" mxGetComplexDoubles(plhs[{ol}])->real = real_{bt}({n});\n" f" mxGetComplexDoubles(plhs[{ol}])->imag = imag_{bt}({n});\n", f" plhs[{ol}] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX);\n" f" *mxGetPr(plhs[{ol}]) = real_{bt}({n});\n" f" *mxGetPi(plhs[{ol}]) = imag_{bt}({n});\n") elif v.tinfo == VT.string: fp.write(f" plhs[{ol}] = mxCreateString({n});\n") def _marshal_results_var(fp, ctx, vars, return_flag): for v in vars: if v.iospec != 'i': _marshal_result(fp, ctx, v, return_flag) def _marshal_results(fp, ctx, f): if not nullable_return(f): _marshal_results_var(fp, ctx, f.ret, True) _marshal_results_var(fp, ctx, f.args, False) # --- Step 10: Dealloc --- def _dealloc_var(fp, ctx, vars, return_flag): for v in vars: if v.devicespec != 'g': if is_array(v.tinfo) or v.tinfo == VT.string: if v.iospec == 'o': fp.write(f" if (out{v.output_label}_) mxFree(out{v.output_label}_);\n") elif v.iospec == 'b' or not (v.basetype == "double" or v.basetype == "float"): fp.write(f" if (in{v.input_label}_) mxFree(in{v.input_label}_);\n") elif is_obj(v.tinfo) and ctx.is_mxarray_type(v.basetype): if v.iospec in ('i', 'b'): fp.write(f" if (in{v.input_label}_) mxWrapFree_{v.basetype}(in{v.input_label}_);\n") elif v.iospec == 'o' and not return_flag: fp.write(f" if (out{v.output_label}_) mxWrapFree_{v.basetype}(out{v.output_label}_);\n") if v.devicespec == 'g': if v.iospec in ('i', 'b'): fp.write(f" if (mxGPUArray_in{v.input_label}_) mxGPUDestroyGPUArray(mxGPUArray_in{v.input_label}_);\n") if v.iospec == 'o': fp.write(f" if (mxGPUArray_out{v.output_label}_) mxGPUDestroyGPUArray(mxGPUArray_out{v.output_label}_);\n") def _dealloc(fp, ctx, f): if not nullable_return(f): _dealloc_var(fp, ctx, f.ret, True) _dealloc_var(fp, ctx, f.args, False) # =================================================================== # Print a single MEX stub # =================================================================== def _print_c_comment(fp, f): fp.write(f"/* ---- {f.fname}: {f.line} ----\n") fp.write(f" * {print_func(f)}") # Preserve original behavior: only print first duplicate if f.same: fsame = f.same[0] fp.write(f" * Also at {fsame.fname}: {fsame.line}\n") fp.write(" */\n") def _print_mex_stub(fp, ctx, f): _print_c_comment(fp, f) ids = id_string(ctx, f) fp.write(f"static const char* stubids{f.id}_ = \"{ids}\";\n\n") fp.write(f"void mexStub{f.id}(int nlhs, mxArray* plhs[],\n" f" int nrhs, const mxArray* prhs[])\n" f"{{\n" f" const char* mw_err_txt_ = 0;\n") _declare_args(fp, f) _unpack_dims(fp, f) _check_dims(fp, f.args) _unpack_inputs(fp, ctx, f) _check_inputs(fp, f.args) _alloc_outputs(fp, ctx, f) _record_call(fp, f) _make_stmt(fp, ctx, f) _marshal_results(fp, ctx, f) fp.write("\nmw_err_label:\n") _dealloc(fp, ctx, f) fp.write(" if (mw_err_txt_)\n" " mexErrMsgTxt(mw_err_txt_);\n" "}\n\n") # =================================================================== # Print all stubs, dispatch table, mexFunction # =================================================================== def _print_mex_stubs(fp, ctx, funcs): for f in funcs: _print_mex_stub(fp, ctx, f) def _print_mex_stub_table(fp, funcs): # Build id → stub_id map id_to_stub = {} maxid = 0 for fc in funcs: id_to_stub[fc.id] = fc.id if fc.id > maxid: maxid = fc.id for fsame in fc.same: id_to_stub[fsame.id] = fc.id if fsame.id > maxid: maxid = fsame.id if maxid <= 0: return fp.write("typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[],\n" " int nrhs, const mxArray* prhs[]);\n\n" "static mwStubFunc_t mwStubs_[] = {\n" " NULL") for i in range(1, maxid + 1): fp.write(",\n") if i in id_to_stub: fp.write(f" mexStub{id_to_stub[i]}") else: fp.write(" NULL") fp.write("\n};\n\n") fp.write(f"static int mwNumStubs_ = {maxid};\n\n") def _make_profile_output(fp, funcs, printfunc): fp.write(f" if (!mexprofrecord_)\n" f" {printfunc}\"Profiler inactive\\n\");\n") for fc in funcs: fp.write(f" {printfunc}\"%d calls to {fc.fname}:{fc.line}") # Preserve original behavior: only print first duplicate if fc.same: fp.write(f" ({fc.same[0].fname}:{fc.same[0].line})") fp.write(f"\\n\", mexprofrecord_[{fc.id}]);\n") def _print_mex_else_cases(fp, funcs): for fc in funcs: fp.write(f" else if (strcmp(id, stubids{fc.id}_) == 0)\n" f" mexStub{fc.id}(nlhs,plhs, nrhs-1,prhs+1);\n") maxid = max_routine_id(funcs) fp.write(f" else if (strcmp(id, \"*profile on*\") == 0) {{\n" f" if (!mexprofrecord_) {{\n" f" mexprofrecord_ = (int*) malloc({maxid+1} * sizeof(int));\n" f" mexLock();\n" f" }}\n" f" memset(mexprofrecord_, 0, {maxid+1} * sizeof(int));\n" f" }} else if (strcmp(id, \"*profile off*\") == 0) {{\n" f" if (mexprofrecord_) {{\n" f" free(mexprofrecord_);\n" f" mexUnlock();\n" f" }}\n" f" mexprofrecord_ = NULL;\n" f" }} else if (strcmp(id, \"*profile report*\") == 0) {{\n") _make_profile_output(fp, funcs, "mexPrintf(") fp.write(f" }} else if (strcmp(id, \"*profile log*\") == 0) {{\n" f" FILE* logfp;\n" f" if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0)\n" f" mexErrMsgTxt(\"Must have two string arguments\");\n" f" logfp = fopen(id, \"w+\");\n" f" if (!logfp)\n" f" mexErrMsgTxt(\"Cannot open log for output\");\n") _make_profile_output(fp, funcs, "fprintf(logfp, ") fp.write(" fclose(logfp);\n") fp.write(" } else\n" " mexErrMsgTxt(\"Unknown identifier\");\n") # =================================================================== # Top-level: print_mex_init + print_mex_file # =================================================================== MWRAP_BANNER = ( "/* --------------------------------------------------- */\n" "/* Automatically generated by mwrap */\n" "/* --------------------------------------------------- */\n\n" ) MEX_BASE = ( "/* ----\n" " */\n" "void mexFunction(int nlhs, mxArray* plhs[],\n" " int nrhs, const mxArray* prhs[])\n" "{\n" " if (nrhs == 0) {\n" " mexPrintf(\"Mex function installed\\n\");\n" " return;\n" " }\n\n" " /* Fast path: integer stub ID */\n" " if (!mxIsChar(prhs[0])) {\n" " int stub_id = (int) mxGetScalar(prhs[0]);\n" " if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id])\n" " mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1);\n" " else\n" " mexErrMsgTxt(\"Unknown function ID\");\n" " return;\n" " }\n\n" ) MEX_BASE_IF = ( " char id[1024];\n" " if (mxGetString(prhs[0], id, sizeof(id)) != 0)\n" " mexErrMsgTxt(\"Identifier should be a string\");\n" ) def print_mex_init(fp, ctx, support_text): """Write the MEX file header: banner + runtime support + complex/GPU includes.""" fp.write(MWRAP_BANNER) fp.write(support_text) fp.write("\n") if ctx.mw_use_gpu: fp.write("#include \n\n") if ctx.mw_use_c99_complex: mex_c99_complex(fp) elif ctx.mw_use_cpp_complex: mex_cpp_complex(fp) if ctx.mw_use_gpu: mex_gpucpp_complex(fp) def print_mex_file(fp, ctx, funcs): """Write the rest of the MEX file: copiers, getters, stubs, dispatch.""" if ctx.mw_use_int32_t or ctx.mw_use_int64_t or ctx.mw_use_uint32_t or ctx.mw_use_uint64_t: fp.write("#include \n\n") mex_define_copiers(fp, ctx) mex_casting_getters(fp, ctx) if has_fortran(funcs): mex_define_fnames(fp, funcs) mex_fortran_decls(fp, funcs) _print_mex_stubs(fp, ctx, funcs) _print_mex_stub_table(fp, funcs) fp.write(MEX_BASE) fp.write("\n") if ctx.mw_use_gpu: fp.write(" mxInitGPU();\n") fp.write("\n") fp.write(MEX_BASE_IF) _print_mex_else_cases(fp, funcs) fp.write("}\n\n") zgimbutas-mwrap-25008ce/python/mwrap_lexer.py000066400000000000000000000243041515063637600214320ustar00rootroot00000000000000""" mwrap_lexer.py — Line-oriented lexer for .mw files. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ import re import sys import os from enum import Enum, auto from dataclasses import dataclass from typing import Optional, TextIO, List class TokenType(Enum): ID = auto() NUMBER = auto() STRING = auto() NEW = auto() FORTRAN = auto() INPUT = auto() OUTPUT = auto() INOUT = auto() CLASS = auto() TYPEDEF = auto() CPU = auto() GPU = auto() PUNCT = auto() # single characters: ( ) , ; * & [ ] . - > = : NON_C_LINE = auto() EOF = auto() KEYWORDS = { "new": TokenType.NEW, "FORTRAN": TokenType.FORTRAN, "input": TokenType.INPUT, "output": TokenType.OUTPUT, "inout": TokenType.INOUT, "class": TokenType.CLASS, "typedef": TokenType.TYPEDEF, "cpu": TokenType.CPU, "gpu": TokenType.GPU, } # Regex for tokenising a '#' line body _TOKEN_RE = re.compile( r"(//[^\n]*)" # comment (rest of line) — skip r"|('[^'\n]*'?)" # string literal (single-quoted) r"|((?:::)?[_a-zA-Z][_a-zA-Z0-9]*(?:::(?:[_a-zA-Z][_a-zA-Z0-9]*))*)" # ID (may have ::) r"|([0-9]+)" # number r"|([->()\[\],;*&=:.])" # punctuation r"|[ \t\r]+" # whitespace — skip ) @dataclass class Token: type: TokenType value: str line: int def _is_name_char(c): return c.isalnum() or c == '_' def _fname_scan_line(text): """Extract function name from '@function ...' tail, return name.m.""" paren = text.find('(') if paren < 0: paren = len(text) # Walk back from paren to find last alnum end = paren while end > 0 and not _is_name_char(text[end - 1]): end -= 1 start = end while start > 0 and _is_name_char(text[start - 1]): start -= 1 name = text[start:end] return name + ".m" class Lexer: """Line-oriented lexer for .mw files. Usage: lex = Lexer(outfp, outcfp, mbatching_flag, listing_flag) for tok in lex.lex_file(filename): ... # only tokens from '#' lines; NON_C_LINE for other lines """ def __init__(self, outfp=None, outcfp=None, mbatching_flag=False, listing_flag=False): self.outfp: Optional[TextIO] = outfp self.outcfp: Optional[TextIO] = outcfp self.mbatching_flag: bool = mbatching_flag self.listing_flag: bool = listing_flag self.linenum: int = 0 self.current_ifname: str = "" # File include stack self._file_stack: List = [] # [(fp, linenum, ifname), ...] self._current_fp: Optional[TextIO] = None # ------------------------------------------------------------------ # public interface # ------------------------------------------------------------------ def lex_file(self, filename): """Yield Token objects from *filename*.""" fp = open(filename, "r") self._current_fp = fp self.current_ifname = filename self.linenum = 1 yield from self._lex_stream() # ------------------------------------------------------------------ # directive handlers # ------------------------------------------------------------------ def _handle_block_c(self, line): """Process a line in block C mode. Returns False when block ends.""" stripped = line.rstrip('\r\n') if re.match(r'^\$\][ \t\r]*$', stripped): self.linenum += 1 return False if self.outcfp: self.outcfp.write(line) self.linenum += 1 return True def _handle_comment(self): """Handle // comment line.""" self.linenum += 1 yield Token(TokenType.NON_C_LINE, "", self.linenum - 1) def _handle_function(self, stripped): """Handle @function directive.""" tail = stripped[len("@function"):] tail = tail.rstrip('\r\n') fname = _fname_scan_line(tail) if self.mbatching_flag: if self.outfp: self.outfp.close() try: self.outfp = open(fname, "w") except OSError: print(f"Error: Could not write {fname}", file=sys.stderr) sys.exit(1) if self.listing_flag: print(fname) if self.outfp: self.outfp.write(f"function{tail}\n") self.linenum += 1 yield Token(TokenType.NON_C_LINE, "", self.linenum - 1) def _handle_include(self, stripped): """Handle @include directive. Pushes current file onto stack.""" rest = stripped[len("@include"):].strip().rstrip('\r\n') if len(self._file_stack) >= 10: print("Error: Includes nested too deeply", file=sys.stderr) sys.exit(1) self._file_stack.append( (self._current_fp, self.linenum, self.current_ifname)) try: new_fp = open(rest, "r") except OSError: print(f"Error: Could not read '{rest}'", file=sys.stderr) sys.exit(1) self.current_ifname = rest self.linenum = 1 self._current_fp = new_fp def _handle_redirect(self, stripped): """Handle @ redirect directive.""" rest = stripped[1:].strip().rstrip('\r\n') if self.mbatching_flag: if self.outfp: self.outfp.close() self.outfp = None if rest: try: self.outfp = open(rest, "w") except OSError: print(f"Error: Could not write {rest}", file=sys.stderr) sys.exit(1) if self.listing_flag and rest: print(rest) self.linenum += 1 yield Token(TokenType.NON_C_LINE, "", self.linenum - 1) def _handle_dollar_line(self, stripped): """Handle $ single-line C pass-through.""" rest = stripped[1:] if self.outcfp: self.outcfp.write(rest) self.linenum += 1 yield Token(TokenType.NON_C_LINE, "", self.linenum - 1) def _handle_hash_line(self, stripped): """Handle # C declaration line — tokenise.""" body = stripped[1:].rstrip('\r\n') yield from self._tokenize_c_line(body, self.linenum) self.linenum += 1 # ------------------------------------------------------------------ # internal line-by-line driver # ------------------------------------------------------------------ def _lex_stream(self): """Process all lines from self._current_fp, yielding tokens.""" in_block_c = False while True: raw_line = self._current_fp.readline() if raw_line == "": # End of current file if self._file_stack: self._current_fp.close() self._current_fp, self.linenum, self.current_ifname = self._file_stack.pop() continue else: return # real EOF # Strip the trailing newline for processing but track it line = raw_line # --- block C mode ($[ ... $]) --- if in_block_c: in_block_c = self._handle_block_c(line) continue # Determine line prefix — compute leading whitespace stripped = line.lstrip(' \t') leading_ws = line[:len(line) - len(stripped)] # In the original Flex lexer, leading [ \t] in INITIAL state is # always written to outfp regardless of what prefix follows. # We replicate this for all prefix types except pure text lines # (which include their own leading whitespace in the full line). if leading_ws and self.outfp and ( stripped.startswith("$") or stripped.startswith("#") or stripped.startswith("@") or stripped.startswith("//")): self.outfp.write(leading_ws) # $[ block start if re.match(r'^\$\[[ \t\r]*\n?$', stripped): in_block_c = True self.linenum += 1 continue if stripped.startswith("//"): yield from self._handle_comment() continue if stripped.startswith("@function"): yield from self._handle_function(stripped) continue if stripped.startswith("@include"): self._handle_include(stripped) continue if stripped.startswith("@"): yield from self._handle_redirect(stripped) continue if stripped.startswith("$") and not stripped.startswith("$["): yield from self._handle_dollar_line(stripped) continue if stripped.startswith("#"): yield from self._handle_hash_line(stripped) continue # Text line — copy to MATLAB output if self.outfp: self.outfp.write(line) self.linenum += 1 yield Token(TokenType.NON_C_LINE, "", self.linenum - 1) # ------------------------------------------------------------------ # tokenise a single '#' line body # ------------------------------------------------------------------ def _tokenize_c_line(self, body, line): """Yield tokens for the body of a '#' line.""" for m in _TOKEN_RE.finditer(body): comment, string, ident, number, punct = m.groups() if comment: break # rest of line is a comment if string: yield Token(TokenType.STRING, string, line) elif ident: tt = KEYWORDS.get(ident, TokenType.ID) yield Token(tt, ident, line) elif number: yield Token(TokenType.NUMBER, number, line) elif punct: yield Token(TokenType.PUNCT, punct, line) zgimbutas-mwrap-25008ce/python/mwrap_mgen.py000066400000000000000000000026371515063637600212460ustar00rootroot00000000000000""" mwrap_mgen.py — MATLAB stub generator. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ from mwrap_ast import VT def _output_arg_names(args): """Collect names of output/inout arguments.""" return [v.name for v in args if v.iospec in ('o', 'b')] def _input_arg_strs(args): """Collect input argument strings (with leading ', ').""" parts = [] for v in args: if v.tinfo == VT.const: parts.append(", 0") elif v.iospec in ('i', 'b'): parts.append(f", {v.name}") return parts def _dim_arg_strs(vars): """Collect dimension argument strings (with leading ', ').""" parts = [] for v in vars: if v.qual: for e in v.qual.args: parts.append(f", {e.value}") return parts def print_matlab_call(fp, f, mexfunc): """Emit MATLAB stub for function call f.""" fp.write(f"mex_id_ = {f.id};\n") out_names = _output_arg_names(f.ret) + _output_arg_names(f.args) if out_names: fp.write(f"[{', '.join(out_names)}] = ") rhs = [f"mex_id_"] if f.thisv: rhs.append(f", {f.thisv}") rhs.extend(_input_arg_strs(f.args)) rhs.extend(_dim_arg_strs(f.ret)) rhs.extend(_dim_arg_strs(f.args)) fp.write(f"{mexfunc}({''.join(rhs)});\n") zgimbutas-mwrap-25008ce/python/mwrap_parser.py000066400000000000000000000354101515063637600216070ustar00rootroot00000000000000""" mwrap_parser.py — Recursive descent parser for mwrap .mw files. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ import sys from mwrap_ast import ( Expr, TypeQual, Var, Func, VT, promote_int, id_string, add_inherits, ) from mwrap_lexer import Lexer, Token, TokenType from mwrap_typecheck import typecheck from mwrap_mgen import print_matlab_call class ParseError(Exception): pass class Parser: """Recursive descent parser for mwrap '#' lines. Usage: parser = Parser(lexer, ctx, mexfunc=mexfunc) for tok in lexer.lex_file(filename): parser.feed(tok) # After all files: funcs = parser.funcs # list[Func] err_flag = parser.err_flag """ def __init__(self, lexer, ctx, mexfunc="mexfunction"): self.lexer = lexer self.ctx = ctx self.mexfunc = mexfunc # Function list self.funcs = [] self.func_id = 0 self.func_lookup = {} # id_string -> first Func with that sig # Error tracking self.type_errs = 0 self.err_flag = 0 # Token buffer for current '#' line self._tokens = [] self._pos = 0 self._collecting = False # True while inside a '#' line # ------------------------------------------------------------------ # Token stream interface # ------------------------------------------------------------------ def feed(self, tok): """Feed one token from the lexer.""" if tok.type == TokenType.EOF: self._flush_pending(tok) return if tok.type == TokenType.NON_C_LINE: self._flush_pending(tok) return # Accumulate tokens from a '#' line self._tokens.append(tok) # A ';' terminates a statement — parse it if tok.type == TokenType.PUNCT and tok.value == ';': self._parse_line() self._tokens.clear() def _flush_pending(self, tok): """Report error if there are tokens pending without a ';'.""" if self._tokens: tname = "NON_C_LINE" if tok.type == TokenType.NON_C_LINE else "$end" fname = self.lexer.current_ifname line = tok.line print(f"Parse error ({fname}:{line}): syntax error, unexpected {tname}, expecting ';'", file=sys.stderr) self.err_flag += 1 self._tokens.clear() def finish_file(self): """Call after all tokens from one input file have been fed.""" # Flush any pending tokens (missing ';' at EOF) if self._tokens: fname = self.lexer.current_ifname line = self.lexer.linenum print(f"Parse error ({fname}:{line}): syntax error, unexpected $end, expecting ';'", file=sys.stderr) self.err_flag += 1 self._tokens.clear() if self.type_errs: print(f"{self.lexer.current_ifname}: {self.type_errs} type errors detected", file=sys.stderr) self.err_flag += self.type_errs self.type_errs = 0 # ------------------------------------------------------------------ # Token access helpers # ------------------------------------------------------------------ def _peek(self): if self._pos < len(self._tokens): return self._tokens[self._pos] return Token(TokenType.EOF, "", 0) def _advance(self): tok = self._peek() self._pos += 1 return tok def _expect(self, ttype, value=None): tok = self._advance() if tok.type != ttype or (value is not None and tok.value != value): exp = f"{ttype.name}" if value: exp += f" '{value}'" self._error(f"Expected {exp}, got {tok.type.name} '{tok.value}'") return tok def _expect_punct(self, ch): return self._expect(TokenType.PUNCT, ch) def _at(self, ttype, value=None): t = self._peek() if t.type != ttype: return False if value is not None and t.value != value: return False return True def _at_punct(self, ch): return self._at(TokenType.PUNCT, ch) def _line(self): """Current line number for error messages.""" if self._tokens: return self._tokens[0].line return self.lexer.linenum def _error(self, msg): fname = self.lexer.current_ifname line = self._line() print(f"Parse error ({fname}:{line}): {msg}", file=sys.stderr) raise ParseError(msg) # ------------------------------------------------------------------ # Top-level statement parse # ------------------------------------------------------------------ def _parse_line(self): """Parse one complete '#' line (already accumulated in _tokens).""" self._pos = 0 try: self._statement() except ParseError: self.err_flag += 1 def _statement(self): """statement ::= tdef | classdef | basevar '=' funcall | funcall""" tok = self._peek() if tok.type == TokenType.TYPEDEF: self._tdef() return if tok.type == TokenType.CLASS: self._classdef() return # Distinguish: basevar = funcall vs funcall # A funcall starts with: ID -> ... | ID ( | FORTRAN ID | NEW ID # A basevar starts with: ID ID or ID qual ID # The disambiguator: look for '=' before '(' or ';' if self._has_assignment(): bv = self._basevar() self._expect_punct('=') fc = self._funcall() fc.ret = [bv] self._finish_func(fc) else: fc = self._funcall() self._finish_func(fc) def _has_assignment(self): """Lookahead: is there a '=' before '(' or ';'?""" depth = 0 for i in range(len(self._tokens)): t = self._tokens[i] if t.type == TokenType.PUNCT: if t.value == '[': depth += 1 elif t.value == ']': depth -= 1 elif depth == 0 and t.value == '=': return True elif depth == 0 and t.value == '(': return False elif depth == 0 and t.value == ';': return False return False # ------------------------------------------------------------------ # typedef / classdef # ------------------------------------------------------------------ def _tdef(self): """TYPEDEF ID ID ';'""" self._expect(TokenType.TYPEDEF) space = self._expect(TokenType.ID).value name = self._expect(TokenType.ID).value self._expect_punct(';') if space == "numeric": self.ctx.add_scalar_type(name) elif space == "dcomplex": self.ctx.add_zscalar_type(name) elif space == "fcomplex": self.ctx.add_cscalar_type(name) elif space == "mxArray": self.ctx.add_mxarray_type(name) else: print(f"Unrecognized typespace: {space}", file=sys.stderr) self.type_errs += 1 def _classdef(self): """CLASS ID ':' inheritslist ';'""" self._expect(TokenType.CLASS) child = self._expect(TokenType.ID).value self._expect_punct(':') parents = self._inheritslist() self._expect_punct(';') add_inherits(self.ctx, child, parents) def _inheritslist(self): """ID (',' ID)* — returns list[str]""" result = [self._expect(TokenType.ID).value] while self._at_punct(','): self._advance() result.append(self._expect(TokenType.ID).value) return result # ------------------------------------------------------------------ # funcall / func # ------------------------------------------------------------------ def _funcall(self): """funcall ::= func '(' args ')' ';'""" f = self._func() self._expect_punct('(') f.args = self._args() self._expect_punct(')') self._expect_punct(';') return f def _func(self): """func ::= ID '->' ID '.' ID | ID | FORTRAN ID | NEW ID""" tok = self._peek() if tok.type == TokenType.FORTRAN: self._advance() name = self._expect(TokenType.ID).value f = Func(None, None, name, self.lexer.current_ifname, self._line()) f.fort = True return f if tok.type == TokenType.NEW: self._advance() classname = self._expect(TokenType.ID).value return Func(None, classname, "new", self.lexer.current_ifname, self._line()) # ID — could be plain func, or thisvar -> classname . method name = self._expect(TokenType.ID).value if self._at_punct('-'): # thisvar -> classname . method self._advance() # '-' self._expect_punct('>') classname = self._expect(TokenType.ID).value self._expect_punct('.') method = self._expect(TokenType.ID).value return Func(name, classname, method, self.lexer.current_ifname, self._line()) return Func(None, None, name, self.lexer.current_ifname, self._line()) # ------------------------------------------------------------------ # args / var # ------------------------------------------------------------------ def _args(self): """args ::= var (',' var)* | ε — returns list[Var]""" if self._at_punct(')'): return [] result = [self._var()] while self._at_punct(','): self._advance() result.append(self._var()) return result def _var(self): """var ::= [devicespec] [iospec] TYPE [qual] (NAME | NUMBER | STRING) OR: [devicespec] [iospec] TYPE NAME [aqual] (post-name array) """ devicespec = self._devicespec() iospec = self._iospec() basetype = promote_int(self.ctx, self._expect(TokenType.ID).value) # Now we may see: # quals then NAME/NUMBER/STRING # NAME/NUMBER/STRING then optional aqual # Just NAME/NUMBER/STRING (no qual) tok = self._peek() if tok.type == TokenType.PUNCT and tok.value in ('*', '&', '['): # quals before name qual = self._quals() name = self._name_or_literal() return Var(devicespec, iospec, basetype, qual, name) # NAME/NUMBER/STRING first, then optional aqual name = self._name_or_literal() # Check for post-name aqual: name [ ... ] or name [ ... ] & if self._at_punct('['): qual = self._aqual() return Var(devicespec, iospec, basetype, qual, name) return Var(devicespec, iospec, basetype, None, name) def _name_or_literal(self): tok = self._peek() if tok.type in (TokenType.ID, TokenType.NUMBER, TokenType.STRING): self._advance() return tok.value self._error(f"Expected name, number or string, got {tok.type.name} '{tok.value}'") def _devicespec(self): tok = self._peek() if tok.type == TokenType.CPU: self._advance() return 'c' if tok.type == TokenType.GPU: self._advance() return 'g' return 'c' def _iospec(self): tok = self._peek() m = { TokenType.INPUT: 'i', TokenType.OUTPUT: 'o', TokenType.INOUT: 'b', } if tok.type in m: self._advance() return m[tok.type] return 'i' def _quals(self): """quals ::= '*' | '&' | aqual""" if self._at_punct('*'): self._advance() return TypeQual('*') if self._at_punct('&'): self._advance() return TypeQual('&') return self._aqual() def _aqual(self): """aqual ::= arrayspec ['&']""" exprs = self._arrayspec() if self._at_punct('&'): self._advance() return TypeQual('r', exprs) return TypeQual('a', exprs) def _arrayspec(self): """'[' exprs ']' — returns list[Expr]""" self._expect_punct('[') e = self._exprs() self._expect_punct(']') return e def _exprs(self): """exprs ::= expr (',' expr)* | ε — returns list[Expr]""" if self._at_punct(']'): return [] result = [self._expr()] while self._at_punct(','): self._advance() result.append(self._expr()) return result def _expr(self): """expr ::= ID | NUMBER""" tok = self._peek() if tok.type in (TokenType.ID, TokenType.NUMBER): self._advance() return Expr(tok.value) self._error(f"Expected expression, got {tok.type.name} '{tok.value}'") def _basevar(self): """basevar ::= ID [quals] ID — always output, cpu""" basetype = promote_int(self.ctx, self._expect(TokenType.ID).value) # Peek: quals or name? tok = self._peek() if tok.type == TokenType.PUNCT and tok.value in ('*', '&', '['): qual = self._quals() name = self._expect(TokenType.ID).value return Var('c', 'o', basetype, qual, name) # NAME then optional aqual name = self._expect(TokenType.ID).value if self._at_punct('['): qual = self._aqual() return Var('c', 'o', basetype, qual, name) return Var('c', 'o', basetype, None, name) # ------------------------------------------------------------------ # Post-parse: typecheck, MATLAB stub, add to func list # ------------------------------------------------------------------ def _finish_func(self, func): """Typecheck, emit MATLAB stub, add to function list.""" self.func_id += 1 func.id = self.func_id self.type_errs += typecheck(self.ctx, func, self._line()) if self.lexer.outfp: print_matlab_call(self.lexer.outfp, func, self.mexfunc) self._add_func(func) def _add_func(self, func): """Add func to list; deduplicate via id_string.""" ids = id_string(self.ctx, func) first = self.func_lookup.get(ids) if first: # Same signature — add to first occurrence's same list first.same.append(func) else: # New unique signature — append to main list self.funcs.append(func) self.func_lookup[ids] = func zgimbutas-mwrap-25008ce/python/mwrap_support.c000066400000000000000000000551531515063637600216270ustar00rootroot00000000000000/* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif zgimbutas-mwrap-25008ce/python/mwrap_typecheck.py000066400000000000000000000236521515063637600222770ustar00rootroot00000000000000""" mwrap_typecheck.py — Semantic analysis and type classification. Copyright (c) 2007-2008 David Bindel See the file COPYING for copying permissions Converted to Python by Zydrunas Gimbutas (2026), with assistance from Claude Code / Claude Opus 4.6 (Anthropic). """ import sys from mwrap_ast import ( VT, Expr, TypeQual, Var, Func, promote_int, iospec_is_input, iospec_is_output, iospec_is_inonly, ) # --------------------------------------------------------------------------- # Label assignment # --------------------------------------------------------------------------- def _label_dim_args_expr(args, icount): """Assign input_label to dimension expressions; returns updated icount.""" for e in args: e.input_label = icount icount += 1 return icount def _label_dim_args_var(vars, icount): """Walk var list, label dimension expressions.""" for v in vars: if v.qual: icount = _label_dim_args_expr(v.qual.args, icount) return icount def _label_args_var(vars, icount, ocount): """Assign input/output labels to vars; returns (icount, ocount).""" for v in vars: if iospec_is_input(v.iospec): v.input_label = icount icount += 1 if iospec_is_output(v.iospec): v.output_label = ocount ocount += 1 return icount, ocount def label_args(f): """Assign prhs[] / plhs[] indices to a Func's variables.""" icount = 1 if f.thisv else 0 ocount = 0 icount, ocount = _label_args_var(f.ret, icount, ocount) icount, ocount = _label_args_var(f.args, icount, ocount) icount = _label_dim_args_var(f.ret, icount) icount = _label_dim_args_var(f.args, icount) # --------------------------------------------------------------------------- # Type-info assignment # --------------------------------------------------------------------------- def _assign_scalar_tinfo(v, line, tags, tagp, tagr, taga, tagar): """Assign tinfo for a scalar/complex type. Returns error count.""" if not v.qual: v.tinfo = tags elif v.qual.qual == '*': v.tinfo = tagp elif v.qual.qual == '&': v.tinfo = tagr elif v.qual.qual == 'a': v.tinfo = taga # check max 2D if len(v.qual.args) > 2: print(f"Error ({line}): Array {v.name} should be 1D or 2D", file=sys.stderr) return 1 elif v.qual.qual == 'r': v.tinfo = tagar if tagar == VT.unk: print(f"Error ({line}): Array ref {v.name} must be to a real array", file=sys.stderr) return 1 if len(v.qual.args) > 2: print(f"Error ({line}): Array {v.name} should be 1D or 2D", file=sys.stderr) return 1 else: assert False, f"Unknown qual '{v.qual.qual}'" return 0 def assign_tinfo(ctx, v, line): """Assign VT_* tinfo to a single Var. Returns error count.""" bt = v.basetype if ctx.is_scalar_type(bt): return _assign_scalar_tinfo(v, line, VT.scalar, VT.p_scalar, VT.r_scalar, VT.array, VT.rarray) elif ctx.is_cscalar_type(bt): return _assign_scalar_tinfo(v, line, VT.cscalar, VT.p_cscalar, VT.r_cscalar, VT.carray, VT.unk) elif ctx.is_zscalar_type(bt): return _assign_scalar_tinfo(v, line, VT.zscalar, VT.p_zscalar, VT.r_zscalar, VT.zarray, VT.unk) elif bt == "const": if v.qual: print(f"Error ({line}): Constant {v.name} cannot have modifiers", file=sys.stderr) return 1 v.tinfo = VT.const # Strip quotes from name if present if v.name and v.name.startswith("'"): v.name = v.name.replace("'", "") elif bt == "cstring": if v.qual and v.qual.qual != 'a': print(f"Error ({line}): String type {v.name} cannot have modifiers", file=sys.stderr) return 1 if v.qual and len(v.qual.args) > 1: print(f"Error ({line}): Strings are one dimensional", file=sys.stderr) return 1 v.tinfo = VT.string elif bt == "mxArray": if v.qual: print(f"Error ({line}): mxArray {v.name} cannot have modifiers", file=sys.stderr) return 1 v.tinfo = VT.mx else: # Object type if not v.qual: v.tinfo = VT.obj elif v.qual.qual == '*': v.tinfo = VT.p_obj elif v.qual.qual == '&': v.tinfo = VT.r_obj elif v.qual.qual in ('a', 'r'): print(f"Error ({line}): {v.name} cannot be an array of object {bt}", file=sys.stderr) return 1 else: assert False return 0 # --------------------------------------------------------------------------- # Return-value validation # --------------------------------------------------------------------------- def _typecheck_return(ctx, ret, line): if not ret: return 0 v = ret[0] err = assign_tinfo(ctx, v, line) if v.tinfo in (VT.array, VT.carray, VT.zarray): if not (v.qual and v.qual.args): print(f"Error ({line}): Return array {v.name} must have dims", file=sys.stderr) err += 1 elif v.tinfo == VT.const: print(f"Error ({line}): Cannot return constant", file=sys.stderr) err += 1 elif v.tinfo == VT.rarray: print(f"Error ({line}): Ref to array {v.name} looks just like array on return", file=sys.stderr) err += 1 elif v.tinfo == VT.string and v.qual: print(f"Error ({line}): Return string {v.name} cannot have dims", file=sys.stderr) err += 1 return err # --------------------------------------------------------------------------- # Argument validation # --------------------------------------------------------------------------- def _typecheck_args(ctx, args, line): err = 0 for v in args: err += assign_tinfo(ctx, v, line) if iospec_is_inonly(v.iospec): continue # Output / inout checks if v.name and v.name[0:1].isdigit(): print(f"Error ({line}): Number {v.name} cannot be output", file=sys.stderr) err += 1 if (v.tinfo in (VT.obj, VT.p_obj, VT.r_obj) and not ctx.is_mxarray_type(v.basetype)): print(f"Error ({line}): Object {v.name} cannot be output", file=sys.stderr) err += 1 elif (v.tinfo in (VT.array, VT.carray, VT.zarray, VT.rarray) and v.iospec == 'o' and not (v.qual and v.qual.args)): print(f"Error ({line}): Output array {v.name} must have dims", file=sys.stderr) err += 1 elif v.tinfo == VT.rarray and not iospec_is_output(v.iospec): print(f"Error ({line}): Array ref {v.name} *must* be output", file=sys.stderr) err += 1 elif v.tinfo == VT.scalar: print(f"Error ({line}): Scalar {v.name} cannot be output", file=sys.stderr) err += 1 elif v.tinfo == VT.const: print(f"Error ({line}): Constant {v.name} cannot be output", file=sys.stderr) err += 1 elif v.tinfo == VT.string and not (v.qual and v.qual.args): print(f"Error ({line}): String {v.name} cannot be output without size", file=sys.stderr) err += 1 elif v.tinfo == VT.mx and v.iospec == 'b': print(f"Error ({line}): mxArray {v.name} cannot be used for inout", file=sys.stderr) err += 1 return err # --------------------------------------------------------------------------- # Fortran-ize arguments # --------------------------------------------------------------------------- def _fortranize_args_var(args, line): """Convert scalar args to pointer-to-scalar for FORTRAN. Returns error count.""" err = 0 for v in args: if v.tinfo in (VT.obj, VT.p_obj, VT.r_obj): print(f"Error ({line}): Cannot pass object {v.name} to FORTRAN", file=sys.stderr) err += 1 elif v.tinfo == VT.rarray: print(f"Error ({line}): Cannot pass pointer ref {v.name} to FORTRAN", file=sys.stderr) err += 1 elif v.tinfo == VT.string: print(f"Warning ({line}): Danger passing C string {v.name} to FORTRAN", file=sys.stderr) elif v.tinfo in (VT.scalar, VT.r_scalar): v.tinfo = VT.p_scalar elif v.tinfo in (VT.cscalar, VT.r_cscalar): v.tinfo = VT.p_cscalar elif v.tinfo in (VT.zscalar, VT.r_zscalar): v.tinfo = VT.p_zscalar return err def _fortranize_ret(v, line): if not v: return 0 if v.tinfo in (VT.cscalar, VT.zscalar): print(f"Warning ({line}): Danger returning complex from FORTRAN", file=sys.stderr) elif v.tinfo != VT.scalar: print(f"Error ({line}): Can only return scalars from FORTRAN", file=sys.stderr) return 1 return 0 def _fortranize_args(f, line): if not f.fort: return 0 err = _fortranize_args_var(f.args, line) if f.ret: err += _fortranize_ret(f.ret[0], line) return err # --------------------------------------------------------------------------- # Top-level typecheck # --------------------------------------------------------------------------- def typecheck(ctx, f, line): """Run full semantic analysis on a Func. Returns error count.""" label_args(f) return (_typecheck_return(ctx, f.ret, line) + _typecheck_args(ctx, f.args, line) + _fortranize_args(f, line)) zgimbutas-mwrap-25008ce/src/000077500000000000000000000000001515063637600157765ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/src/CMakeLists.txt000066400000000000000000000051701515063637600205410ustar00rootroot00000000000000set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(stringify stringify.c) set(MWRAP_SUPPORT_HEADER ${CMAKE_CURRENT_BINARY_DIR}/mwrap-support.h) add_custom_command( OUTPUT ${MWRAP_SUPPORT_HEADER} COMMAND ${CMAKE_COMMAND} -DSTRINGIFY=$ -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/mwrap-support.c -DOUTPUT=${MWRAP_SUPPORT_HEADER} -DNAME=mex_header -P ${PROJECT_SOURCE_DIR}/cmake/run_stringify.cmake DEPENDS stringify ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-support.c COMMENT "Generating mwrap-support.h" VERBATIM ) set_source_files_properties(${MWRAP_SUPPORT_HEADER} PROPERTIES GENERATED TRUE) add_custom_target(mwrap_support_header DEPENDS ${MWRAP_SUPPORT_HEADER}) set(MWRAP_HANDWRITTEN_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-ast.cc ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-typecheck.cc ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-cgen.cc ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-mgen.cc ) set(MWRAP_HANDWRITTEN_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/mwrap-ast.h ) find_package(BISON REQUIRED) find_package(FLEX REQUIRED) if(BISON_VERSION VERSION_GREATER_EQUAL "3.0") set(ERROR_VERBOSE "%define parse.error verbose") else() set(ERROR_VERBOSE "%error-verbose") endif() configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mwrap.y.in ${CMAKE_CURRENT_BINARY_DIR}/mwrap.y @ONLY ) BISON_TARGET(MwrapParser ${CMAKE_CURRENT_BINARY_DIR}/mwrap.y ${CMAKE_CURRENT_BINARY_DIR}/mwrap.cc DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/mwrap.hh VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/mwrap.output ) FLEX_TARGET(MwrapLexer ${CMAKE_CURRENT_SOURCE_DIR}/mwrap.l ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.c ) ADD_FLEX_BISON_DEPENDENCY(MwrapLexer MwrapParser) set(MWRAP_GENERATED_SOURCES ${BISON_MwrapParser_OUTPUT_SOURCE} ${FLEX_MwrapLexer_OUTPUTS} ) set(MWRAP_GENERATED_HEADERS ${BISON_MwrapParser_OUTPUT_HEADER} ) set_source_files_properties(${MWRAP_GENERATED_SOURCES} ${MWRAP_GENERATED_HEADERS} PROPERTIES GENERATED TRUE) add_executable(mwrap ${MWRAP_HANDWRITTEN_SOURCES} ${MWRAP_GENERATED_SOURCES} ${MWRAP_SUPPORT_HEADER} ) add_dependencies(mwrap mwrap_support_header) target_sources(mwrap PRIVATE ${MWRAP_HANDWRITTEN_HEADERS} ${MWRAP_GENERATED_HEADERS}) target_include_directories(mwrap PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) target_compile_definitions(mwrap PRIVATE $<$:R2008OO> $<$:MWRAP_ENABLE_C99_COMPLEX> $<$:MWRAP_ENABLE_CPP_COMPLEX> ) install(TARGETS mwrap RUNTIME DESTINATION bin) zgimbutas-mwrap-25008ce/src/Makefile000066400000000000000000000025061515063637600174410ustar00rootroot00000000000000include ../make.inc # === Primary targets === ../mwrap: mwrap.o lex.yy.o mwrap-ast.o mwrap-typecheck.o \ mwrap-mgen.o mwrap-cgen.o mwrap-ast.h $(CXX) -o ../mwrap mwrap.o mwrap-ast.o \ mwrap-typecheck.o mwrap-mgen.o mwrap-cgen.o \ lex.yy.o mwrap.o: mwrap.cc lex.yy.c mwrap-ast.h $(CXX) -c mwrap.cc mwrap.cc mwrap.hh: mwrap.y $(BISON) -d -v mwrap.y -o mwrap.cc ifeq ($(shell bison --version 2>&1 | sed -n 's/^.*GNU Bison.* \([0-9]*\).*$$/\1/p'), 3) ERROR_VERBOSE = %define parse.error verbose else ERROR_VERBOSE = %error-verbose endif mwrap.y: mwrap.y.in sed -e 's/@ERROR_VERBOSE@/$(ERROR_VERBOSE)/' < mwrap.y.in > mwrap.y lex.yy.o: lex.yy.c mwrap.hh $(CC) -c lex.yy.c lex.yy.c: mwrap.l $(FLEX) mwrap.l mwrap-ast.o: mwrap-ast.cc mwrap-ast.h $(CXX) -c -g mwrap-ast.cc mwrap-typecheck.o: mwrap-typecheck.cc mwrap-ast.h $(CXX) -c -g mwrap-typecheck.cc mwrap-cgen.o: mwrap-cgen.cc mwrap-ast.h mwrap-support.h $(CXX) -c -g mwrap-cgen.cc mwrap-mgen.o: mwrap-mgen.cc mwrap-ast.h $(CXX) -c -g mwrap-mgen.cc mwrap-support.h: mwrap-support.c stringify ./stringify mex_header < mwrap-support.c > mwrap-support.h stringify: stringify.c $(CC) -o stringify stringify.c # === Clean-up targets === clean: rm -f mwrap.output rm -f *.o *~ rm -f stringify realclean: clean rm -f mwrap.y lex.yy.c mwrap.cc mwrap.hh mwrap-support.h zgimbutas-mwrap-25008ce/src/mwrap-ast.cc000066400000000000000000000211031515063637600202150ustar00rootroot00000000000000/* * mwrap-ast.cc * Recursive routines for AST printing, identifier construction, * and destruction. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include #include "mwrap-ast.h" /* -- Add inheritance relationship -- */ /* * We represent inheritance relationships as a list of child classes * associated with each parent. This makes sense when we generate the * type casting routines, since we only allow casts to the parent * types. But it's the opposite of how inheritance relations are * specified syntactically. */ map class_decls; void add_inherits(const char* childname, InheritsDecl* ilist) { for (; ilist; ilist = ilist->next) { InheritsDecl*& children = class_decls[ilist->name]; children = new InheritsDecl(mwrap_strdup(childname), children); } } /* -- Add scalar type data -- */ /* * The names of the numeric scalar types are stored in the set scalar_decls. * We provide a basic list, but the user can specify more -- the only real * constraint is there has to be a meaningful typecast to/from a double. */ set scalar_decls; set cscalar_decls; set zscalar_decls; set mxarray_decls; void init_scalar_types() { const char* scalar_types[] = { "double", "float", "long", "int", "short", "char", "ulong", "uint", "ushort", "uchar", "int32_t", "int64_t", "uint32_t", "uint64_t", "bool", "size_t", "ptrdiff_t", NULL}; for (const char** s = scalar_types; *s; ++s) add_scalar_type(*s); } char *promote_int(char* name) { /* Detect C99 types: int32_t, int64_t, uint32_t, uint64_t */ if( strcmp(name,"int32_t") == 0 ) mw_use_int32_t = 1; if( strcmp(name,"int64_t") == 0 ) mw_use_int64_t = 1; if( strcmp(name,"uint32_t") == 0 ) mw_use_uint32_t = 1; if( strcmp(name,"uint64_t") == 0 ) mw_use_uint64_t = 1; if( strcmp(name,"ulong") == 0 ) mw_use_ulong = 1; if( strcmp(name,"uint") == 0 ) mw_use_uint = 1; if( strcmp(name,"ushort") == 0 ) mw_use_ushort = 1; if( strcmp(name,"uchar") == 0 ) mw_use_uchar = 1; /* Promote integers */ if( mw_promote_int == 1 ) { if( strcmp(name,"uint") == 0 ) mw_use_ulong = 1; if( strcmp(name,"int") == 0 ) return strdup("long"); if( strcmp(name,"uint") == 0 ) return strdup("ulong"); } if( mw_promote_int == 2 ) { if( strcmp(name,"uint") == 0 ) mw_use_ulong = 1; if( strcmp(name,"ulong") == 0 ) mw_use_ulong = 1; if( strcmp(name,"int") == 0 ) return strdup("long"); if( strcmp(name,"long") == 0 ) return strdup("long"); if( strcmp(name,"uint") == 0 ) return strdup("ulong"); if( strcmp(name,"ulong") == 0 ) return strdup("ulong"); } if( mw_promote_int == 3 ) { if( strcmp(name,"int") == 0 ) mw_use_int32_t = 1; if( strcmp(name,"long") == 0 ) mw_use_int64_t = 1; if( strcmp(name,"uint") == 0 ) mw_use_uint32_t = 1; if( strcmp(name,"ulong") == 0 ) mw_use_uint64_t = 1; if( strcmp(name,"int") == 0 ) return strdup("int32_t"); if( strcmp(name,"long") == 0 ) return strdup("int32_t"); if( strcmp(name,"uint") == 0 ) return strdup("uint64_t"); if( strcmp(name,"ulong") == 0 ) return strdup("uint64_t"); } if( mw_promote_int == 4 ) { if( strcmp(name,"int") == 0 ) mw_use_int64_t = 1; if( strcmp(name,"long") == 0 ) mw_use_int64_t = 1; if( strcmp(name,"uint") == 0 ) mw_use_uint64_t = 1; if( strcmp(name,"ulong") == 0 ) mw_use_uint64_t = 1; if( strcmp(name,"int") == 0 ) return strdup("int64_t"); if( strcmp(name,"long") == 0 ) return strdup("int64_t"); if( strcmp(name,"uint") == 0 ) return strdup("uint64_t"); if( strcmp(name,"ulong") == 0 ) return strdup("uint64_t"); } return name; } void add_scalar_type(const char* name) { scalar_decls.insert(name); } void add_cscalar_type(const char* name) { cscalar_decls.insert(name); } void add_zscalar_type(const char* name) { zscalar_decls.insert(name); } void add_mxarray_type(const char* name) { mxarray_decls.insert(name); } bool is_scalar_type(const char* name) { return (scalar_decls.find(name) != scalar_decls.end()); } bool is_cscalar_type(const char* name) { return (cscalar_decls.find(name) != cscalar_decls.end()); } bool is_zscalar_type(const char* name) { return (zscalar_decls.find(name) != zscalar_decls.end()); } bool is_mxarray_type(const char* name) { return (mxarray_decls.find(name) != mxarray_decls.end()); } /* -- Print the AST -- */ /* * Print a human-readable translation of the abstract syntax tree to * the output. This is only used for generating comprehensible comments * in the C code. */ void print(FILE* fp, Expr* e) { if (!e) return; fprintf(fp, "%s", e->value); if (e->next) { fprintf(fp, ", "); print(fp, e->next); } } void print(FILE* fp, TypeQual* q) { if (!q) return; if (q->qual == 'a') { fprintf(fp, "["); print(fp, q->args); fprintf(fp, "]"); } else fprintf(fp, "%c", q->qual); } void print_devicespec(FILE* fp, Var* v) { if (v->devicespec == 'g') fprintf(fp, "gpu "); } void print_iospec(FILE* fp, Var* v) { if (v->iospec == 'o') fprintf(fp, "output "); else if (v->iospec == 'b') fprintf(fp, "inout "); } void print_var(FILE* fp, Var* v) { fprintf(fp, "%s", v->basetype); print(fp, v->qual); fprintf(fp, " %s", v->name); } void print_args(FILE* fp, Var* v) { if (!v) return; print_devicespec(fp, v); print_iospec(fp, v); print_var(fp, v); if (v->next) { fprintf(fp, ", "); print_args(fp, v->next); } } void print(FILE* fp, Func* f) { if (!f) return; if (f->ret) { print_var(fp, f->ret); fprintf(fp, " = "); } if (f->thisv) fprintf(fp, "%s->%s.", f->thisv, f->classv); fprintf(fp, "%s(", f->funcv); print_args(fp, f->args); fprintf(fp, ");\n"); } /* -- ID string -- */ /* * The ID string is a compressed text representation of the AST for * a function. We replace all the variable names by the letter 'x' * so that when we have the same function call with different arguments, * we will generate the same signature. */ string id_string(Expr* e) { if (!e) return ""; return "x" + id_string(e->next); } string id_string(TypeQual* q) { if (!q) return ""; if (q->qual == 'a') return "[" + id_string(q->args) + "]"; else return (string() + q->qual); } string id_string(Var* v) { if (!v) return ""; string name; if (v->devicespec == 'c') name += "c "; else if (v->devicespec == 'g') name += "g "; if (v->iospec == 'i') name += "i "; else if (v->iospec == 'o') name += "o "; else name += "io "; name += promote_int(v->basetype); name += id_string(v->qual); if (v->tinfo == VT_const) { name += " "; name += v->name; } if (v->next) { name += ", "; name += id_string(v->next); } return name; } string id_string(Func* f) { if (!f) return ""; string name; if (f->ret) { name += id_string(f->ret); name += " = "; } if (f->thisv) { name += f->thisv; name += "->"; name += f->classv; name += "."; } name += f->funcv; name += "("; name += id_string(f->args); name += ")"; return name; } /* -- Destroy an AST -- */ void destroy(Expr* e) { if (!e) return; destroy(e->next); delete[] e->value; delete e; } void destroy(TypeQual* q) { if (!q) return; destroy(q->args); delete q; } void destroy(Var* v) { if (!v) return; destroy(v->next); destroy(v->qual); delete[] v->basetype; delete[] v->name; delete v; } void destroy(Func* f) { while (f) { Func* oldf = f; f = f->next; destroy(oldf->same_next); destroy(oldf->ret); if (oldf->thisv) delete[] oldf->thisv; if (oldf->classv) delete[] oldf->classv; delete[] oldf->funcv; destroy(oldf->args); delete oldf; } } void destroy(InheritsDecl* i) { if (!i) return; destroy(i->next); delete i; } void destroy_inherits() { map::iterator i = class_decls.begin(); for (; i != class_decls.end(); ++i) { destroy(i->second); i->second = NULL; } } zgimbutas-mwrap-25008ce/src/mwrap-ast.h000066400000000000000000000117371515063637600200730ustar00rootroot00000000000000/* * mwrap-ast.h * MWrap abstract syntax tree declarations. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #ifndef MWRAP_AST_H #define MWRAP_AST_H #include #include #include #include using std::string; using std::map; using std::set; enum { VT_unk, // Unknown VT_obj, // Object VT_array, // Numeric array (real) VT_carray, // Numeric array (single complex) VT_zarray, // Numeric array (double complex) VT_rarray, // Reference to numeric array VT_scalar, // Numeric scalar (real) VT_cscalar, // Numeric scalar (single complex) VT_zscalar, // Numeric scalar (double complex) VT_string, // Char string VT_mx, // mxArray VT_p_obj, // Pointer to object VT_p_scalar, // Pointer to scalar (real) VT_p_cscalar, // Pointer to scalar (single complex) VT_p_zscalar, // Pointer to scalar (double complex) VT_r_obj, // Reference to object VT_r_scalar, // Reference to scalar (real) VT_r_cscalar, // Reference to scalar (single complex) VT_r_zscalar, // Reference to scalar (double complex) VT_const, // Constant expression }; struct InheritsDecl { InheritsDecl(char* name, InheritsDecl* next) : name(name), next(next) {} char* name; // Name of inherited class InheritsDecl* next; }; struct Expr { Expr(char* value) : value(value), next(NULL), input_label(-1) {} int input_label; // Index of dim variable in input arg list char* value; // Expression to be evaluated to get dimension Expr* next; }; struct TypeQual { TypeQual(char qual, Expr* args) : qual(qual), args(args) {} char qual; // Pointer ('*'), ref ('&'), array ('a'), or nothing (0) Expr* args; // Array / cstring dimension list }; struct Var { Var(char devicespec, char iospec, char* basetype, TypeQual* qual, char* name) : devicespec(devicespec), iospec(iospec), basetype(basetype), qual(qual), tinfo(VT_unk), name(name), next(NULL), input_label(-1), output_label(-1) {} int input_label; // Index in input arg list int output_label; // Index in output arg list char iospec; // Indicate input ('i'), output ('o'), or both ('b') char devicespec; // Indicate cpu ('c'), gpu ('g') char* basetype; // Name of the base type TypeQual* qual; // Type qualifier (pointer, ref, etc) int tinfo; // General type identifier (see VT_* list above) char* name; // MATLAB text for variable name (or value) Var* next; }; struct Func { Func(char* thisv, char* classv, char* funcv, const string& fname, int line) : fname(fname), line(line), fort(false), id(-1), thisv(thisv), classv(classv), funcv(funcv), args(NULL), ret(NULL), next(NULL), same_next(NULL) {} string fname; // Name of file where this function was defined int line; // Number of the line where the function was defined bool fort; // Flag whether this is a FORTRAN function int id; // Identifier (used for numbering stub functions) char* thisv; // This var (only for methods) char* classv; // Class type (only for methods or 'new' calls) char* funcv; // Function or method name Var* args; // Arguments Var* ret; // Return variable Func* next; // Next in ordinary linked list Func* same_next; // Next in list of type-identical calls }; extern "C" char* mwrap_strdup(const char* s); extern map class_decls; void add_inherits(const char* childname, InheritsDecl* ilist); extern set scalar_decls; extern set cscalar_decls; extern set zscalar_decls; extern set mxarray_decls; void init_scalar_types(); char *promote_int(char* name); void add_scalar_type(const char* name); void add_cscalar_type(const char* name); void add_zscalar_type(const char* name); void add_mxarray_type(const char* name); bool is_scalar_type(const char* name); bool is_cscalar_type(const char* name); bool is_zscalar_type(const char* name); bool is_mxarray_type(const char* name); string id_string(Func* f); int typecheck(Func* func, int line); void print(FILE* fp, Func* func); void print_matlab_call(FILE* fp, Func* func, const char* mexfunc); void print_mex_init(FILE* fp); void print_mex_file(FILE* fp, Func* f); void mex_c99_complex(FILE* fp); void mex_cpp_complex(FILE* fp); void destroy(Func* func); void destroy(InheritsDecl* ilist); void destroy_inherits(); extern bool mw_use_gpu; extern bool mw_generate_catch; extern bool mw_use_c99_complex; extern bool mw_use_cpp_complex; extern int mw_promote_int; extern int mw_use_int32_t; extern int mw_use_int64_t; extern int mw_use_uint32_t; extern int mw_use_uint64_t; extern int mw_use_longlong; extern int mw_use_ulonglong; extern int mw_use_ulong; extern int mw_use_uint; extern int mw_use_ushort; extern int mw_use_uchar; #endif /* MWRAP_AST_H */ zgimbutas-mwrap-25008ce/src/mwrap-cgen.cc000066400000000000000000001575251515063637600203640ustar00rootroot00000000000000/* * mwrap-cgen.cc * Generate C MEX file from MWrap AST. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include #include "mwrap-ast.h" #include "mwrap-support.h" /* -- General utility functions -- */ /* * map dcomplex/fcomplex to cuda complex types */ char *basetype_to_cucomplex(const char* name) { if( strcmp(name,"fcomplex") == 0 ) return strdup("cuFloatComplex"); if( strcmp(name,"dcomplex") == 0 ) return strdup("cuDoubleComplex"); return strdup(name); } /* * map type to mxClassID */ char *basetype_to_mxclassid(const char* name) { if( strcmp(name,"int32_t") == 0 ) return strdup("mxINT32_CLASS"); if( strcmp(name,"int64_t") == 0 ) return strdup("mxINT64_CLASS"); if( strcmp(name,"uint32_t") == 0 ) return strdup("mxUINT32_CLASS"); if( strcmp(name,"uint64_t") == 0 ) return strdup("mxUINT64_CLASS"); if( strcmp(name,"float") == 0 ) return strdup("mxSINGLE_CLASS"); if( strcmp(name,"fcomplex") == 0 ) return strdup("mxSINGLE_CLASS"); if( strcmp(name,"double") == 0 ) return strdup("mxDOUBLE_CLASS"); if( strcmp(name,"dcomplex") == 0 ) return strdup("mxDOUBLE_CLASS"); return strdup("mxVOID_CLASS"); } /* * Check whether a tinfo is an array type */ bool is_array(int tinfo) { return (tinfo == VT_array || tinfo == VT_carray || tinfo == VT_zarray); } /* * Check whether a tinfo is an array type */ bool is_obj(int tinfo) { return (tinfo == VT_obj || tinfo == VT_p_obj || tinfo == VT_r_obj); } /* * A function has a nullable return value if it returns a non-object * type for which a NULL pointer value makes sense. */ bool nullable_return(Func* f) { return (f->ret && (f->ret->tinfo == VT_string || is_array(f->ret->tinfo) || f->ret->tinfo == VT_p_scalar || f->ret->tinfo == VT_p_cscalar || f->ret->tinfo == VT_p_zscalar)); } /* * Get the name of a variable into the provided buffer. */ const char* vname(Var* v, char* buf) { if (v->iospec == 'o') sprintf(buf, "out%d_", v->output_label); else sprintf(buf, "in%d_", v->input_label); return buf; } /* * Check whether there are any FORTRAN routines in the list. */ bool has_fortran(Func* f) { for (; f; f=f->next) if (f->fort) return true; return false; } /* * Check whether the specified variable is complex */ bool complex_tinfo(Var* v) { return (v->tinfo == VT_carray || v->tinfo == VT_zarray || v->tinfo == VT_cscalar || v->tinfo == VT_zscalar || v->tinfo == VT_r_cscalar || v->tinfo == VT_r_zscalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar); } /* * Count routines in the list. */ int max_routine_id(Func* f) { int maxid = 0; for (; f; f=f->next) if (f->id > maxid) maxid = f->id; return maxid; } void mex_use_gpu(FILE* fp) { fprintf(fp, "#include \n\n"); } /* -- Generate standard complex type definitions -- */ void mex_cpp_complex(FILE* fp) { fprintf(fp, "#include \n" "\n" "typedef std::complex dcomplex;\n" "#define real_dcomplex(z) std::real(z)\n" "#define imag_dcomplex(z) std::imag(z)\n" "#define setz_dcomplex(z,r,i) *z = dcomplex(r,i)\n" "\n" "typedef std::complex fcomplex;\n" "#define real_fcomplex(z) std::real(z)\n" "#define imag_fcomplex(z) std::imag(z)\n" "#define setz_fcomplex(z,r,i) *z = fcomplex(r,i)\n\n"); } void mex_gpucpp_complex(FILE* fp) { fprintf(fp,"#include \n\n"); } void mex_c99_complex(FILE* fp) { fprintf(fp, "#include \n" "\n" "typedef _Complex double dcomplex;\n" "#define real_dcomplex(z) creal(z)\n" "#define imag_dcomplex(z) cimag(z)\n" "#define setz_dcomplex(z,r,i) *z = r + i*_Complex_I\n" "\n" "typedef _Complex float fcomplex;\n" "#define real_fcomplex(z) crealf(z)\n" "#define imag_fcomplex(z) cimagf(z)\n" "#define setz_fcomplex(z,r,i) *z = r + i*_Complex_I\n\n"); } /* -- Generate scalar conversion info -- */ /* * For each scalar type T, we define methods to convert a double array * to/from a T array, and to handle return of a pointer to a single T * (which might be NULL). */ void mex_define_copiers(FILE* fp, const char* name) { /* Skip C99 int32_t, int64_t, uint32_t, uint64_t, if not detected */ if( (strcmp(name, "int32_t") == 0 ) && ( mw_use_int32_t == 0 ) ) return; if( (strcmp(name, "int64_t") == 0 ) && ( mw_use_int64_t == 0 ) ) return; if( (strcmp(name, "uint32_t") == 0 ) && ( mw_use_uint32_t == 0 ) ) return; if( (strcmp(name, "uint64_t") == 0 ) && ( mw_use_uint64_t == 0 ) ) return; if( (strcmp(name, "ulong") == 0 ) && ( mw_use_ulong == 0 ) ) return; if( (strcmp(name, "uint") == 0 ) && ( mw_use_uint == 0 ) ) return; if( (strcmp(name, "ushort") == 0 ) && ( mw_use_ushort == 0 ) ) return; if( (strcmp(name, "uchar") == 0 ) && ( mw_use_uchar == 0 ) ) return; /* Define copiers */ fprintf(fp, "mxWrapGetArrayDef(mxWrapGetArray_%s, %s)\n", name, name); fprintf(fp, "mxWrapCopyDef (mxWrapCopy_%s, %s)\n", name, name); fprintf(fp, "mxWrapReturnDef (mxWrapReturn_%s, %s)\n", name, name); /* Single precision */ fprintf(fp, "mxWrapGetArrayDef_single(mxWrapGetArray_single_%s, %s)\n", name, name); fprintf(fp, "mxWrapCopyDef_single (mxWrapCopy_single_%s, %s)\n", name, name); fprintf(fp, "mxWrapReturnDef_single (mxWrapReturn_single_%s, %s)\n", name, name); } void mex_define_zcopiers(FILE* fp, const char* name, const char* ztype) { /* Define complex copiers */ fprintf(fp, "mxWrapGetScalarZDef(mxWrapGetScalar_%s, %s,\n" " %s, setz_%s)\n", name, name, ztype, name); fprintf(fp, "mxWrapGetArrayZDef (mxWrapGetArray_%s, %s,\n" " %s, setz_%s)\n", name, name, ztype, name); fprintf(fp, "mxWrapCopyZDef (mxWrapCopy_%s, %s,\n" " real_%s, imag_%s)\n", name, name, name, name); fprintf(fp, "mxWrapReturnZDef (mxWrapReturn_%s, %s,\n" " real_%s, imag_%s)\n", name, name, name, name); /* Single precision */ fprintf(fp, "mxWrapGetScalarZDef_single(mxWrapGetScalar_single_%s, %s,\n" " %s, setz_%s)\n", name, name, ztype, name); fprintf(fp, "mxWrapGetArrayZDef_single (mxWrapGetArray_single_%s, %s,\n" " %s, setz_%s)\n", name, name, ztype, name); fprintf(fp, "mxWrapCopyZDef_single (mxWrapCopy_single_%s, %s,\n" " real_%s, imag_%s)\n", name, name, name, name); fprintf(fp, "mxWrapReturnZDef_single (mxWrapReturn_single_%s, %s,\n" " real_%s, imag_%s)\n", name, name, name, name); } void mex_define_copiers(FILE* fp) { fprintf(fp, "\n\n\n"); fprintf(fp, "/* Array copier definitions */\n"); for( set::iterator iter = scalar_decls.begin(); iter != scalar_decls.end(); ++iter){ mex_define_copiers(fp, iter->c_str()); } for( set::iterator iter = cscalar_decls.begin(); iter != cscalar_decls.end(); ++iter) mex_define_zcopiers(fp, iter->c_str(), "float"); for( set::iterator iter = zscalar_decls.begin(); iter != zscalar_decls.end(); ++iter) mex_define_zcopiers(fp, iter->c_str(), "double"); fprintf(fp, "\n"); } /* -- Handle FORTRAN name mangling -- */ /* * For each FORTRAN function, we define a macro version of the name * starting with MWF77_, which will handle the various name-mangling * issues that come up. We support three name mangling conventions for * now: all upper (no underscore mangling); all lower, single underscore; * and all lower, single underscore, double underscore for names that * contain an underscore (f2c). */ void mex_define_caps_fname(FILE* fp, Func* f) { fprintf(fp, "#define MWF77_%s ", f->funcv); for (char* s = f->funcv; *s; ++s) fputc(toupper(*s), fp); fprintf(fp, "\n"); } void mex_define_caps_fnames(FILE* fp, Func* f) { set fnames; for (; f; f = f->next) { if (f->fort && fnames.find(f->funcv) == fnames.end()) { mex_define_caps_fname(fp, f); fnames.insert(f->funcv); } } } void mex_define_underscore1_fname(FILE* fp, Func* f) { fprintf(fp, "#define MWF77_%s ", f->funcv); for (char* s = f->funcv; *s; ++s) fputc(tolower(*s), fp); fprintf(fp, "_\n"); } void mex_define_underscore1_fnames(FILE* fp, Func* f) { set fnames; for (; f; f = f->next) { if (f->fort && fnames.find(f->funcv) == fnames.end()) { mex_define_underscore1_fname(fp, f); fnames.insert(f->funcv); } } } void mex_define_underscore0_fname(FILE* fp, Func* f) { fprintf(fp, "#define MWF77_%s ", f->funcv); for (char* s = f->funcv; *s; ++s) fputc(tolower(*s), fp); fprintf(fp, "\n"); } void mex_define_underscore0_fnames(FILE* fp, Func* f) { set fnames; for (; f; f = f->next) { if (f->fort && fnames.find(f->funcv) == fnames.end()) { mex_define_underscore0_fname(fp, f); fnames.insert(f->funcv); } } } void mex_define_f2c_fname(FILE* fp, Func* f) { fprintf(fp, "#define MWF77_%s ", f->funcv); bool has_underscore = false; for (char* s = f->funcv; *s; ++s) { has_underscore = (has_underscore || (*s == '_')); fputc(tolower(*s), fp); } if (has_underscore) fprintf(fp, "__\n"); else fprintf(fp, "_\n"); } void mex_define_f2c_fnames(FILE* fp, Func* f) { set fnames; for (; f; f = f->next) { if (f->fort && fnames.find(f->funcv) == fnames.end()) { mex_define_f2c_fname(fp, f); fnames.insert(f->funcv); } } } void mex_define_fnames(FILE* fp, Func* f) { fprintf(fp, "#if defined(MWF77_CAPS)\n"); mex_define_caps_fnames(fp, f); fprintf(fp, "#elif defined(MWF77_UNDERSCORE1)\n"); mex_define_underscore1_fnames(fp, f); fprintf(fp, "#elif defined(MWF77_UNDERSCORE0)\n"); mex_define_underscore0_fnames(fp, f); fprintf(fp, "#else /* f2c convention */\n"); mex_define_f2c_fnames(fp, f); fprintf(fp, "#endif\n\n"); } /* -- Handle FORTRAN declarations -- */ /* * We assume unless told otherwise that all FORTRAN functions need * prototypes, which we will generate. */ void mex_fortran_arg(FILE* fp, Var* v) { if (!v) return; if (v->tinfo == VT_mx) fprintf(fp, "const mxArray*"); else fprintf(fp, "%s*", v->basetype); if (v->next) { fprintf(fp, ", "); mex_fortran_arg(fp, v->next); } } void mex_fortran_decl(FILE* fp, Func* f) { if (f->ret) fprintf(fp, "%s ", f->ret->basetype); else fprintf(fp, "MWF77_RETURN "); fprintf(fp, "MWF77_%s(", f->funcv); mex_fortran_arg(fp, f->args); fprintf(fp, ");\n"); } void mex_fortran_decls(FILE* fp, Func* f) { fprintf(fp, "#ifdef __cplusplus\n" "extern \"C\" { /* Prevent C++ name mangling */\n" "#endif\n\n" "#ifndef MWF77_RETURN\n" "#define MWF77_RETURN int\n" "#endif\n\n"); set fnames; for (; f; f = f->next) { if (f->fort && fnames.find(f->funcv) == fnames.end()) { mex_fortran_decl(fp, f); fnames.insert(f->funcv); } } fprintf(fp, "\n#ifdef __cplusplus\n" "} /* end extern C */\n" "#endif\n\n"); } /* -- Generate class conversion info -- */ /* * For every parent class, we define a getter method that can take a * string of the form "T:value" and interpret the value as a pointer * to T for every child class T. We want to get an *exact* match with * the child pointer type and then cast that pointer to the parent type * in the C++ code, because otherwise we don't get the right behavior * with multiple inheritance (i.e. when a cast actually changes the pointer * value). */ void mex_casting_getter_type(FILE* fp, const char* name) { fprintf(fp, " %s* p_%s = NULL;\n" " sscanf(pbuf, \"%s:%%p\", &p_%s);\n" " if (p_%s)\n" " return p_%s;\n\n", name, name, name, name, name, name); } void mex_casting_getter(FILE* fp, const char* cname, InheritsDecl* inherits) { fprintf(fp, "\n%s* mxWrapGetP_%s(const mxArray* a, const char** e)\n", cname, cname); fprintf(fp, "{\n" " char pbuf[128];\n" " if (mxGetClassID(a) == mxDOUBLE_CLASS &&\n" " mxGetM(a)*mxGetN(a) == 1 &&\n" "#if MX_HAS_INTERLEAVED_COMPLEX\n" " ((mxIsComplex(a) ? ((*mxGetComplexDoubles(a)).real == 0 && (*mxGetComplexDoubles(a)).imag == 0) : *mxGetDoubles(a) == 0))\n" "#else\n" " *mxGetPr(a) == 0\n" "#endif\n" " )\n" " return NULL;\n" " if (!mxIsChar(a)) {\n" "#ifdef R2008OO\n" " mxArray* ap = mxGetProperty(a, 0, \"mwptr\");\n" " if (ap)\n" " return mxWrapGetP_%s(ap, e);\n" "#endif\n" " *e = \"Invalid pointer\";\n" " return NULL;\n" " }\n" " mxGetString(a, pbuf, sizeof(pbuf));\n\n", cname); mex_casting_getter_type(fp, cname); for (InheritsDecl* i = inherits; i; i = i->next) mex_casting_getter_type(fp, i->name); fprintf(fp, " *e = \"Invalid pointer to %s\";\n" " return NULL;\n" "}\n\n", cname); } void mex_casting_getters(FILE* fp) { map::iterator i = class_decls.begin(); for (; i != class_decls.end(); ++i) mex_casting_getter(fp, i->first.c_str(), i->second); } void mex_cast_get_p(FILE* fp, const char* basetype, int input_label) { fprintf(fp, " in%d_ = ", input_label); if (is_mxarray_type(basetype)) fprintf(fp, "mxWrapGet_%s(prhs[%d], &mw_err_txt_);\n", basetype, input_label); else if (class_decls.find(basetype) == class_decls.end()) fprintf(fp, "(%s*) mxWrapGetP(prhs[%d], \"%s:%%p\", &mw_err_txt_);\n", basetype, input_label, basetype); else fprintf(fp, "mxWrapGetP_%s(prhs[%d], &mw_err_txt_);\n", basetype, input_label); fprintf(fp, " if (mw_err_txt_)\n" " goto mw_err_label;\n\n"); } /* -- Mex stub variable declarations -- */ /* * In each stub function, we declare local variables corresponding to * arguments (input and output), return values, and dimension parameters. * We use the names inX_, outX_, and dimX_ to represent input/inout, output * and dimension parameters, where X is the index in the prhs array or * plhs array. */ void mex_declare_type(char* typebuf, Var* v) { if (is_obj(v->tinfo) || is_array(v->tinfo)){ if(v->devicespec == 'g'){ sprintf(typebuf, "%s*", basetype_to_cucomplex(v->basetype)); } else{ sprintf(typebuf, "%s*", v->basetype); } } else if (v->tinfo == VT_rarray){ if(v->devicespec == 'g'){ sprintf(typebuf, "const %s*", basetype_to_cucomplex(v->basetype)); } else{ sprintf(typebuf, "const %s*", v->basetype); } } else if (v->tinfo == VT_scalar || v->tinfo == VT_cscalar || v->tinfo == VT_zscalar || v->tinfo == VT_r_scalar || v->tinfo == VT_r_cscalar || v->tinfo == VT_r_zscalar || v->tinfo == VT_p_scalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar) sprintf(typebuf, "%s", v->basetype); else if (v->tinfo == VT_string) sprintf(typebuf, "char*"); else if (v->tinfo == VT_mx && v->iospec == 'i') sprintf(typebuf, "const mxArray*"); else if (v->tinfo == VT_mx && v->iospec == 'o') sprintf(typebuf, "mxArray*"); else { fprintf(stderr, "v->tinfo == %d; v->name = %s\n", v->tinfo, v->name); assert(0); } } void mex_declare_in_args(FILE* fp, Var* v) { if (!v) return; if (v->iospec != 'o' && v->tinfo != VT_const) { char typebuf[128]; mex_declare_type(typebuf, v); if (is_array(v->tinfo) || is_obj(v->tinfo) || v->tinfo == VT_string) { fprintf(fp, " %-10s in%d_ =0; /* %-10s */\n", typebuf, v->input_label, v->name); if(v->devicespec == 'g'){ fprintf(fp, " %-10s *mxGPUArray_in%d_ =0; /* %-10s */\n", "mxGPUArray const", v->input_label, v->name); } } else { fprintf(fp, " %-10s in%d_; /* %-10s */\n", typebuf, v->input_label, v->name); } } mex_declare_in_args(fp, v->next); } void mex_declare_out_args(FILE* fp, Var* v) { if (!v) return; if (v->iospec == 'o' && v->tinfo != VT_mx) { char typebuf[128]; mex_declare_type(typebuf, v); if (is_array(v->tinfo) || is_obj(v->tinfo) || v->tinfo == VT_string) { fprintf(fp, " %-10s out%d_=0; /* %-10s */\n", typebuf, v->output_label, v->name); if(v->devicespec == 'g'){ fprintf(fp, " %-10s *mxGPUArray_out%d_ =0; /* %-10s */\n", "mxGPUArray", v->output_label, v->name); fprintf(fp, " %-10s gpu_outdims%d_[2] = {0,0}; /* %-10s dims*/\n", "mwSize", v->output_label, v->name); } } else { fprintf(fp, " %-10s out%d_; /* %-10s */\n", typebuf, v->output_label, v->name); } } mex_declare_out_args(fp, v->next); } void mex_declare_dim_args(FILE* fp, Expr* e) { if (!e) return; fprintf(fp, " %-10s dim%d_; /* %-10s */\n", "mwSize", e->input_label, e->value); mex_declare_dim_args(fp, e->next); } void mex_declare_dim_args(FILE* fp, Var* v) { if (!v) return; if (v->qual) mex_declare_dim_args(fp, v->qual->args); mex_declare_dim_args(fp, v->next); } void mex_declare_return(FILE* fp, Var* v) { mex_declare_out_args(fp, v); } void mex_declare_args(FILE* fp, Func* f) { if (f->thisv) { char typebuf[128]; strcpy(typebuf, f->classv); strcat(typebuf, "*"); fprintf(fp, " %-10s in%d_ =0; /* %-10s */\n", typebuf, 0, f->thisv); } mex_declare_in_args(fp, f->args); if (!nullable_return(f)) mex_declare_return(fp, f->ret); mex_declare_out_args(fp, f->args); mex_declare_dim_args(fp, f->ret); mex_declare_dim_args(fp, f->args); if (f->ret || f->args || f->thisv) fprintf(fp, "\n"); } /* -- Mex stub dimension retrieval -- */ /* * After declaring local variables, we copy in the dimension arguments. */ int mex_unpack_dims(FILE* fp, Expr* e) { if (!e) return 0; fprintf(fp, " dim%d_ = (mwSize) mxWrapGetScalar(prhs[%d], &mw_err_txt_);\n", e->input_label, e->input_label); return mex_unpack_dims(fp, e->next)+1; } int mex_unpack_dims(FILE* fp, Var* v) { if (!v) return 0; if (v->qual) return mex_unpack_dims(fp, v->qual->args) + mex_unpack_dims(fp, v->next); return mex_unpack_dims(fp, v->next); } void mex_unpack_dims(FILE* fp, Func* f) { if (mex_unpack_dims(fp, f->ret) || mex_unpack_dims(fp, f->args)) fprintf(fp, "\n"); } /* -- Mex stub dimension checks -- */ /* * For input and inout arrays where the dimensions are given explicitly * in the call, we check that the dimensions of the MATLAB array passed * in agree with the dimensions in the dimension arguments. */ void mex_check_dims(FILE* fp, Var* v) { if (!v) return; if (v->iospec != 'o' && is_array(v->tinfo) && v->qual && v->qual->args && v->devicespec != 'g') { Expr* a = v->qual->args; if (a->next) { fprintf(fp, " if (mxGetM(prhs[%d]) != dim%d_ ||\n" " mxGetN(prhs[%d]) != dim%d_) {\n" " mw_err_txt_ = \"Bad argument size: %s\";\n" " goto mw_err_label;\n" " }\n\n", v->input_label, a->input_label, v->input_label, a->next->input_label, v->name); } else { fprintf(fp, " if (mxGetM(prhs[%d])*mxGetN(prhs[%d]) != dim%d_) {\n" " mw_err_txt_ = \"Bad argument size: %s\";" " goto mw_err_label;\n" " }\n\n", v->input_label, v->input_label, a->input_label, v->name); } } mex_check_dims(fp, v->next); } void mex_check_dims(FILE* fp, Func* f) { if (!fp) return; mex_check_dims(fp, f->args); } /* -- Output size data -- */ /* * Generate code to compute the size of an array from dim arguments. */ void mex_alloc_size1(FILE* fp, Expr* e) { if (!e) return; fprintf(fp, "dim%d_", e->input_label); if (e->next) { fprintf(fp, "*"); mex_alloc_size1(fp, e->next); } } void mex_alloc_size(FILE* fp, Expr* e) { if (!e) fprintf(fp, "1"); else mex_alloc_size1(fp, e); } /* -- Unpack input data -- */ /* * Generate code to copy data from the prhs array into the inX_ * local variables in a stub function. Note that for input strings, * we take any explicit dimension information as what the user wants -- * if the string is too long to fit in that explicit dimension, our * generated code will return with an error message. */ void mex_unpack_input_array(FILE* fp, Var* v) { if (v->devicespec != 'g'){ fprintf(fp, " if (mxGetM(prhs[%d])*mxGetN(prhs[%d]) != 0) {\n", v->input_label, v->input_label); if (strcmp(v->basetype, "fcomplex") == 0) fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxSINGLE_CLASS )\n" " mw_err_txt_ = \"Invalid array argument, mxSINGLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " in%d_ = mxWrapGetArray_single_%s(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->input_label, v->basetype, v->input_label); else if (strcmp(v->basetype, "dcomplex") == 0) fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxDOUBLE_CLASS )\n" " mw_err_txt_ = \"Invalid array argument, mxDOUBLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " in%d_ = mxWrapGetArray_%s(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->input_label, v->basetype, v->input_label); else if (strcmp(v->basetype, "float") == 0) if (v->iospec == 'i') fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxSINGLE_CLASS )\n" " mw_err_txt_ = \"Invalid array argument, mxSINGLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" "#if MX_HAS_INTERLEAVED_COMPLEX\n" " in%d_ = mxGetSingles(prhs[%d]);\n" "#else\n" " in%d_ = (float*) mxGetData(prhs[%d]);\n" "#endif\n", v->input_label, v->input_label, v->input_label, v->input_label, v->input_label); else fprintf(fp, " in%d_ = mxWrapGetArray_single_%s(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->basetype, v->input_label); else if (strcmp(v->basetype, "double") == 0) if (v->iospec == 'i'){ fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxDOUBLE_CLASS )\n" " mw_err_txt_ = \"Invalid array argument, mxDOUBLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" "#if MX_HAS_INTERLEAVED_COMPLEX\n" " in%d_ = mxGetDoubles(prhs[%d]);\n" "#else\n" " in%d_ = mxGetPr(prhs[%d]);\n" "#endif\n", v->input_label, v->input_label, v->input_label, v->input_label, v->input_label); } else fprintf(fp, " in%d_ = mxWrapGetArray_%s(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->basetype, v->input_label); else fprintf(fp, " in%d_ = mxWrapGetArray_%s(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->basetype, v->input_label); fprintf(fp, " } else\n" " in%d_ = NULL;\n", v->input_label); fprintf(fp, "\n"); } if (v->devicespec == 'g'){ if (v->iospec == 'i' || v->iospec == 'b'){ fprintf(fp, " // extract input GPU array pointer\n" " if(!(mxIsGPUArray(prhs[%d])))\n" " mw_err_txt_ = \"Invalid array argument, gpuArray expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " mxGPUArray_in%d_ = mxGPUCreateFromMxArray(prhs[%d]);\n" " in%d_ = (%s *)mxGPUGetDataReadOnly(mxGPUArray_in%d_);\n\n", v->input_label, v->input_label, v->input_label, v->input_label, basetype_to_cucomplex(v->basetype), v->input_label); } } } void mex_unpack_input_string(FILE* fp, Var* v) { if (!(v->qual && v->qual->args)) fprintf(fp, " in%d_ = mxWrapGetString(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->input_label); else { fprintf(fp, " in%d_ = (char*) mxMalloc(", v->input_label); mex_alloc_size(fp, v->qual->args); fprintf(fp, "*sizeof(char));\n"); fprintf(fp, " if (mxGetString(prhs[%d], in%d_, ", v->input_label, v->input_label); mex_alloc_size(fp, v->qual->args); fprintf(fp, ") != 0) {\n" " mw_err_txt_ = \"Invalid string argument\";\n" " goto mw_err_label;\n" " }\n"); } fprintf(fp, "\n"); } void mex_unpack_inputs(FILE* fp, Var* v) { if (!v) return; if (v->iospec == 'o') { mex_unpack_inputs(fp, v->next); return; } if (is_obj(v->tinfo)) mex_cast_get_p(fp, v->basetype, v->input_label); else if (is_array(v->tinfo)) mex_unpack_input_array(fp, v); else if (v->tinfo == VT_scalar || v->tinfo == VT_r_scalar || v->tinfo == VT_p_scalar) { if ( strcmp(v->basetype,"float") == 0 ) fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxSINGLE_CLASS )\n" " mw_err_txt_ = \"Invalid scalar argument, mxSINGLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " in%d_ = (%s) mxWrapGetScalar_single(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n\n", v->input_label, v->input_label, v->basetype, v->input_label); else if ( strcmp(v->basetype,"char") == 0 ) fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxCHAR_CLASS )\n" " mw_err_txt_ = \"Invalid scalar argument, mxCHAR_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " in%d_ = (%s) mxWrapGetScalar_char(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", v->input_label, v->input_label, v->basetype, v->input_label); else fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxDOUBLE_CLASS )\n" " mw_err_txt_ = \"Invalid scalar argument, mxDOUBLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n" " in%d_ = (%s) mxWrapGetScalar(prhs[%d], &mw_err_txt_);\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n\n", v->input_label, v->input_label, v->basetype, v->input_label); } else if (v->tinfo == VT_cscalar || v->tinfo == VT_zscalar || v->tinfo == VT_r_cscalar || v->tinfo == VT_r_zscalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar) { if ( strcmp(v->basetype,"fcomplex") == 0 ) { fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxSINGLE_CLASS )\n" " mw_err_txt_ = \"Invalid scalar argument, mxSINGLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n", v->input_label); fprintf(fp, " mxWrapGetScalar_single_%s(&in%d_, prhs[%d]);\n\n", v->basetype, v->input_label, v->input_label); } else { fprintf(fp, " if( mxGetClassID(prhs[%d]) != mxDOUBLE_CLASS )\n" " mw_err_txt_ = \"Invalid scalar argument, mxDOUBLE_CLASS expected\";\n" " if (mw_err_txt_) goto mw_err_label;\n", v->input_label); fprintf(fp, " mxWrapGetScalar_%s(&in%d_, prhs[%d]);\n\n", v->basetype, v->input_label, v->input_label); } } else if (v->tinfo == VT_string) mex_unpack_input_string(fp, v); else if (v->tinfo == VT_mx) fprintf(fp, " in%d_ = prhs[%d];\n\n", v->input_label, v->input_label); mex_unpack_inputs(fp, v->next); } void mex_unpack_inputs(FILE* fp, Func* f) { if (f->thisv) mex_cast_get_p(fp, f->classv, 0); mex_unpack_inputs(fp, f->args); } /* -- Check input data -- */ /* * If an input variable is declared to be an object or a reference to * an object, we check to make sure the pointer passed in is not NULL. */ void mex_check_inputs(FILE* fp, Var* v) { if (!v) return; if (v->iospec != 'o' && (v->tinfo == VT_obj || v->tinfo == VT_r_obj)) fprintf(fp, " if (!in%d_) {\n" " mw_err_txt_ = \"Argument %s cannot be null\";\n" " goto mw_err_label;\n" " }\n", v->input_label, v->name); mex_check_inputs(fp, v->next); } void mex_check_inputs(FILE* fp, Func* f) { mex_check_inputs(fp, f->args); } /* -- Allocate output data -- */ /* * When we allocate data for output variables, we only allocate data * for *pure* output variables. For input/output variables, we'll use * the scratch copy of the input as the scratch copy of the output, too. */ void mex_alloc_output(FILE* fp, Var* v, bool return_flag) { if (!v) return; if (v->iospec == 'o') { if (v->devicespec != 'g'){ if (!return_flag && is_obj(v->tinfo) && is_mxarray_type(v->basetype)) { fprintf(fp, " out%d_ = mxWrapAlloc_%s();\n", v->output_label, v->basetype); } else if (is_array(v->tinfo)) { fprintf(fp, " out%d_ = (%s*) mxMalloc(", v->output_label, v->basetype); mex_alloc_size(fp, v->qual->args); fprintf(fp, "*sizeof(%s));\n", v->basetype); } else if (v->tinfo == VT_rarray) { fprintf(fp, " out%d_ = (%s*) NULL;\n", v->output_label, v->basetype); } else if (v->tinfo == VT_string) { fprintf(fp, " out%d_ = (char*) mxMalloc(", v->output_label); mex_alloc_size(fp, v->qual->args); fprintf(fp, "*sizeof(char));\n"); } } if (v->devicespec == 'g') { // need to allocate Expr* e = v->qual->args; int ndims = 0; if (e && e->next && !e->next->next) { ndims = 2; } else { ndims = 1; } const char* mtype = complex_tinfo(v) ? "mxCOMPLEX" : "mxREAL"; const char* mxclassid = basetype_to_mxclassid(v->basetype); if (ndims == 2) { fprintf(fp, " gpu_outdims%d_[0] = dim%d_; gpu_outdims%d_[1] = dim%d_;\n", v->output_label, e->input_label, v->output_label, e->next->input_label); } if (ndims == 1) { fprintf(fp, " gpu_outdims%d_[0] = dim%d_;\n", v->output_label, e->input_label); } fprintf(fp, " mxGPUArray_out%d_ = mxGPUCreateGPUArray(%d, gpu_outdims%d_, %s, %s, MX_GPU_DO_NOT_INITIALIZE);\n", v->output_label, ndims, v->output_label, mxclassid, mtype); fprintf(fp, " out%d_ = (%s *)mxGPUGetData(mxGPUArray_out%d_);\n\n", v->output_label, basetype_to_cucomplex(v->basetype), v->output_label); } } mex_alloc_output(fp, v->next, return_flag); } void mex_alloc_output(FILE* fp, Func* f) { if (!nullable_return(f)) mex_alloc_output(fp, f->ret, true); mex_alloc_output(fp, f->args, false); } /* -- Record that this routine was called -- */ /* * For coverage testing, we keep a counter of the number of times each * stub is called. */ void mex_record_call(FILE* fp, Func* f) { fprintf(fp, " if (mexprofrecord_)\n" " mexprofrecord_[%d]++;\n", f->id); } /* -- Make the call -- */ /* * The only non-obvious aspect of the call line is the way that return * values are treated. The biggest issue is that functions can return * NULL, and we need to present that to the user in some reasonable * way that won't be confused with an ordinary return -- this is why * we use 0 to represent a null return for a string or an object, but * we use an empty array to represent a null return for a numeric * object. A secondary issue has to do with strings -- we won't know the * size of a return string until after we have it in hand. Both because * of the possibility of NULL returns and because of the indeterminate size * of strings, we allocate space to hold return values *with* the call, * rather than setting up space before the call. */ void mex_make_call(FILE* fp, Var* v, int first) { if (!v) return; if (!first) fprintf(fp, ", "); char namebuf[128]; if (v->tinfo == VT_obj || v->tinfo == VT_r_obj) fprintf(fp, "*%s", vname(v, namebuf)); else if (v->tinfo == VT_mx && v->iospec == 'o') fprintf(fp, "plhs+%d", v->output_label); else if (v->tinfo == VT_p_scalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar) fprintf(fp, "&%s", vname(v, namebuf)); else if (v->tinfo == VT_const) fprintf(fp, "%s", v->name); else fprintf(fp, "%s", vname(v, namebuf)); mex_make_call(fp, v->next, 0); } void mex_make_call(FILE* fp, Func* f) { if (f->thisv) fprintf(fp, "in0_->"); if (strcmp(f->funcv, "new") == 0) fprintf(fp, "new %s(", f->classv); else { if (f->fort) fprintf(fp, "MWF77_"); fprintf(fp, "%s(", f->funcv); } mex_make_call(fp, f->args, 1); fprintf(fp, ")"); } void mex_make_stmt(FILE* fp, Func* f) { if (!f) return; if (f->thisv) fprintf(fp, " if (!in0_) {\n" " mw_err_txt_ = \"Cannot dispatch to NULL\";\n" " goto mw_err_label;\n" " }\n"); if (mw_generate_catch) fprintf(fp, " try {\n "); if (f->ret) { Var* v = f->ret; if (v->tinfo == VT_obj) { if (is_mxarray_type(v->basetype)) { fprintf(fp, " plhs[0] = mxWrapSet_%s(&(", v->basetype); mex_make_call(fp, f); fprintf(fp ,"));\n"); } else { fprintf(fp, " out0_ = new %s(", v->basetype); mex_make_call(fp, f); fprintf(fp ,");\n"); } } else if (is_array(v->tinfo)) { fprintf(fp, " plhs[0] = mxWrapReturn_%s(", v->basetype); mex_make_call(fp, f); fprintf(fp, ", "); Expr* e = v->qual->args; if (e && e->next && !e->next->next) { fprintf(fp, " dim%d_, dim%d_);\n", e->input_label, e->next->input_label); } else { mex_alloc_size(fp, v->qual->args); fprintf(fp, ", 1);\n"); } } else if (v->tinfo == VT_scalar || v->tinfo == VT_r_scalar || v->tinfo == VT_cscalar || v->tinfo == VT_r_cscalar || v->tinfo == VT_zscalar || v->tinfo == VT_r_zscalar) { fprintf(fp, " out0_ = "); mex_make_call(fp, f); fprintf(fp, ";\n"); } else if (v->tinfo == VT_string) { fprintf(fp, " plhs[0] = mxWrapStrncpy("); mex_make_call(fp, f); fprintf(fp, ");\n"); } else if (v->tinfo == VT_mx) { fprintf(fp, " plhs[0] = "); mex_make_call(fp, f); fprintf(fp, ";\n"); } else if (v->tinfo == VT_p_obj) { if (is_mxarray_type(v->basetype)) { fprintf(fp, " plhs[0] = mxWrapSet_%s(", v->basetype); mex_make_call(fp, f); fprintf(fp, ");\n"); } else { fprintf(fp, " out0_ = "); mex_make_call(fp, f); fprintf(fp, ";\n"); } } else if (v->tinfo == VT_p_scalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar) { fprintf(fp, " plhs[0] = mxWrapReturn_%s(", v->basetype); mex_make_call(fp, f); fprintf(fp, ", 1, 1);\n"); } else if (v->tinfo == VT_r_obj) { if (is_mxarray_type(v->basetype)) { fprintf(fp, " plhs[0] = mxWrapSet_%s(&(", v->basetype); mex_make_call(fp, f); fprintf(fp, "));\n"); } else { fprintf(fp, " out0_ = &("); mex_make_call(fp, f); fprintf(fp, ");\n"); } } } else { fprintf(fp, " "); mex_make_call(fp, f); fprintf(fp, ";\n"); } if (mw_generate_catch) fprintf(fp, " } catch(...) {\n" " mw_err_txt_ = \"Caught C++ exception from %s\";\n" " }\n" " if (mw_err_txt_)\n" " goto mw_err_label;\n", f->funcv); } /* -- Marshal the results -- */ /* * Copy inout arguments, output arguments, and any simple return * arguments into the plhs array. */ void mex_marshal_array(FILE* fp, Var* v) { if (v->devicespec != 'g'){ Expr* e = v->qual->args; char namebuf[128]; const char* mtype = complex_tinfo(v) ? "mxCOMPLEX" : "mxREAL"; const char* ws = " "; if (v->tinfo == VT_rarray) { ws = " "; fprintf(fp, " if (out%d_ == NULL) {\n", v->output_label); fprintf(fp, " plhs[%d] = mxCreateDoubleMatrix(0,0, mxREAL);\n", v->output_label); fprintf(fp, " } else {\n"); } if (!e) { // No dimension info -- must be an inout array if (strcmp(v->basetype, "float") == 0 || strcmp(v->basetype, "fcomplex") == 0) { fprintf(fp, "%splhs[%d] = mxCreateNumericMatrix(" "mxGetM(prhs[%d]), mxGetN(prhs[%d]), mxSINGLE_CLASS, %s);\n", ws, v->output_label, v->input_label, v->input_label, mtype); fprintf(fp, "%smxWrapCopy_single_%s(plhs[%d], in%d_, ", ws, v->basetype, v->output_label, v->input_label); } else { fprintf(fp, "%splhs[%d] = mxCreateDoubleMatrix(" "mxGetM(prhs[%d]), mxGetN(prhs[%d]), %s);\n", ws, v->output_label, v->input_label, v->input_label, mtype); fprintf(fp, "%smxWrapCopy_%s(plhs[%d], in%d_, ", ws, v->basetype, v->output_label, v->input_label); } fprintf(fp, "mxGetM(prhs[%d])*mxGetN(prhs[%d])", v->input_label, v->input_label); fprintf(fp, ");\n"); } else if (!(e->next)) { // Only size given if (strcmp(v->basetype, "float") == 0 || strcmp(v->basetype, "fcomplex") == 0) { fprintf(fp, "%splhs[%d] = mxCreateNumericMatrix(dim%d_, 1, mxSINGLE_CLASS, %s);\n", ws, v->output_label, e->input_label, mtype); fprintf(fp, "%smxWrapCopy_single_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } else { fprintf(fp, "%splhs[%d] = mxCreateDoubleMatrix(dim%d_, 1, %s);\n", ws, v->output_label, e->input_label, mtype); fprintf(fp, "%smxWrapCopy_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } fprintf(fp, "dim%d_", e->input_label); fprintf(fp, ");\n"); } else if (!(e->next->next)) { // Two dimensions given if (strcmp(v->basetype, "float") == 0 || strcmp(v->basetype, "fcomplex") == 0) { fprintf(fp, "%splhs[%d] = mxCreateNumericMatrix(" "dim%d_, dim%d_, mxSINGLE_CLASS, %s);\n", ws, v->output_label, e->input_label, e->next->input_label, mtype); fprintf(fp, "%smxWrapCopy_single_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } else { fprintf(fp, "%splhs[%d] = mxCreateDoubleMatrix(" "dim%d_, dim%d_, %s);\n", ws, v->output_label, e->input_label, e->next->input_label, mtype); fprintf(fp, "%smxWrapCopy_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } fprintf(fp, "dim%d_*dim%d_", e->input_label, e->next->input_label); fprintf(fp, ");\n"); } else { // Three or more dimensions given -- punt and make it 1D if (strcmp(v->basetype, "float") == 0 || strcmp(v->basetype, "fcomplex") == 0) { fprintf(fp, "%splhs[%d] = mxCreateNumericMatrix(", ws, v->output_label); mex_alloc_size(fp, e); fprintf(fp, ", 1, mxSINGLE_CLASS, %s);\n", mtype); fprintf(fp, "%smxWrapCopy_single_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } else { fprintf(fp, "%splhs[%d] = mxCreateDoubleMatrix(", ws, v->output_label); mex_alloc_size(fp, e); fprintf(fp, ", 1, %s);\n", mtype); fprintf(fp, "%smxWrapCopy_%s(plhs[%d], %s, ", ws, v->basetype, v->output_label, vname(v, namebuf)); } mex_alloc_size(fp, e); fprintf(fp, ");\n"); } if (v->tinfo == VT_rarray) { fprintf(fp, " }\n"); } } if (v->devicespec == 'g'){ if (v->iospec == 'b') { fprintf(fp, " plhs[%d] = prhs[%d];\n", v->output_label, v->input_label); } if (v->iospec == 'o') { fprintf(fp, " plhs[%d] = mxGPUCreateMxArrayOnGPU(mxGPUArray_out%d_);\n", v->output_label, v->output_label); } } } void mex_marshal_result(FILE* fp, Var* v, bool return_flag) { char namebuf[1280]; if (is_obj(v->tinfo) && is_mxarray_type(v->basetype)) { if (!return_flag) fprintf(fp, " plhs[%d] = mxWrapSet_%s(%s);\n", v->output_label, v->basetype, vname(v,namebuf)); } else if (is_obj(v->tinfo)) fprintf(fp, " plhs[%d] = mxWrapCreateP(out%d_, \"%s:%%p\");\n", v->output_label, v->output_label, v->basetype); else if (is_array(v->tinfo) || v->tinfo == VT_rarray) mex_marshal_array(fp, v); else if (v->tinfo == VT_scalar || v->tinfo == VT_r_scalar || v->tinfo == VT_p_scalar) fprintf(fp, "#if MX_HAS_INTERLEAVED_COMPLEX\n" " plhs[%d] = mxCreateDoubleMatrix(1, 1, mxREAL);\n" " *mxGetDoubles(plhs[%d]) = %s;\n" "#else\n" " plhs[%d] = mxCreateDoubleMatrix(1, 1, mxREAL);\n" " *mxGetPr(plhs[%d]) = %s;\n" "#endif\n", v->output_label, v->output_label, vname(v, namebuf), v->output_label, v->output_label, vname(v, namebuf)); else if (v->tinfo == VT_cscalar || v->tinfo == VT_zscalar || v->tinfo == VT_r_cscalar || v->tinfo == VT_r_zscalar || v->tinfo == VT_p_cscalar || v->tinfo == VT_p_zscalar) fprintf(fp, "#if MX_HAS_INTERLEAVED_COMPLEX\n" " plhs[%d] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX);\n" " mxGetComplexDoubles(plhs[%d])->real = real_%s(%s);\n" " mxGetComplexDoubles(plhs[%d])->imag = imag_%s(%s);\n" "#else\n" " plhs[%d] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX);\n" " *mxGetPr(plhs[%d]) = real_%s(%s);\n" " *mxGetPi(plhs[%d]) = imag_%s(%s);\n" "#endif\n", v->output_label, v->output_label, v->basetype, vname(v, namebuf), v->output_label, v->basetype, vname(v, namebuf), v->output_label, v->output_label, v->basetype, vname(v, namebuf), v->output_label, v->basetype, vname(v, namebuf)); else if (v->tinfo == VT_string) fprintf(fp, " plhs[%d] = mxCreateString(%s);\n", v->output_label, vname(v, namebuf)); } void mex_marshal_results(FILE* fp, Var* v, bool return_flag) { if (!v) return; if (v->iospec != 'i') mex_marshal_result(fp, v, return_flag); mex_marshal_results(fp, v->next, return_flag); } void mex_marshal_results(FILE* fp, Func* f) { if (!nullable_return(f)) mex_marshal_results(fp, f->ret, true); mex_marshal_results(fp, f->args, false); } /* -- Deallocate temporary data -- */ /* * Free scratch arrays allocated to hold input copies and output * storage. */ void mex_dealloc(FILE* fp, Var* v, bool return_flag) { if (!v) return; if (v->devicespec != 'g'){ if (is_array(v->tinfo) || v->tinfo == VT_string) { if (v->iospec == 'o') fprintf(fp, " if (out%d_) mxFree(out%d_);\n", v->output_label, v->output_label); else if (v->iospec == 'b' || !(strcmp(v->basetype, "double") == 0 || strcmp(v->basetype, "float") == 0) ) fprintf(fp, " if (in%d_) mxFree(in%d_);\n", v->input_label, v->input_label); } else if (is_obj(v->tinfo) && is_mxarray_type(v->basetype)) { if (v->iospec == 'i' || v->iospec == 'b') fprintf(fp, " if (in%d_) mxWrapFree_%s(in%d_);\n", v->input_label, v->basetype, v->input_label); else if (v->iospec == 'o' && !return_flag) fprintf(fp, " if (out%d_) mxWrapFree_%s(out%d_);\n", v->output_label, v->basetype, v->output_label); } } if (v->devicespec == 'g'){ if (v->iospec == 'i' || v->iospec == 'b'){ fprintf(fp, " if (mxGPUArray_in%d_) mxGPUDestroyGPUArray(mxGPUArray_in%d_);\n", v->input_label, v->input_label); } if (v->iospec == 'o'){ fprintf(fp, " if (mxGPUArray_out%d_) mxGPUDestroyGPUArray(mxGPUArray_out%d_);\n", v->output_label, v->output_label); } } mex_dealloc(fp, v->next, return_flag); } void mex_dealloc(FILE* fp, Func* f) { if (!nullable_return(f)) mex_dealloc(fp, f->ret, true); mex_dealloc(fp, f->args, false); } /* -- Generate mex stub -- */ /* * Print a MEX stub function. We generate one of these for each * distinct call line in the input files. */ void print_c_comment(FILE* fp, Func* f) { fprintf(fp, "/* ---- %s: %d ----\n * ", f->fname.c_str(), f->line); print(fp, f); for (Func* fsame = f->same_next; fsame; fsame = fsame->next) fprintf(fp, " * Also at %s: %d\n", fsame->fname.c_str(), fsame->line); fprintf(fp, " */\n"); } void print_mex_stub(FILE* fp, Func* f) { print_c_comment(fp, f); fprintf(fp, "static const char* stubids%d_ = \"%s\";\n\n" "void mexStub%d(int nlhs, mxArray* plhs[],\n" " int nrhs, const mxArray* prhs[])\n" "{\n" " const char* mw_err_txt_ = 0;\n", f->id, id_string(f).c_str(), f->id); mex_declare_args(fp, f); mex_unpack_dims(fp, f); mex_check_dims(fp, f); mex_unpack_inputs(fp, f); mex_check_inputs(fp, f); mex_alloc_output(fp, f); mex_record_call(fp, f); mex_make_stmt(fp, f); mex_marshal_results(fp, f); fprintf(fp, "\nmw_err_label:\n"); mex_dealloc(fp, f); fprintf(fp, " if (mw_err_txt_)\n" " mexErrMsgTxt(mw_err_txt_);\n" "}\n\n"); } /* -- Generate profiler output routine -- */ /* * The profiler / coverage testing routines include starting, * ending, and reporting. Starting the profiler locks the MEX file * in memory. */ void make_profile_output(FILE* fp, Func* f, const char* printfunc) { fprintf(fp, " if (!mexprofrecord_)\n" " %s\"Profiler inactive\\n\");\n", printfunc); for (; f; f = f->next) { fprintf(fp, " %s\"%%d calls to %s:%d", printfunc, f->fname.c_str(), f->line); for (Func* fsame = f->same_next; fsame; fsame = fsame->next) fprintf(fp, " (%s:%d)", fsame->fname.c_str(), fsame->line); fprintf(fp, "\\n\", mexprofrecord_[%d]);\n", f->id); } } /* -- Generate MEX file -- */ /* * Generate the overall C file to be fed into MEX. This consists of * basic support code (from mwrap-support.c), type conversion * routines, all the call stubs, and a main dispatcher that decides * which stub to call. */ void print_mex_stubs(FILE* fp, Func* f) { for (; f; f = f->next) print_mex_stub(fp, f); } void print_mex_stub_table(FILE* fp, Func* f) { /* Build map: id -> stub_id. Functions on same_next chains share * the stub of the primary function in the next chain. */ int maxid = 0; map id_to_stub; for (Func* fcall = f; fcall; fcall = fcall->next) { id_to_stub[fcall->id] = fcall->id; if (fcall->id > maxid) maxid = fcall->id; for (Func* fsame = fcall->same_next; fsame; fsame = fsame->same_next) { id_to_stub[fsame->id] = fcall->id; if (fsame->id > maxid) maxid = fsame->id; } } if (maxid <= 0) return; fprintf(fp, "typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[],\n" " int nrhs, const mxArray* prhs[]);\n\n" "static mwStubFunc_t mwStubs_[] = {\n" " NULL"); for (int i = 1; i <= maxid; i++) { fprintf(fp, ",\n"); map::iterator it = id_to_stub.find(i); if (it != id_to_stub.end()) fprintf(fp, " mexStub%d", it->second); else fprintf(fp, " NULL"); } fprintf(fp, "\n};\n\n"); fprintf(fp, "static int mwNumStubs_ = %d;\n\n", maxid); } void print_mex_else_cases(FILE* fp, Func* f) { for (Func* fcall = f; fcall; fcall = fcall->next) fprintf(fp, " else if (strcmp(id, stubids%d_) == 0)\n" " mexStub%d(nlhs,plhs, nrhs-1,prhs+1);\n", fcall->id, fcall->id); int maxid = max_routine_id(f); fprintf(fp, " else if (strcmp(id, \"*profile on*\") == 0) {\n" " if (!mexprofrecord_) {\n" " mexprofrecord_ = (int*) malloc(%d * sizeof(int));\n" " mexLock();\n" " }\n" " memset(mexprofrecord_, 0, %d * sizeof(int));\n" " } else if (strcmp(id, \"*profile off*\") == 0) {\n" " if (mexprofrecord_) {\n" " free(mexprofrecord_);\n" " mexUnlock();\n" " }\n" " mexprofrecord_ = NULL;\n" " } else if (strcmp(id, \"*profile report*\") == 0) {\n", maxid+1, maxid+1); make_profile_output(fp, f, "mexPrintf("); fprintf(fp, " } else if (strcmp(id, \"*profile log*\") == 0) {\n" " FILE* logfp;\n" " if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0)\n" " mexErrMsgTxt(\"Must have two string arguments\");\n" " logfp = fopen(id, \"w+\");\n" " if (!logfp)\n" " mexErrMsgTxt(\"Cannot open log for output\");\n"); make_profile_output(fp, f, "fprintf(logfp, "); fprintf(fp, " fclose(logfp);\n"); fprintf(fp, " } else\n" " mexErrMsgTxt(\"Unknown identifier\");\n"); } const char* mwrap_banner = "/* --------------------------------------------------- */\n" "/* Automatically generated by mwrap */\n" "/* --------------------------------------------------- */\n\n"; const char* mexBase = "/* ----\n" " */\n" "void mexFunction(int nlhs, mxArray* plhs[],\n" " int nrhs, const mxArray* prhs[])\n" "{\n" " if (nrhs == 0) {\n" " mexPrintf(\"Mex function installed\\n\");\n" " return;\n" " }\n\n" " /* Fast path: integer stub ID */\n" " if (!mxIsChar(prhs[0])) {\n" " int stub_id = (int) mxGetScalar(prhs[0]);\n" " if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id])\n" " mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1);\n" " else\n" " mexErrMsgTxt(\"Unknown function ID\");\n" " return;\n" " }\n\n"; const char* mexBaseIf = " char id[1024];\n" " if (mxGetString(prhs[0], id, sizeof(id)) != 0)\n" " mexErrMsgTxt(\"Identifier should be a string\");\n"; const char* mwrap_compat_type_support = "/*\n" " * Compiler compatibility extensions\n" " */\n" "\n" "typedef unsigned long ulong;\n" "typedef unsigned int uint;\n" "typedef unsigned short ushort;\n" "typedef unsigned char uchar;\n" "typedef long long longlong;\n" "typedef unsigned long long ulonglong;\n"; // "#ifndef ulong\n" // "# define ulong unsigned long\n" // "#endif\n" // "#ifndef uint\n" // "# define uint unsigned int\n" // "#endif\n" // "#ifndef ushort\n" // "# define ushort unsigned short\n" // "#endif\n" // "#ifndef uchar\n" // "# define uchar unsigned char\n" // "#endif\n" // "\n" // "#ifndef longlong\n" // "# define longlong long long\n" // "#endif\n" // "#ifndef ulonglong\n" // "# define ulonglong unsigned long long\n" // "#endif\n"; void print_mex_init(FILE* fp) { fprintf(fp, "%s", mwrap_banner); fprintf(fp, "%s", mex_header); fprintf(fp, "\n"); if (mw_use_gpu) mex_use_gpu(fp); if (mw_use_c99_complex) mex_c99_complex(fp); else if (mw_use_cpp_complex) { mex_cpp_complex(fp); if (mw_use_gpu) mex_gpucpp_complex(fp); } // fprintf(fp, "\n"); // fprintf(fp, "%s", mwrap_compat_type_support); // fprintf(fp, "\n"); } void print_mex_file(FILE* fp, Func* f) { if (mw_use_int32_t || mw_use_int64_t || mw_use_uint32_t || mw_use_uint64_t) fprintf(fp, "#include \n\n"); mex_define_copiers(fp); mex_casting_getters(fp); if (has_fortran(f)) { mex_define_fnames(fp, f); mex_fortran_decls(fp, f); } print_mex_stubs(fp, f); print_mex_stub_table(fp, f); fprintf(fp, "%s", mexBase); fprintf(fp, "\n"); if (mw_use_gpu) fprintf(fp, " mxInitGPU();\n"); fprintf(fp, "\n"); fprintf(fp, "%s", mexBaseIf); print_mex_else_cases(fp, f); fprintf(fp, "}\n\n"); } zgimbutas-mwrap-25008ce/src/mwrap-mgen.cc000066400000000000000000000042071515063637600203620ustar00rootroot00000000000000/* * mwrap-mgen.cc * Generate MATLAB scripts from MWrap AST. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include #include "mwrap-ast.h" /* -- Output MATLAB call code -- */ /* * Each call is translated to MATLAB code of the form * * mex_id_ = 'identifier from id_string'; * [result1, result2, ...] = mexfunc(mex_id_, in1, ..., dim1, dim2, ...); * * where dim1, dim2, ... are any explicitly provided array dimensions. */ int has_output_args(Var* v) { if (!v) return 0; if (v->iospec == 'o' || v->iospec == 'b') return 1; else return has_output_args(v->next); } void print_output_args(FILE* fp, Var* v, int& first) { if (!v) return; if (v->iospec == 'o' || v->iospec == 'b') { if (!first) fprintf(fp, ", "); fprintf(fp, "%s", v->name); first = 0; } print_output_args(fp, v->next, first); } void print_input_args(FILE* fp, Var* v) { if (!v) return; if (v->tinfo == VT_const) fprintf(fp, ", 0"); else if (v->iospec == 'i' || v->iospec == 'b') fprintf(fp, ", %s", v->name); print_input_args(fp, v->next); } void print_dimension_args(FILE* fp, Expr* e) { if (!e) return; fprintf(fp, ", %s", e->value); print_dimension_args(fp, e->next); } void print_dimension_args(FILE* fp, Var* v) { if (!v) return; if (v->qual) print_dimension_args(fp, v->qual->args); print_dimension_args(fp, v->next); } void print_matlab_call(FILE* fp, Func* f, const char* mexfunc) { fprintf(fp, "mex_id_ = %d;\n", f->id); if (f->ret || has_output_args(f->args)) { int first = 1; fprintf(fp, "["); print_output_args(fp, f->ret, first); print_output_args(fp, f->args, first); fprintf(fp, "] = "); } fprintf(fp, "%s(mex_id_", mexfunc); if (f->thisv) fprintf(fp, ", %s", f->thisv); print_input_args(fp, f->args); print_dimension_args(fp, f->ret); print_dimension_args(fp, f->args); fprintf(fp, ");\n"); } zgimbutas-mwrap-25008ce/src/mwrap-support.c000066400000000000000000000551531515063637600210130ustar00rootroot00000000000000/* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif zgimbutas-mwrap-25008ce/src/mwrap-typecheck.cc000066400000000000000000000246721515063637600214230ustar00rootroot00000000000000/* * mwrap-typecheck.cc * Typecheck MWrap AST. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include #include #include "mwrap-ast.h" /* -- Label input / output indices -- */ /* * To each argument, we assign an input label (index of the argument * in the prhs array) and an output label (the index in the plhs * array). The protocol is that we pass input and inout arguments in * first, and then tack on all the dimensioning arguments at the end. */ void label_dim_args(Expr* e, int& icount) { if (!e) return; e->input_label = icount++; label_dim_args(e->next, icount); } void label_dim_args(Var* v, int& icount) { if (!v) return; if (v->qual) label_dim_args(v->qual->args, icount); label_dim_args(v->next, icount); } void label_args(Var* v, int& icount, int& ocount) { if (!v) return; if (v->iospec == 'i' || v->iospec == 'b') v->input_label = icount++; if (v->iospec == 'o' || v->iospec == 'b') v->output_label = ocount++; label_args(v->next, icount, ocount); } void label_args(Func* f) { int icount = 0; int ocount = 0; if (f->thisv) icount = 1; label_args(f->ret, icount, ocount); label_args(f->args, icount, ocount); label_dim_args(f->ret, icount); label_dim_args(f->args, icount); } /* -- Fortran-ize arguments -- */ /* * For FORTRAN calls, we make the following type conversions and * checks on arguments: * * - All types of scalar arguments are converted to pointer-to-scalar. * - Object arguments are forbidden * - C string arguments generate a warning * * Only scalar return values are allowed from wrapped FORTRAN functions. */ int fortranize_args(Var* v, int line) { if (!v) return 0; int errcount = 0; if (v->tinfo == VT_obj || v->tinfo == VT_p_obj || v->tinfo == VT_r_obj) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Cannot pass object %s to FORTRAN\n", v->name); ++errcount; } else if (v->tinfo == VT_rarray) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Cannot pass pointer ref %s to FORTRAN\n", v->name); ++errcount; } else if (v->tinfo == VT_string) { fprintf(stderr, "Warning (%d): ", line); fprintf(stderr, "Danger passing C string %s to FORTRAN\n", v->name); } else if (v->tinfo == VT_scalar || v->tinfo == VT_r_scalar) { v->tinfo = VT_p_scalar; } else if (v->tinfo == VT_cscalar || v->tinfo == VT_r_cscalar) { v->tinfo = VT_p_cscalar; } else if (v->tinfo == VT_zscalar || v->tinfo == VT_r_zscalar) { v->tinfo = VT_p_zscalar; } return errcount + fortranize_args(v->next, line); } int fortranize_ret(Var* v, int line) { if (!v) return 0; if (v->tinfo == VT_cscalar || v->tinfo == VT_zscalar) { fprintf(stderr, "Warning (%d): ", line); fprintf(stderr, "Danger returning complex from FORTRAN\n"); } else if (v->tinfo != VT_scalar) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Can only return scalars from FORTRAN\n"); return 1; } return 0; } int fortranize_args(Func* f, int line) { if (!f->fort) return 0; return (fortranize_args(f->args, line) + fortranize_ret(f->ret, line)); } /* -- Type info assignment and checking -- */ /* * Strictly speaking, we're doing semantic checking here -- there are a * few things we check for that don't qualify as type errors. The * assumption is that any input to the C code generator has passed the * type checker. */ int assign_scalar_tinfo(Var* v, int line, int tags, int tagp, int tagr, int taga, int tagar) { // Numeric types if (!v->qual) { v->tinfo = tags; } else if (v->qual->qual == '*') { v->tinfo = tagp; } else if (v->qual->qual == '&') { v->tinfo = tagr; } else if (v->qual->qual == 'a') { v->tinfo = taga; if (v->qual->args && v->qual->args->next && v->qual->args->next->next) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Array %s should be 1D or 2D\n", v->name); return 1; } } else if (v->qual->qual == 'r') { v->tinfo = tagar; if (tagar == VT_unk) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Array ref %s must be to a real array\n", v->name); return 1; } if (v->qual->args && v->qual->args->next && v->qual->args->next->next) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Array %s should be 1D or 2D\n", v->name); return 1; } } else { assert(0); } return 0; } int assign_tinfo(Var* v, int line) { if (is_scalar_type(v->basetype)) { return assign_scalar_tinfo(v, line, VT_scalar, VT_p_scalar, VT_r_scalar, VT_array, VT_rarray); } else if (is_cscalar_type(v->basetype)) { return assign_scalar_tinfo(v, line, VT_cscalar, VT_p_cscalar, VT_r_cscalar, VT_carray, VT_unk); } else if (is_zscalar_type(v->basetype)) { return assign_scalar_tinfo(v, line, VT_zscalar, VT_p_zscalar, VT_r_zscalar, VT_zarray, VT_unk); } else if (strcmp(v->basetype, "const") == 0) { if (v->qual) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Constant %s cannot have modifiers\n", v->name); return 1; } v->tinfo = VT_const; if (v->name[0] == '\'') { char* p_out = v->name; char* p_in = v->name; for (; *p_in; ++p_in) { if (*p_in != '\'') *p_out++ = *p_in; } *p_out++ = 0; } } else if (strcmp(v->basetype, "cstring") == 0) { // String type if (v->qual && v->qual->qual != 'a') { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "String type %s cannot have modifiers\n", v->name); return 1; } if (v->qual && v->qual->args && v->qual->args->next) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Strings are one dimensional\n"); return 1; } v->tinfo = VT_string; } else if (strcmp(v->basetype, "mxArray") == 0) { // MATLAB intrinsic type if (v->qual) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "mxArray %s cannot have modifiers\n", v->name); return 1; } v->tinfo = VT_mx; } else { // Object type if (!v->qual) v->tinfo = VT_obj; else if (v->qual->qual == '*') v->tinfo = VT_p_obj; else if (v->qual->qual == '&') v->tinfo = VT_r_obj; else if (v->qual->qual == 'a' || v->qual->qual == 'r') { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "%s cannot be an array of object %s\n", v->name, v->basetype); return 1; } else assert(0); } return 0; } int typecheck_return(Var* v, int line) { if (!v) return 0; int err = assign_tinfo(v, line); if ((v->tinfo == VT_array || v->tinfo == VT_carray || v->tinfo == VT_zarray) && !(v->qual && v->qual->args)) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Return array %s must have dims\n", v->name); ++err; } else if (v->tinfo == VT_const) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Cannot return constant\n"); ++err; } else if (v->tinfo == VT_rarray) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Ref to array %s looks just like array on return\n", v->name); ++err; } else if (v->tinfo == VT_string && v->qual) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Return string %s cannot have dims\n", v->name); ++err; } return err; } int typecheck_args(Var* v, int line) { if (!v) return 0; int err = assign_tinfo(v, line); if (v->iospec == 'i') return err + typecheck_args(v->next, line); if (isdigit(v->name[0])) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Number %s cannot be output\n", v->name); ++err; } if ((v->tinfo == VT_obj || v->tinfo == VT_p_obj || v->tinfo == VT_r_obj) && !is_mxarray_type(v->basetype)) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Object %s cannot be output\n", v->name); ++err; } else if ((v->tinfo == VT_array || v->tinfo == VT_carray || v->tinfo == VT_zarray || v->tinfo == VT_rarray) && v->iospec == 'o' && !(v->qual && v->qual->args)) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Output array %s must have dims\n", v->name); ++err; } else if (v->tinfo == VT_rarray && v->iospec != 'o' && v->iospec != 'b') { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Array ref %s *must* be output\n", v->name); ++err; } else if (v->tinfo == VT_scalar) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Scalar %s cannot be output\n", v->name); ++err; } else if (v->tinfo == VT_const) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "Constant %s cannot be output\n", v->name); ++err; } else if (v->tinfo == VT_string && !(v->qual && v->qual->args)) { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "String %s cannot be output without size\n", v->name); ++err; } else if (v->tinfo == VT_mx && v->iospec == 'b') { fprintf(stderr, "Error (%d): ", line); fprintf(stderr, "mxArray %s cannot be used for inout\n", v->name); ++err; } return err + typecheck_args(v->next, line); } int typecheck(Func* f, int line) { label_args(f); return (typecheck_return(f->ret, line) + typecheck_args(f->args, line) + fortranize_args(f, line)); } zgimbutas-mwrap-25008ce/src/mwrap.l000066400000000000000000000146131515063637600173060ustar00rootroot00000000000000%{ /* * mwrap.l * Lexer for MWrap. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include "mwrap.hh" #include #include extern int listing_flag; // Output filenames from @ commands? extern int mbatching_flag; // Do we want to output on @ commands? extern int linenum; // Lexer line number extern FILE* outfp; // MATLAB output file extern FILE* outcfp; // C output file static int done_at_switch; // Set when @ redirection is done extern char* mwrap_strdup(char* s); static int is_name_char(char c) { return (isalnum(c) || c == '_'); } static char* fname_scan_line(char* s) { static char namebuf[256]; /* FIXME */ int name_start, name_end, i, j; /* Name ends at last alphanum before args */ name_end = 0; while (s[name_end] && s[name_end] != '(') ++name_end; while (name_end > 0 && !is_name_char(s[name_end])) --name_end; /* Back up to the start of the name */ name_start = name_end; while (s[name_start] > 0 && is_name_char(s[name_start])) --name_start; /* Copy the name into the buf and add .m */ for (i = name_start+1, j = 0; i <= name_end; ++i, ++j) namebuf[j] = s[i]; strcpy(namebuf+j, ".m"); return namebuf; } #define MAX_INCLUDE_DEPTH 10 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; int include_stack_line[MAX_INCLUDE_DEPTH]; int include_stack_ptr = 0; extern void set_include_name(const char* s); extern void get_include_name(); /* The lexer switches states when it sees a specially formatted comment * as the first non-blank mode in a line. In total, there are six states: * * INITIAL - start of line * TS - ordinary text line * AS - at line (redirection) * FS - @function line (function declaration + redirection) * SS - embedded C line * BS - block of embedded C * CS - C call line * COMMS - Comment line * * Transitions are as follows. * * "$[" : INITIAL -> BS * "$]" : BS -> INITIAL * "@" : INITIAL -> AS (batching mode only) * "@function" : INITIAL -> FS * "$" : INITIAL -> SS * "#" : INITIAL -> CS * non-blank : INITIAL -> TS * newline: (AS, SS, CS, TS) -> INITIAL */ %} %s CSTATE %s SSTATE %s BSTATE %s ASTATE %s FSTATE %s TSTATE %s COMMSTATE %x INCLSTATE %% "@function" { if (mbatching_flag && outfp) fclose(outfp); BEGIN FSTATE; return NON_C_LINE; } "@include" { BEGIN INCLSTATE; return NON_C_LINE; } "@" { if (mbatching_flag && outfp) fclose(outfp); done_at_switch = 0; BEGIN ASTATE; return NON_C_LINE; } "#" { BEGIN CSTATE; } \$\[[ \t\r]*\n { BEGIN BSTATE; ++linenum; return NON_C_LINE; } "$" { BEGIN SSTATE; return NON_C_LINE; } "//" { BEGIN COMMSTATE; return NON_C_LINE; } \n { if (outfp) fprintf(outfp, "%s", yytext); ++linenum; BEGIN 0; return NON_C_LINE; } [ \t] { if (outfp) fprintf(outfp, "%s", yytext); } . { if (outfp) fprintf(outfp, "%s", yytext); BEGIN TSTATE; return NON_C_LINE; } \n { ++linenum; BEGIN 0; } . ; <> { if (--include_stack_ptr < 0) { yyterminate(); } else { yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(include_stack[include_stack_ptr]); linenum = include_stack_line[include_stack_ptr]; get_include_name(); BEGIN INCLSTATE; } } [ \t\r]* ; [^ \t\r\n]+ { if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { fprintf(stderr, "Error: Includes nested too deeply"); exit(-1); } set_include_name(yytext); include_stack_line[include_stack_ptr] = linenum; include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; yyin = fopen(yytext, "r"); if (!yyin) { fprintf(stderr, "Error: Could not read '%s'\n", yytext); exit(-1); } linenum = 1; yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); BEGIN 0; } \n { ++linenum; BEGIN 0; } [^\n]+ { char* fname = fname_scan_line(yytext); if (mbatching_flag) { outfp = fopen(fname, "w+"); if (!outfp) { fprintf(stderr, "Error: Could not write %s\n", yytext); exit(-1); } } if (listing_flag) fprintf(stdout, "%s\n", fname); if (outfp) fprintf(outfp, "function%s\n", yytext); } \n { ++linenum; BEGIN 0; } [ \t\r]+ ; [^ \t\r\n]+ { if (mbatching_flag && !done_at_switch) { outfp = fopen(yytext, "w+"); if (!outfp) { fprintf(stderr, "Error: Could not write %s\n", yytext); exit(-1); } } if (listing_flag && !done_at_switch) fprintf(stdout, "%s\n", yytext); done_at_switch = 1; } \n { ++linenum; BEGIN 0; } \n { if (outfp) fprintf(outfp, "%s", yytext); ++ linenum; BEGIN 0; } . { if (outfp) fprintf(outfp, "%s", yytext); } \n { if (outcfp) fprintf(outcfp, "%s", yytext); ++linenum; BEGIN 0; } . { if (outcfp) fprintf(outcfp, "%s", yytext); } \$\][ \t\r]*\n { ++linenum; BEGIN 0; } \n { if (outcfp) fprintf(outcfp, "%s", yytext); ++linenum; } . { if (outcfp) fprintf(outcfp, "%s", yytext); } "new" { return NEW; } "FORTRAN" { return FORTRAN; } "input" { return INPUT; } "output" { return OUTPUT; } "inout" { return INOUT; } "class" { return CLASS; } "typedef" { return TYPEDEF; } "cpu" { return CPU; } "gpu" { return GPU; } ((::)?[_a-zA-Z][_a-zA-Z0-9]*)* { yylval.string = mwrap_strdup(yytext); return ID; } [0-9]+ { yylval.string = mwrap_strdup(yytext); return NUMBER; } \'[^'\n]*['\n] { yylval.string = mwrap_strdup(yytext); return STRING; } \/\/[^\n]* ; [ \t\r]+ ; \n { ++linenum; BEGIN 0; } . return yytext[0]; %% zgimbutas-mwrap-25008ce/src/mwrap.y000066400000000000000000000277431515063637600173330ustar00rootroot00000000000000%{ /* * mwrap.y * Parser for mwrap. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include "mwrap-ast.h" extern "C" { int yylex(); int yywrap(); int yyerror(const char* s); } using std::string; bool mw_use_gpu = 0; // Use GPU? bool mw_generate_catch = false; // Catch C++ exceptions? bool mw_use_cpp_complex = false; // Use C++ complex types? bool mw_use_c99_complex = false; // Use C99 complex types? int mw_promote_int = 0; // Convert integer types to mwSize? int mw_use_int32_t = 0; // Use C99 int32_t? int mw_use_int64_t = 0; // Use C99 int64_t? int mw_use_uint32_t = 0; // Use C99 uint32_t? int mw_use_uint64_t = 0; // Use C99 uint64_t? int mw_use_ulong = 0; // Use unsigned long? int mw_use_uint = 0; // Use unsigned int? int mw_use_ushort = 0; // Use unsigned short? int mw_use_uchar = 0; // Use unsigned char? int listing_flag = 0; // Output filenames from @ commands? int mbatching_flag = 0; // Output on @ commands? int linenum = 0; // Lexer line number FILE* outfp = 0; // MATLAB output file FILE* outcfp = 0; // C output file static int type_errs = 0; // Number of typecheck errors static int func_id = 0; // Assign stub numbers static Func* funcs = 0; // AST - linked list of functions static Func* lastfunc = 0; // Last link in funcs list static const char* mexfunc = "mexfunction"; // Name of mex function static string current_ifname; // Current input file name #define MAX_INCLUDE_DEPTH 10 static string include_stack_names[MAX_INCLUDE_DEPTH]; extern int include_stack_ptr; extern "C" void set_include_name(const char* s) { include_stack_names[include_stack_ptr] = current_ifname; current_ifname = s; } extern "C" void get_include_name() { current_ifname = include_stack_names[include_stack_ptr].c_str(); } inline void add_func(Func* func) { static std::map func_lookup; if (!funcs) { funcs = func; lastfunc = func; return; } Func*& func_ptr = func_lookup[id_string(func)]; if (func_ptr) { func_ptr->same_next = func; } else { lastfunc->next = func; lastfunc = func; } func_ptr = func; } %} %union { char* string; struct Func* func; struct Var* var; struct TypeQual* qual; struct Expr* expr; struct InheritsDecl* inherits; char c; } %token NON_C_LINE %token NEW TYPEDEF CLASS FORTRAN %token ID %token NUMBER STRING %token INPUT OUTPUT INOUT %token CPU GPU %type func funcall %type var basevar args argsrest %type iospec %type devicespec %type quals aqual %type arrayspec exprs exprrest expr %type inheritslist inheritsrest %error-verbose %% statements: statement statements | ; statement: basevar '=' funcall { $3->ret = $1; $3->id = ++func_id; type_errs += typecheck($3, linenum); if (outfp) print_matlab_call(outfp, $3, mexfunc); add_func($3); } | funcall { $1->id = ++func_id; type_errs += typecheck($1, linenum); if (outfp) print_matlab_call(outfp, $1, mexfunc); add_func($1); } | tdef | classdef | NON_C_LINE | error ';' { yyerrok; } ; tdef: TYPEDEF ID ID ';' { if (strcmp($2, "numeric") == 0) { add_scalar_type($3); } else if (strcmp($2, "dcomplex") == 0) { add_zscalar_type($3); } else if (strcmp($2, "fcomplex") == 0) { add_cscalar_type($3); } else if (strcmp($2, "mxArray") == 0) { add_mxarray_type($3); } else { fprintf(stderr, "Unrecognized typespace: %s\n", $2); ++type_errs; } delete[] $2; delete[] $3; } ; classdef: CLASS ID ':' inheritslist ';' { add_inherits($2, $4); delete[] $2; destroy($4); } inheritslist: ID inheritsrest { $$ = new InheritsDecl($1, $2); } ; inheritsrest: ',' ID inheritsrest { $$ = new InheritsDecl($2, $3); } | { $$ = NULL; } ; funcall: func '(' args ')' ';' { $$ = $1; $$->args = $3; } ; args: var argsrest { $$ = $1; $$->next = $2; } | { $$ = NULL; } ; argsrest: ',' var argsrest {$$ = $2; $$->next = $3; } | { $$ = NULL; } ; basevar: ID ID { $$ = new Var('c', 'o', promote_int($1), NULL, $2); } basevar: ID quals ID { $$ = new Var('c', 'o', promote_int($1), $2, $3); } basevar: ID ID aqual { $$ = new Var('c', 'o', promote_int($1), $3, $2); } var: devicespec iospec ID ID { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals ID { $$ = new Var($1, $2, promote_int($3), $4, $5); } var: devicespec iospec ID ID aqual { $$ = new Var($1, $2, promote_int($3), $5, $4); } var: devicespec iospec ID NUMBER { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals NUMBER { $$ = new Var($1, $2, promote_int($3), $4, $5); } var: devicespec iospec ID STRING { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals STRING { $$ = new Var($1, $2, promote_int($3), $4, $5); } devicespec: CPU { $$ = 'c'; } | GPU { $$ = 'g'; } | { $$ = 'c'; } ; iospec: INPUT { $$ = 'i'; } | OUTPUT { $$ = 'o'; } | INOUT { $$ = 'b'; } | { $$ = 'i'; } ; quals: '*' { $$ = new TypeQual('*', NULL); } | '&' { $$ = new TypeQual('&', NULL); } | aqual { $$ = $1; } ; aqual: arrayspec { $$ = new TypeQual('a', $1); } | arrayspec '&' { $$ = new TypeQual('r', $1); } ; arrayspec: '[' exprs ']' { $$ = $2; } ; exprs: expr exprrest { $$ = $1; $$->next = $2; } | { $$ = NULL; } exprrest: ',' expr exprrest { $$ = $2; $$->next = $3; } | { $$ = NULL; } expr: ID { $$ = new Expr($1); } | NUMBER { $$ = new Expr($1); } func: ID '-' '>' ID '.' ID { $$ = new Func($1, $4, $6, current_ifname, linenum); } | ID { $$ = new Func(NULL, NULL, $1, current_ifname, linenum); } | FORTRAN ID { $$ = new Func(NULL, NULL, $2, current_ifname, linenum); $$->fort = true; } | NEW ID { $$ = new Func(NULL, $2, mwrap_strdup("new"), current_ifname, linenum); } ; %% #include #include extern FILE* yyin; int yywrap() { return 1; } int yyerror(const char* s) { fprintf(stderr, "Parse error (%s:%d): %s\n", current_ifname.c_str(), linenum, s); return 0; } char* mwrap_strdup(const char* s) { char* result = new char[strlen(s)+1]; strcpy(result, s); return result; } const char* usage_string = "Usage: mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] infile1 ...\n" "Try 'mwrap --help' for more information.\n"; const char* help_string = "mwrap 1.3 - MEX file generator for MATLAB and Octave\n" "\n" "Syntax:\n" " mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb] [-list]\n" " [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu] infile1 infile2 ...\n" "\n" " -mex outputmex -- specify the MATLAB mex function name\n" " -m output.m -- generate the MATLAB stub called output.m\n" " -c outputmex.c -- generate the C file outputmex.c\n" " -mb -- generate .m files specified with @ redirections\n" " -list -- list files specified with @ redirections\n" " -catch -- generate C++ exception handling code\n" " -i8 -- convert int, long, uint, ulong to int64_t, uint64_t\n" " -c99complex -- add support code for C99 complex types\n" " -cppcomplex -- add support code for C++ complex types\n" " -gpu -- add support code for MATLAB gpuArray\n" "\n"; int main(int argc, char** argv) { int j; int err_flag = 0; init_scalar_types(); if (argc == 1) { fprintf(stderr, "%s", help_string); return 0; } else { bool emitted_mex_init = false; const char* mfile = NULL; const char* cfile = NULL; for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "--help") == 0) { fprintf(stderr, "%s", help_string); return 0; } if (strcmp(argv[j], "-m") == 0 && j+1 < argc) mfile = argv[++j]; else if (strcmp(argv[j], "-c") == 0 && j+1 < argc) cfile = argv[++j]; else if (strcmp(argv[j], "-mex") == 0 && j+1 < argc) mexfunc = argv[++j]; else if (strcmp(argv[j], "-mb") == 0) mbatching_flag = 1; else if (strcmp(argv[j], "-list") == 0) listing_flag = 1; else if (strcmp(argv[j], "-catch") == 0) mw_generate_catch = true; else if (strcmp(argv[j], "-i8") == 0) mw_promote_int = 4; else if (strcmp(argv[j], "-c99complex") == 0) mw_use_c99_complex = true; else if (strcmp(argv[j], "-cppcomplex") == 0) mw_use_cpp_complex = true; else if (strcmp(argv[j], "-gpu") == 0) mw_use_gpu = true; } if (mw_use_c99_complex || mw_use_cpp_complex) { add_zscalar_type("dcomplex"); add_cscalar_type("fcomplex"); } /* Pre-scan: count input files before opening any output files */ int yyin_count = 0; for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "-m") == 0 || strcmp(argv[j], "-c") == 0 || strcmp(argv[j], "-mex") == 0) ++j; else if (strcmp(argv[j], "--help") == 0 || strcmp(argv[j], "-mb") == 0 || strcmp(argv[j], "-list") == 0 || strcmp(argv[j], "-catch") == 0 || strcmp(argv[j], "-i8") == 0 || strcmp(argv[j], "-c99complex") == 0 || strcmp(argv[j], "-cppcomplex") == 0 || strcmp(argv[j], "-gpu") == 0) ; else ++yyin_count; } if (yyin_count == 0) { fprintf(stderr, "%s", usage_string); return 0; } /* Now safe to open output files */ if (mfile) outfp = fopen(mfile, "w+"); if (cfile) outcfp = fopen(cfile, "w+"); for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "-m") == 0 || strcmp(argv[j], "-c") == 0 || strcmp(argv[j], "-mex") == 0) ++j; else if (strcmp(argv[j], "-mb") == 0 || strcmp(argv[j], "-list") == 0 || strcmp(argv[j], "-catch") == 0 || strcmp(argv[j], "-i8") == 0 || strcmp(argv[j], "-c99complex") == 0 || strcmp(argv[j], "-cppcomplex") == 0 || strcmp(argv[j], "-gpu") == 0) ; else { linenum = 1; type_errs = 0; yyin = fopen(argv[j], "r"); if (yyin) { current_ifname = argv[j]; if (outcfp && !emitted_mex_init) { print_mex_init(outcfp); emitted_mex_init = true; } err_flag += yyparse(); fclose(yyin); } else { fprintf(stderr, "Could not read %s\n", argv[j]); } if (type_errs) fprintf(stderr, "%s: %d type errors detected\n", argv[j], type_errs); err_flag += type_errs; } } } if (!err_flag && outcfp) print_mex_file(outcfp, funcs); destroy(funcs); destroy_inherits(); if (outfp) fclose(outfp); if (outcfp) fclose(outcfp); return err_flag; } zgimbutas-mwrap-25008ce/src/mwrap.y.in000066400000000000000000000277441515063637600177410ustar00rootroot00000000000000%{ /* * mwrap.y * Parser for mwrap. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include #include #include "mwrap-ast.h" extern "C" { int yylex(); int yywrap(); int yyerror(const char* s); } using std::string; bool mw_use_gpu = 0; // Use GPU? bool mw_generate_catch = false; // Catch C++ exceptions? bool mw_use_cpp_complex = false; // Use C++ complex types? bool mw_use_c99_complex = false; // Use C99 complex types? int mw_promote_int = 0; // Convert integer types to mwSize? int mw_use_int32_t = 0; // Use C99 int32_t? int mw_use_int64_t = 0; // Use C99 int64_t? int mw_use_uint32_t = 0; // Use C99 uint32_t? int mw_use_uint64_t = 0; // Use C99 uint64_t? int mw_use_ulong = 0; // Use unsigned long? int mw_use_uint = 0; // Use unsigned int? int mw_use_ushort = 0; // Use unsigned short? int mw_use_uchar = 0; // Use unsigned char? int listing_flag = 0; // Output filenames from @ commands? int mbatching_flag = 0; // Output on @ commands? int linenum = 0; // Lexer line number FILE* outfp = 0; // MATLAB output file FILE* outcfp = 0; // C output file static int type_errs = 0; // Number of typecheck errors static int func_id = 0; // Assign stub numbers static Func* funcs = 0; // AST - linked list of functions static Func* lastfunc = 0; // Last link in funcs list static const char* mexfunc = "mexfunction"; // Name of mex function static string current_ifname; // Current input file name #define MAX_INCLUDE_DEPTH 10 static string include_stack_names[MAX_INCLUDE_DEPTH]; extern int include_stack_ptr; extern "C" void set_include_name(const char* s) { include_stack_names[include_stack_ptr] = current_ifname; current_ifname = s; } extern "C" void get_include_name() { current_ifname = include_stack_names[include_stack_ptr].c_str(); } inline void add_func(Func* func) { static std::map func_lookup; if (!funcs) { funcs = func; lastfunc = func; return; } Func*& func_ptr = func_lookup[id_string(func)]; if (func_ptr) { func_ptr->same_next = func; } else { lastfunc->next = func; lastfunc = func; } func_ptr = func; } %} %union { char* string; struct Func* func; struct Var* var; struct TypeQual* qual; struct Expr* expr; struct InheritsDecl* inherits; char c; } %token NON_C_LINE %token NEW TYPEDEF CLASS FORTRAN %token ID %token NUMBER STRING %token INPUT OUTPUT INOUT %token CPU GPU %type func funcall %type var basevar args argsrest %type iospec %type devicespec %type quals aqual %type arrayspec exprs exprrest expr %type inheritslist inheritsrest @ERROR_VERBOSE@ %% statements: statement statements | ; statement: basevar '=' funcall { $3->ret = $1; $3->id = ++func_id; type_errs += typecheck($3, linenum); if (outfp) print_matlab_call(outfp, $3, mexfunc); add_func($3); } | funcall { $1->id = ++func_id; type_errs += typecheck($1, linenum); if (outfp) print_matlab_call(outfp, $1, mexfunc); add_func($1); } | tdef | classdef | NON_C_LINE | error ';' { yyerrok; } ; tdef: TYPEDEF ID ID ';' { if (strcmp($2, "numeric") == 0) { add_scalar_type($3); } else if (strcmp($2, "dcomplex") == 0) { add_zscalar_type($3); } else if (strcmp($2, "fcomplex") == 0) { add_cscalar_type($3); } else if (strcmp($2, "mxArray") == 0) { add_mxarray_type($3); } else { fprintf(stderr, "Unrecognized typespace: %s\n", $2); ++type_errs; } delete[] $2; delete[] $3; } ; classdef: CLASS ID ':' inheritslist ';' { add_inherits($2, $4); delete[] $2; destroy($4); } inheritslist: ID inheritsrest { $$ = new InheritsDecl($1, $2); } ; inheritsrest: ',' ID inheritsrest { $$ = new InheritsDecl($2, $3); } | { $$ = NULL; } ; funcall: func '(' args ')' ';' { $$ = $1; $$->args = $3; } ; args: var argsrest { $$ = $1; $$->next = $2; } | { $$ = NULL; } ; argsrest: ',' var argsrest {$$ = $2; $$->next = $3; } | { $$ = NULL; } ; basevar: ID ID { $$ = new Var('c', 'o', promote_int($1), NULL, $2); } basevar: ID quals ID { $$ = new Var('c', 'o', promote_int($1), $2, $3); } basevar: ID ID aqual { $$ = new Var('c', 'o', promote_int($1), $3, $2); } var: devicespec iospec ID ID { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals ID { $$ = new Var($1, $2, promote_int($3), $4, $5); } var: devicespec iospec ID ID aqual { $$ = new Var($1, $2, promote_int($3), $5, $4); } var: devicespec iospec ID NUMBER { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals NUMBER { $$ = new Var($1, $2, promote_int($3), $4, $5); } var: devicespec iospec ID STRING { $$ = new Var($1, $2, promote_int($3), NULL, $4); } var: devicespec iospec ID quals STRING { $$ = new Var($1, $2, promote_int($3), $4, $5); } devicespec: CPU { $$ = 'c'; } | GPU { $$ = 'g'; } | { $$ = 'c'; } ; iospec: INPUT { $$ = 'i'; } | OUTPUT { $$ = 'o'; } | INOUT { $$ = 'b'; } | { $$ = 'i'; } ; quals: '*' { $$ = new TypeQual('*', NULL); } | '&' { $$ = new TypeQual('&', NULL); } | aqual { $$ = $1; } ; aqual: arrayspec { $$ = new TypeQual('a', $1); } | arrayspec '&' { $$ = new TypeQual('r', $1); } ; arrayspec: '[' exprs ']' { $$ = $2; } ; exprs: expr exprrest { $$ = $1; $$->next = $2; } | { $$ = NULL; } exprrest: ',' expr exprrest { $$ = $2; $$->next = $3; } | { $$ = NULL; } expr: ID { $$ = new Expr($1); } | NUMBER { $$ = new Expr($1); } func: ID '-' '>' ID '.' ID { $$ = new Func($1, $4, $6, current_ifname, linenum); } | ID { $$ = new Func(NULL, NULL, $1, current_ifname, linenum); } | FORTRAN ID { $$ = new Func(NULL, NULL, $2, current_ifname, linenum); $$->fort = true; } | NEW ID { $$ = new Func(NULL, $2, mwrap_strdup("new"), current_ifname, linenum); } ; %% #include #include extern FILE* yyin; int yywrap() { return 1; } int yyerror(const char* s) { fprintf(stderr, "Parse error (%s:%d): %s\n", current_ifname.c_str(), linenum, s); return 0; } char* mwrap_strdup(const char* s) { char* result = new char[strlen(s)+1]; strcpy(result, s); return result; } const char* usage_string = "Usage: mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] infile1 ...\n" "Try 'mwrap --help' for more information.\n"; const char* help_string = "mwrap 1.3 - MEX file generator for MATLAB and Octave\n" "\n" "Syntax:\n" " mwrap [-mex outputmex] [-m output.m] [-c outputmex.c] [-mb] [-list]\n" " [-catch] [-i8] [-c99complex] [-cppcomplex] [-gpu] infile1 infile2 ...\n" "\n" " -mex outputmex -- specify the MATLAB mex function name\n" " -m output.m -- generate the MATLAB stub called output.m\n" " -c outputmex.c -- generate the C file outputmex.c\n" " -mb -- generate .m files specified with @ redirections\n" " -list -- list files specified with @ redirections\n" " -catch -- generate C++ exception handling code\n" " -i8 -- convert int, long, uint, ulong to int64_t, uint64_t\n" " -c99complex -- add support code for C99 complex types\n" " -cppcomplex -- add support code for C++ complex types\n" " -gpu -- add support code for MATLAB gpuArray\n" "\n"; int main(int argc, char** argv) { int j; int err_flag = 0; init_scalar_types(); if (argc == 1) { fprintf(stderr, "%s", help_string); return 0; } else { bool emitted_mex_init = false; const char* mfile = NULL; const char* cfile = NULL; for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "--help") == 0) { fprintf(stderr, "%s", help_string); return 0; } if (strcmp(argv[j], "-m") == 0 && j+1 < argc) mfile = argv[++j]; else if (strcmp(argv[j], "-c") == 0 && j+1 < argc) cfile = argv[++j]; else if (strcmp(argv[j], "-mex") == 0 && j+1 < argc) mexfunc = argv[++j]; else if (strcmp(argv[j], "-mb") == 0) mbatching_flag = 1; else if (strcmp(argv[j], "-list") == 0) listing_flag = 1; else if (strcmp(argv[j], "-catch") == 0) mw_generate_catch = true; else if (strcmp(argv[j], "-i8") == 0) mw_promote_int = 4; else if (strcmp(argv[j], "-c99complex") == 0) mw_use_c99_complex = true; else if (strcmp(argv[j], "-cppcomplex") == 0) mw_use_cpp_complex = true; else if (strcmp(argv[j], "-gpu") == 0) mw_use_gpu = true; } if (mw_use_c99_complex || mw_use_cpp_complex) { add_zscalar_type("dcomplex"); add_cscalar_type("fcomplex"); } /* Pre-scan: count input files before opening any output files */ int yyin_count = 0; for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "-m") == 0 || strcmp(argv[j], "-c") == 0 || strcmp(argv[j], "-mex") == 0) ++j; else if (strcmp(argv[j], "--help") == 0 || strcmp(argv[j], "-mb") == 0 || strcmp(argv[j], "-list") == 0 || strcmp(argv[j], "-catch") == 0 || strcmp(argv[j], "-i8") == 0 || strcmp(argv[j], "-c99complex") == 0 || strcmp(argv[j], "-cppcomplex") == 0 || strcmp(argv[j], "-gpu") == 0) ; else ++yyin_count; } if (yyin_count == 0) { fprintf(stderr, "%s", usage_string); return 0; } /* Now safe to open output files */ if (mfile) outfp = fopen(mfile, "w+"); if (cfile) outcfp = fopen(cfile, "w+"); for (j = 1; j < argc; ++j) { if (strcmp(argv[j], "-m") == 0 || strcmp(argv[j], "-c") == 0 || strcmp(argv[j], "-mex") == 0) ++j; else if (strcmp(argv[j], "-mb") == 0 || strcmp(argv[j], "-list") == 0 || strcmp(argv[j], "-catch") == 0 || strcmp(argv[j], "-i8") == 0 || strcmp(argv[j], "-c99complex") == 0 || strcmp(argv[j], "-cppcomplex") == 0 || strcmp(argv[j], "-gpu") == 0) ; else { linenum = 1; type_errs = 0; yyin = fopen(argv[j], "r"); if (yyin) { current_ifname = argv[j]; if (outcfp && !emitted_mex_init) { print_mex_init(outcfp); emitted_mex_init = true; } err_flag += yyparse(); fclose(yyin); } else { fprintf(stderr, "Could not read %s\n", argv[j]); } if (type_errs) fprintf(stderr, "%s: %d type errors detected\n", argv[j], type_errs); err_flag += type_errs; } } } if (!err_flag && outcfp) print_mex_file(outcfp, funcs); destroy(funcs); destroy_inherits(); if (outfp) fclose(outfp); if (outcfp) fclose(outcfp); return err_flag; } zgimbutas-mwrap-25008ce/src/stringify.c000066400000000000000000000017311515063637600201620ustar00rootroot00000000000000/* * stringify.c * Turns input from stdin into a C string definition written on * stdout. Adds quotes, newline characters, and backslashes as * needed. * * Copyright (c) 2007 David Bindel * See the file COPYING for copying permissions */ #include #include void stringify(const char* name) { char line[512]; char* p; printf("/*\n" " * Auto-generated by stringify\n" " */\n\n"); printf("const char* %s =", name); while (fgets(line, sizeof(line), stdin)) { printf("\n \""); for (p = line; *p; ++p) { if (*p == '"' || *p == '\\') putc('\\', stdout); if (*p != '\n' && *p != '\r') putc(*p, stdout); } printf("\\n\""); } printf(";\n\n"); } int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "String name required\n"); exit(-1); } stringify(argv[1]); return 0; } zgimbutas-mwrap-25008ce/testing/000077500000000000000000000000001515063637600166645ustar00rootroot00000000000000zgimbutas-mwrap-25008ce/testing/CMakeLists.txt000066400000000000000000000232001515063637600214210ustar00rootroot00000000000000set(_mwrap_log_test_driver "${CMAKE_CURRENT_BINARY_DIR}/mwrap_log_test.cmake") set(_mwrap_log_test_script [[ if(NOT DEFINED MWRAP_EXECUTABLE) message(FATAL_ERROR "MWRAP_EXECUTABLE is required") endif() foreach(var OUTPUT_FILE REFERENCE_FILE) if(NOT DEFINED ${var}) message(FATAL_ERROR "${var} is required") endif() endforeach() if(NOT DEFINED TEST_NAME) set(TEST_NAME "mwrap_test") endif() set(_args) if(DEFINED ARGC AND ARGC GREATER 0) math(EXPR _last_index "${ARGC} - 1") foreach(_arg_index RANGE 0 ${_last_index}) set(_var_name ARG${_arg_index}) if(NOT DEFINED ${_var_name}) message(FATAL_ERROR "${TEST_NAME}: missing argument ${_var_name}") endif() list(APPEND _args "${${_var_name}}") endforeach() endif() set(_working_directory "${CMAKE_CURRENT_LIST_DIR}") if(DEFINED WORKING_DIRECTORY) set(_working_directory "${WORKING_DIRECTORY}") endif() file(MAKE_DIRECTORY "${_working_directory}") set(stdout_file "${OUTPUT_FILE}.stdout") execute_process( COMMAND ${MWRAP_EXECUTABLE} ${_args} RESULT_VARIABLE run_result OUTPUT_FILE "${stdout_file}" ERROR_FILE "${OUTPUT_FILE}" WORKING_DIRECTORY "${_working_directory}" ) set(expect_nonzero FALSE) if(DEFINED EXPECT_NONZERO AND EXPECT_NONZERO) set(expect_nonzero TRUE) endif() if(expect_nonzero AND run_result EQUAL 0) message(FATAL_ERROR "${TEST_NAME}: expected failure but command succeeded") endif() if(NOT expect_nonzero AND NOT run_result EQUAL 0) message(FATAL_ERROR "${TEST_NAME}: command failed with exit code ${run_result}") endif() if(NOT EXISTS "${REFERENCE_FILE}") message(FATAL_ERROR "${TEST_NAME}: reference file '${REFERENCE_FILE}' not found") endif() file(READ "${OUTPUT_FILE}" output_contents) string(REPLACE "end of file" "$end" normalized_output "${output_contents}") if(NOT normalized_output STREQUAL output_contents) file(WRITE "${OUTPUT_FILE}" "${normalized_output}") endif() execute_process( COMMAND ${CMAKE_COMMAND} -E compare_files "${OUTPUT_FILE}" "${REFERENCE_FILE}" RESULT_VARIABLE diff_result ) if(NOT diff_result EQUAL 0) file(READ "${OUTPUT_FILE}" normalized_output) message(FATAL_ERROR "${TEST_NAME}: output does not match reference.\n--- Actual stderr ---\n${normalized_output}") endif() ]]) file(WRITE "${_mwrap_log_test_driver}" "${_mwrap_log_test_script}") function(_mwrap_add_log_test name) set(options EXPECT_NONZERO) set(oneValueArgs REFERENCE) set(multiValueArgs ARGS) cmake_parse_arguments(_MWRAP_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT _MWRAP_TEST_REFERENCE) message(FATAL_ERROR "_mwrap_add_log_test requires REFERENCE for test '${name}'") endif() set(log_file "${CMAKE_CURRENT_BINARY_DIR}/${name}.log") list(LENGTH _MWRAP_TEST_ARGS arg_count) set(arg_definitions -DARGC=${arg_count}) if(arg_count GREATER 0) math(EXPR arg_max "${arg_count} - 1") foreach(arg_index RANGE 0 ${arg_max}) list(GET _MWRAP_TEST_ARGS ${arg_index} arg_value) list(APPEND arg_definitions -DARG${arg_index}=${arg_value}) endforeach() endif() add_test( NAME ${name} COMMAND ${CMAKE_COMMAND} -DMWRAP_EXECUTABLE=$ -DOUTPUT_FILE=${log_file} -DREFERENCE_FILE=${_MWRAP_TEST_REFERENCE} -DEXPECT_NONZERO=${_MWRAP_TEST_EXPECT_NONZERO} -DTEST_NAME=${name} -DWORKING_DIRECTORY=${CMAKE_CURRENT_SOURCE_DIR} ${arg_definitions} -P ${_mwrap_log_test_driver} ) set_tests_properties(${name} PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endfunction() _mwrap_add_log_test( mwrap.test_syntax EXPECT_NONZERO REFERENCE ${CMAKE_CURRENT_SOURCE_DIR}/test_syntax.ref ARGS -cppcomplex test_syntax.mw ) _mwrap_add_log_test( mwrap.test_typecheck EXPECT_NONZERO REFERENCE ${CMAKE_CURRENT_SOURCE_DIR}/test_typecheck.ref ARGS -cppcomplex test_typecheck.mw ) if(MWRAP_COMPILE_MEX AND MWRAP_MEX_BACKENDS) include(${CMAKE_SOURCE_DIR}/cmake/MwrapAddMex.cmake) set(_mwrap_testing_source_dir "${CMAKE_CURRENT_SOURCE_DIR}") set(_mwrap_testing_binary_dir "${CMAKE_CURRENT_BINARY_DIR}/octave") file(MAKE_DIRECTORY "${_mwrap_testing_binary_dir}") configure_file( "${_mwrap_testing_source_dir}/test_include2.mw" "${_mwrap_testing_binary_dir}/test_include2.mw" COPYONLY ) set(_mwrap_testing_generators) mwrap_add_mex(test_transfers WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_transfersmex CC_FILENAME test_transfersmex.cc M_FILENAME test_transfers.m MW_FILES "${_mwrap_testing_source_dir}/test_transfers.mw" ) list(APPEND _mwrap_testing_generators test_transfers) mwrap_add_mex(test_cpp_complex WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_cpp_complexmex CC_FILENAME test_cpp_complexmex.cc M_FILENAME test_cpp_complex.m MW_FILES "${_mwrap_testing_source_dir}/test_cpp_complex.mw" MWRAP_FLAGS -cppcomplex ) list(APPEND _mwrap_testing_generators test_cpp_complex) mwrap_add_mex(test_c99_complex WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_c99_complexmex CC_FILENAME test_c99_complexmex.c M_FILENAME test_c99_complex.m MW_FILES "${_mwrap_testing_source_dir}/test_c99_complex.mw" MWRAP_FLAGS -c99complex ) list(APPEND _mwrap_testing_generators test_c99_complex) mwrap_add_mex(test_catch WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_catchmex CC_FILENAME test_catchmex.cc M_FILENAME test_catch.m MW_FILES "${_mwrap_testing_source_dir}/test_catch.mw" MWRAP_FLAGS -catch ) list(APPEND _mwrap_testing_generators test_catch) mwrap_add_mex(test_fortran1 WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_fortran1mex CC_FILENAME test_fortran1mex.cc M_FILENAME test_fortran1.m MW_FILES "${_mwrap_testing_source_dir}/test_fortran1.mw" ) list(APPEND _mwrap_testing_generators test_fortran1) mwrap_add_mex(test_fortran2 WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_fortran2mex CC_FILENAME test_fortran2mex.c M_FILENAME test_fortran2.m MW_FILES "${_mwrap_testing_source_dir}/test_fortran2.mw" ) list(APPEND _mwrap_testing_generators test_fortran2) mwrap_add_mex(test_include WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_includemex CC_FILENAME test_includemex.cc M_FILENAME test_include.m MW_FILES "${_mwrap_testing_source_dir}/test_include.mw" ) list(APPEND _mwrap_testing_generators test_include) mwrap_add_mex(test_single_cpp WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_singlemex CC_FILENAME test_singlemex.cc MW_FILES "${_mwrap_testing_source_dir}/test_single.mw" MWRAP_FLAGS -cppcomplex -mb ) list(APPEND _mwrap_testing_generators test_single_cpp) mwrap_add_mex(test_char_cpp WORK_DIR "${_mwrap_testing_binary_dir}" MEX_NAME test_charmex CC_FILENAME test_charmex.cc MW_FILES "${_mwrap_testing_source_dir}/test_char.mw" MWRAP_FLAGS -cppcomplex -mb ) list(APPEND _mwrap_testing_generators test_char_cpp) set(_mwrap_testing_mex_targets) foreach(_mwrap_generator IN LISTS _mwrap_testing_generators) _mwrap_compile_mex(${_mwrap_generator} OUTPUT_VAR _mwrap_generator_mex_targets) if(_mwrap_generator_mex_targets) list(APPEND _mwrap_testing_mex_targets ${_mwrap_generator_mex_targets}) endif() endforeach() if(_mwrap_testing_mex_targets) list(REMOVE_DUPLICATES _mwrap_testing_mex_targets) endif() set(_mwrap_redirect_output "${_mwrap_testing_binary_dir}/test_redirect.m") add_custom_command( OUTPUT "${_mwrap_redirect_output}" COMMAND ${CMAKE_COMMAND} -E make_directory "${_mwrap_testing_binary_dir}" COMMAND $ -mb "${_mwrap_testing_source_dir}/test_redirect.mw" DEPENDS mwrap "${_mwrap_testing_source_dir}/test_redirect.mw" WORKING_DIRECTORY "${_mwrap_testing_binary_dir}" COMMENT "Generating test_redirect.m with mwrap" VERBATIM ) add_custom_target(mwrap_testing_redirect DEPENDS "${_mwrap_redirect_output}") set_property(TARGET mwrap_testing_redirect PROPERTY FOLDER "tests") set(_mwrap_testing_artifacts ${_mwrap_testing_mex_targets} mwrap_testing_redirect) list(REMOVE_DUPLICATES _mwrap_testing_artifacts) if(_mwrap_testing_artifacts) add_custom_target(mwrap_testing_mex DEPENDS ${_mwrap_testing_artifacts}) set_property(TARGET mwrap_testing_mex PROPERTY FOLDER "tests") endif() if("OCTAVE" IN_LIST MWRAP_MEX_BACKENDS) if(MWRAP_OCTAVE_EXECUTABLE) string(REPLACE "'" "''" _mwrap_octave_binary_dir_escaped "${_mwrap_testing_binary_dir}") string(REPLACE "'" "''" _mwrap_octave_source_dir_escaped "${_mwrap_testing_source_dir}") set(_mwrap_octave_eval "addpath('${_mwrap_octave_binary_dir_escaped}'); addpath('${_mwrap_octave_source_dir_escaped}'); test_all; exit;") add_test(NAME mwrap.octave.test_all COMMAND ${MWRAP_OCTAVE_EXECUTABLE} --quiet --no-init-file --eval "${_mwrap_octave_eval}") set_tests_properties(mwrap.octave.test_all PROPERTIES WORKING_DIRECTORY "${_mwrap_testing_binary_dir}") else() message(WARNING "Octave backend enabled but no Octave interpreter was found; skipping Octave runtime tests.") endif() endif() endif() if(CMAKE_CONFIGURATION_TYPES) add_custom_target(mwrap_tests COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $ WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) else() add_custom_target(mwrap_tests COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) endif() add_dependencies(mwrap_tests mwrap) if(TARGET mwrap_testing_mex) add_dependencies(mwrap_tests mwrap_testing_mex) endif() set_property(TARGET mwrap_tests PROPERTY FOLDER "tests") zgimbutas-mwrap-25008ce/testing/Makefile000066400000000000000000000075011515063637600203270ustar00rootroot00000000000000include ../make.inc MWRAP = ../mwrap all: test_transfers test_cpp_complex $(TESTC99COMPLEX) test_syntax \ test_typecheck test_catch test_fortran1 test_fortran2 \ test_redirect test_include test_single_cpp test_char_cpp # run the tests... octave-cli --no-init-file --quiet test_all.m test_transfers: $(MWRAP) -mex test_transfersmex \ -c test_transfersmex.cc \ -m test_transfers.m test_transfers.mw $(MEX) test_transfersmex.cc test_cpp_complex: $(MWRAP) -cppcomplex \ -mex test_cpp_complexmex \ -c test_cpp_complexmex.cc \ -m test_cpp_complex.m test_cpp_complex.mw $(MEX) test_cpp_complexmex.cc test_c99_complex: $(MWRAP) -c99complex \ -mex test_c99_complexmex \ -c test_c99_complexmex.c \ -m test_c99_complex.m test_c99_complex.mw $(MEX) test_c99_complexmex.c # the following two are designed to create mwrap errors, and compared against # log files. For now, since they would break the make process, the minus signs # prevent them from being made. test_syntax: - $(MWRAP) -cppcomplex test_syntax.mw 2> test_syntax.log - diff test_syntax.log test_syntax.ref test_typecheck: - $(MWRAP) -cppcomplex test_typecheck.mw 2> test_typecheck.log diff test_typecheck.log test_typecheck.ref test_catch: $(MWRAP) -mex test_catchmex -catch \ -c test_catchmex.cc \ -m test_catch.m \ test_catch.mw $(MEX) test_catchmex.cc test_fortran1: $(MWRAP) -mex test_fortran1mex \ -c test_fortran1mex.cc \ -m test_fortran1.m \ test_fortran1.mw $(MEX) test_fortran1mex.cc test_fortran2: $(MWRAP) -mex test_fortran2mex \ -c test_fortran2mex.c \ -m test_fortran2.m \ test_fortran2.mw $(MEX) test_fortran2mex.c test_redirect: $(MWRAP) -mb test_redirect.mw test_include: $(MWRAP) -mex test_includemex\ -c test_includemex.cc \ -m test_include.m test_include.mw $(MEX) test_includemex.cc # these two are tested by test_char.m ... test_char_cpp: $(MWRAP) -cppcomplex -mex test_charmex \ -c test_charmex.cc \ -mb test_char.mw $(MEX) test_charmex.cc test_char_c99: $(MWRAP) -mex test_charmex \ -c test_charmex.c \ -mb test_char.mw $(MEX) test_charmex.c # these last two are tested by test_single.m ... test_single_cpp: $(MWRAP) -cppcomplex -mex test_singlemex \ -c test_singlemex.cc \ -mb test_single.mw $(MEX) test_singlemex.cc test_single_c99: $(MWRAP) -c99complex -mex test_singlemex \ -c test_singlemex.c \ -mb test_single.mw $(MEX) test_singlemex.c test_gpu: $(MWRAP) -gpu -list -cppcomplex -mb -mex test_gpu -c test_gpu.cu test_gpu.mw test_gpu_complex: $(MWRAP) -gpu -list -cppcomplex -mb -mex test_gpu_complex -c test_gpu_complex.cu test_gpu_complex.mw test_gpu_int32: $(MWRAP) -gpu -list -cppcomplex -mb -mex test_gpu_int32 -c test_gpu_int32.cu test_gpu_int32.mw # GPU tests: requires CUDA toolkit and GPU device # Run mwrap targets first (test_gpu, test_gpu_complex, test_gpu_int32), # then run this target from MATLAB/Octave with GPU support. test_all_gpu: test_gpu test_gpu_complex test_gpu_int32 matlab -batch "test_all_gpu" test_cpu: $(MWRAP) -list -cppcomplex -mb -mex test_cpu -c test_cpu.cc test_cpu.mw test_cpu_int32: $(MWRAP) -list -cppcomplex -mb -mex test_cpu_int32 -c test_cpu_int32.cc test_cpu_int32.mw clean: rm -f *~ *.mex* *.o* test_typecheck.log test_syntax.log rm -f test_fortran1.m test_fortran2.m test_transfers.m test_catch.m rm -f test_fortran1mex.cc test_fortran2mex.c rm -f test_cpp_complex.m test_c99_complex.m rm -f test_transfersmex.cc test_catchmex.cc test_fortranmex.cc rm -f test_cpp_complexmex.cc test_c99_complexmex.c rm -f test_redirect.m test_redirect1.m rm -f test_singlemex.c test_singlemex.cc rm -f add.m addf.m addz.m addc.m rm -f arradd.m arraddf.m arraddz.m arraddc.m rm -f test_include.m test_includemex.cc rm -f test_charmex.c test_charmex.cc rm -f addchar.m arraddchar.m rm -f test_cpu.cc timestwo_cpu.m rm -f test_cpu_int32.cc timestwo_cpu_int32.m zgimbutas-mwrap-25008ce/testing/run_matlab_tests.m000066400000000000000000000077221515063637600224200ustar00rootroot00000000000000function run_matlab_tests(build_dir, source_dir) % run_matlab_tests Run all MATLAB tests for mwrap. % % run_matlab_tests(BUILD_DIR, SOURCE_DIR) runs the example and unit tests % using MEX binaries from BUILD_DIR and test scripts from SOURCE_DIR. % % This script is designed for use with matlab-actions/run-command in CI. % It exits with a non-zero status on failure. if nargin < 2 error('Usage: run_matlab_tests(build_dir, source_dir)'); end n_pass = 0; n_fail = 0; failures = {}; %% -- Example tests ---------------------------------------------------------- example_tests = { % {test_name, mex_dir, script_dirs, script_name, needs_cd} {'eventq_plain', fullfile(build_dir, 'example', 'eventq_plain'), ... {fullfile(source_dir, 'example', 'eventq')}, 'testq_plain', false} {'eventq_handle', fullfile(build_dir, 'example', 'eventq_handle'), ... {fullfile(source_dir, 'example', 'eventq')}, 'testq_handle', false} {'eventq_class', fullfile(build_dir, 'example', 'eventq_class'), ... {fullfile(source_dir, 'example', 'eventq')}, 'testq_class', false} {'eventq2', fullfile(build_dir, 'example', 'eventq2'), ... {fullfile(source_dir, 'example', 'eventq2')}, 'testq2', false} {'zlib', fullfile(build_dir, 'example', 'zlib'), ... {fullfile(source_dir, 'example', 'zlib')}, 'testgz', true} {'fem_simple', fullfile(build_dir, 'example', 'fem_interface'), ... {fullfile(source_dir, 'example', 'fem')}, 'test_simple', true} {'fem_patch', fullfile(build_dir, 'example', 'fem_interface'), ... {fullfile(source_dir, 'example', 'fem')}, 'test_patch', true} {'fem_assembler', fullfile(build_dir, 'example', 'fem_interface'), ... {fullfile(source_dir, 'example', 'fem')}, 'test_assembler', true} }; for i = 1:numel(example_tests) t = example_tests{i}; test_name = t{1}; mex_dir = t{2}; script_dirs = t{3}; script_name = t{4}; needs_cd = t{5}; fprintf('\n=== Running example test: %s ===\n', test_name); saved_path = path; saved_dir = pwd; try addpath(mex_dir); for j = 1:numel(script_dirs) addpath(script_dirs{j}); end if needs_cd cd(mex_dir); end feval(script_name); fprintf('PASS: %s\n', test_name); n_pass = n_pass + 1; catch ME fprintf('FAIL: %s -- %s\n', test_name, ME.message); n_fail = n_fail + 1; failures{end+1} = test_name; %#ok end cd(saved_dir); path(saved_path); end %% -- Unit tests (testing/) -------------------------------------------------- testing_mex_dir = fullfile(build_dir, 'testing'); testing_gen_dir = fullfile(build_dir, 'testing', 'octave'); testing_src_dir = fullfile(source_dir, 'testing'); unit_tests = { 'test_transfers' 'test_cpp_complex' 'test_c99_complex' 'test_catch' 'test_fortran1' 'test_fortran2' 'test_redirect' 'test_include' 'test_single' 'test_char' }; for i = 1:numel(unit_tests) test_name = unit_tests{i}; fprintf('\n=== Running unit test: %s ===\n', test_name); saved_path = path; saved_dir = pwd; try addpath(testing_mex_dir); addpath(testing_gen_dir); addpath(testing_src_dir); feval(test_name); fprintf('PASS: %s\n', test_name); n_pass = n_pass + 1; catch ME fprintf('FAIL: %s -- %s\n', test_name, ME.message); n_fail = n_fail + 1; failures{end+1} = test_name; %#ok end cd(saved_dir); path(saved_path); end %% -- Summary ----------------------------------------------------------------- fprintf('\n============================\n'); fprintf('Results: %d passed, %d failed\n', n_pass, n_fail); if n_fail > 0 fprintf('Failures:\n'); for i = 1:numel(failures) fprintf(' - %s\n', failures{i}); end error('mwrap:testFailure', '%d test(s) failed.', n_fail); end fprintf('All tests passed.\n'); end zgimbutas-mwrap-25008ce/testing/test_all.m000066400000000000000000000002671515063637600206560ustar00rootroot00000000000000test_transfers; test_cpp_complex; if exist('test_c99_complex.m'), test_c99_complex; end test_catch; test_fortran1; test_fortran2; test_redirect; test_include; test_single; test_char; zgimbutas-mwrap-25008ce/testing/test_all_gpu.m000066400000000000000000000003611515063637600215240ustar00rootroot00000000000000% test_all_gpu - Run all GPU tests. % Requires: CUDA toolkit, mexcuda, GPU device. % Run mwrap first for each test (see individual test files for commands). test_gpu; test_gpu_complex; test_gpu_int32; fprintf('\nAll GPU tests PASSED.\n'); zgimbutas-mwrap-25008ce/testing/test_c99_complex.mw000066400000000000000000000011201515063637600224150ustar00rootroot00000000000000function test_c99_complex; $ #include $ $ _Complex double zsum(_Complex double* zarray, int n) { $ int i; $ _Complex double sum = 0; $ for (i = 0; i < n; ++i) sum += zarray[i]; $ return sum; $ } zarray = rand(10,1) + 1i*rand(10,1); n = length(zarray); # dcomplex result = zsum(dcomplex[] zarray, int n); tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'C++ complex support'); # dcomplex cresult = conj(dcomplex result); tassert(conj(result) == cresult, 'C++ complex support (2)'); function tassert(pred, msg) if ~pred, fprintf('Failure: %s\n', msg); end zgimbutas-mwrap-25008ce/testing/test_c99_complexmex.c000066400000000000000000001015201515063637600227330ustar00rootroot00000000000000/* --------------------------------------------------- */ /* Automatically generated by mwrap */ /* --------------------------------------------------- */ /* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif #include typedef _Complex double dcomplex; #define real_dcomplex(z) creal(z) #define imag_dcomplex(z) cimag(z) #define setz_dcomplex(z,r,i) *z = r + i*_Complex_I typedef _Complex float fcomplex; #define real_fcomplex(z) crealf(z) #define imag_fcomplex(z) cimagf(z) #define setz_fcomplex(z,r,i) *z = r + i*_Complex_I #include _Complex double zsum(_Complex double* zarray, int n) { int i; _Complex double sum = 0; for (i = 0; i < n; ++i) sum += zarray[i]; return sum; } /* Array copier definitions */ mxWrapGetArrayDef(mxWrapGetArray_bool, bool) mxWrapCopyDef (mxWrapCopy_bool, bool) mxWrapReturnDef (mxWrapReturn_bool, bool) mxWrapGetArrayDef_single(mxWrapGetArray_single_bool, bool) mxWrapCopyDef_single (mxWrapCopy_single_bool, bool) mxWrapReturnDef_single (mxWrapReturn_single_bool, bool) mxWrapGetArrayDef(mxWrapGetArray_char, char) mxWrapCopyDef (mxWrapCopy_char, char) mxWrapReturnDef (mxWrapReturn_char, char) mxWrapGetArrayDef_single(mxWrapGetArray_single_char, char) mxWrapCopyDef_single (mxWrapCopy_single_char, char) mxWrapReturnDef_single (mxWrapReturn_single_char, char) mxWrapGetArrayDef(mxWrapGetArray_double, double) mxWrapCopyDef (mxWrapCopy_double, double) mxWrapReturnDef (mxWrapReturn_double, double) mxWrapGetArrayDef_single(mxWrapGetArray_single_double, double) mxWrapCopyDef_single (mxWrapCopy_single_double, double) mxWrapReturnDef_single (mxWrapReturn_single_double, double) mxWrapGetArrayDef(mxWrapGetArray_float, float) mxWrapCopyDef (mxWrapCopy_float, float) mxWrapReturnDef (mxWrapReturn_float, float) mxWrapGetArrayDef_single(mxWrapGetArray_single_float, float) mxWrapCopyDef_single (mxWrapCopy_single_float, float) mxWrapReturnDef_single (mxWrapReturn_single_float, float) mxWrapGetArrayDef(mxWrapGetArray_int, int) mxWrapCopyDef (mxWrapCopy_int, int) mxWrapReturnDef (mxWrapReturn_int, int) mxWrapGetArrayDef_single(mxWrapGetArray_single_int, int) mxWrapCopyDef_single (mxWrapCopy_single_int, int) mxWrapReturnDef_single (mxWrapReturn_single_int, int) mxWrapGetArrayDef(mxWrapGetArray_long, long) mxWrapCopyDef (mxWrapCopy_long, long) mxWrapReturnDef (mxWrapReturn_long, long) mxWrapGetArrayDef_single(mxWrapGetArray_single_long, long) mxWrapCopyDef_single (mxWrapCopy_single_long, long) mxWrapReturnDef_single (mxWrapReturn_single_long, long) mxWrapGetArrayDef(mxWrapGetArray_ptrdiff_t, ptrdiff_t) mxWrapCopyDef (mxWrapCopy_ptrdiff_t, ptrdiff_t) mxWrapReturnDef (mxWrapReturn_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_ptrdiff_t, ptrdiff_t) mxWrapCopyDef_single (mxWrapCopy_single_ptrdiff_t, ptrdiff_t) mxWrapReturnDef_single (mxWrapReturn_single_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef(mxWrapGetArray_short, short) mxWrapCopyDef (mxWrapCopy_short, short) mxWrapReturnDef (mxWrapReturn_short, short) mxWrapGetArrayDef_single(mxWrapGetArray_single_short, short) mxWrapCopyDef_single (mxWrapCopy_single_short, short) mxWrapReturnDef_single (mxWrapReturn_single_short, short) mxWrapGetArrayDef(mxWrapGetArray_size_t, size_t) mxWrapCopyDef (mxWrapCopy_size_t, size_t) mxWrapReturnDef (mxWrapReturn_size_t, size_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_size_t, size_t) mxWrapCopyDef_single (mxWrapCopy_single_size_t, size_t) mxWrapReturnDef_single (mxWrapReturn_single_size_t, size_t) mxWrapGetScalarZDef(mxWrapGetScalar_fcomplex, fcomplex, float, setz_fcomplex) mxWrapGetArrayZDef (mxWrapGetArray_fcomplex, fcomplex, float, setz_fcomplex) mxWrapCopyZDef (mxWrapCopy_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapReturnZDef (mxWrapReturn_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapGetScalarZDef_single(mxWrapGetScalar_single_fcomplex, fcomplex, float, setz_fcomplex) mxWrapGetArrayZDef_single (mxWrapGetArray_single_fcomplex, fcomplex, float, setz_fcomplex) mxWrapCopyZDef_single (mxWrapCopy_single_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapReturnZDef_single (mxWrapReturn_single_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapGetScalarZDef(mxWrapGetScalar_dcomplex, dcomplex, double, setz_dcomplex) mxWrapGetArrayZDef (mxWrapGetArray_dcomplex, dcomplex, double, setz_dcomplex) mxWrapCopyZDef (mxWrapCopy_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapReturnZDef (mxWrapReturn_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapGetScalarZDef_single(mxWrapGetScalar_single_dcomplex, dcomplex, double, setz_dcomplex) mxWrapGetArrayZDef_single (mxWrapGetArray_single_dcomplex, dcomplex, double, setz_dcomplex) mxWrapCopyZDef_single (mxWrapCopy_single_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapReturnZDef_single (mxWrapReturn_single_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) /* ---- test_c99_complex.mw: 14 ---- * dcomplex result = zsum(dcomplex[] zarray, int n); */ static const char* stubids1_ = "c o dcomplex = zsum(c i dcomplex[], c i int)"; void mexStub1(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; dcomplex* in0_ =0; /* zarray */ int in1_; /* n */ dcomplex out0_; /* result */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = mxWrapGetArray_dcomplex(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (int) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[1]++; out0_ = zsum(in0_, in1_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_dcomplex(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_dcomplex(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_dcomplex(out0_); *mxGetPi(plhs[0]) = imag_dcomplex(out0_); #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_c99_complex.mw: 16 ---- * dcomplex cresult = conj(dcomplex result); */ static const char* stubids2_ = "c o dcomplex = conj(c i dcomplex)"; void mexStub2(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; dcomplex in0_; /* result */ dcomplex out0_; /* cresult */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_dcomplex(&in0_, prhs[0]); if (mexprofrecord_) mexprofrecord_[2]++; out0_ = conj(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_dcomplex(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_dcomplex(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_dcomplex(out0_); *mxGetPi(plhs[0]) = imag_dcomplex(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]); static mwStubFunc_t mwStubs_[] = { NULL, mexStub1, mexStub2 }; static int mwNumStubs_ = 2; /* ---- */ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { if (nrhs == 0) { mexPrintf("Mex function installed\n"); return; } /* Fast path: integer stub ID */ if (!mxIsChar(prhs[0])) { int stub_id = (int) mxGetScalar(prhs[0]); if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids2_) == 0) mexStub2(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(3 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 3 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_c99_complex.mw:14\n", mexprofrecord_[1]); mexPrintf("%d calls to test_c99_complex.mw:16\n", mexprofrecord_[2]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_c99_complex.mw:14\n", mexprofrecord_[1]); fprintf(logfp, "%d calls to test_c99_complex.mw:16\n", mexprofrecord_[2]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_catch.mw000066400000000000000000000003021515063637600213450ustar00rootroot00000000000000function test_catch $ void toss() $ { $ throw("Cookies"); $ } try # toss(); disp('Failed to properly catch exception'); catch fprintf('Correctly caught message: %s\n', lasterr); end zgimbutas-mwrap-25008ce/testing/test_catchmex.cc000066400000000000000000000703771515063637600220440ustar00rootroot00000000000000/* --------------------------------------------------- */ /* Automatically generated by mwrap */ /* --------------------------------------------------- */ /* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif void toss() { throw("Cookies"); } /* Array copier definitions */ mxWrapGetArrayDef(mxWrapGetArray_bool, bool) mxWrapCopyDef (mxWrapCopy_bool, bool) mxWrapReturnDef (mxWrapReturn_bool, bool) mxWrapGetArrayDef_single(mxWrapGetArray_single_bool, bool) mxWrapCopyDef_single (mxWrapCopy_single_bool, bool) mxWrapReturnDef_single (mxWrapReturn_single_bool, bool) mxWrapGetArrayDef(mxWrapGetArray_char, char) mxWrapCopyDef (mxWrapCopy_char, char) mxWrapReturnDef (mxWrapReturn_char, char) mxWrapGetArrayDef_single(mxWrapGetArray_single_char, char) mxWrapCopyDef_single (mxWrapCopy_single_char, char) mxWrapReturnDef_single (mxWrapReturn_single_char, char) mxWrapGetArrayDef(mxWrapGetArray_double, double) mxWrapCopyDef (mxWrapCopy_double, double) mxWrapReturnDef (mxWrapReturn_double, double) mxWrapGetArrayDef_single(mxWrapGetArray_single_double, double) mxWrapCopyDef_single (mxWrapCopy_single_double, double) mxWrapReturnDef_single (mxWrapReturn_single_double, double) mxWrapGetArrayDef(mxWrapGetArray_float, float) mxWrapCopyDef (mxWrapCopy_float, float) mxWrapReturnDef (mxWrapReturn_float, float) mxWrapGetArrayDef_single(mxWrapGetArray_single_float, float) mxWrapCopyDef_single (mxWrapCopy_single_float, float) mxWrapReturnDef_single (mxWrapReturn_single_float, float) mxWrapGetArrayDef(mxWrapGetArray_int, int) mxWrapCopyDef (mxWrapCopy_int, int) mxWrapReturnDef (mxWrapReturn_int, int) mxWrapGetArrayDef_single(mxWrapGetArray_single_int, int) mxWrapCopyDef_single (mxWrapCopy_single_int, int) mxWrapReturnDef_single (mxWrapReturn_single_int, int) mxWrapGetArrayDef(mxWrapGetArray_long, long) mxWrapCopyDef (mxWrapCopy_long, long) mxWrapReturnDef (mxWrapReturn_long, long) mxWrapGetArrayDef_single(mxWrapGetArray_single_long, long) mxWrapCopyDef_single (mxWrapCopy_single_long, long) mxWrapReturnDef_single (mxWrapReturn_single_long, long) mxWrapGetArrayDef(mxWrapGetArray_ptrdiff_t, ptrdiff_t) mxWrapCopyDef (mxWrapCopy_ptrdiff_t, ptrdiff_t) mxWrapReturnDef (mxWrapReturn_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_ptrdiff_t, ptrdiff_t) mxWrapCopyDef_single (mxWrapCopy_single_ptrdiff_t, ptrdiff_t) mxWrapReturnDef_single (mxWrapReturn_single_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef(mxWrapGetArray_short, short) mxWrapCopyDef (mxWrapCopy_short, short) mxWrapReturnDef (mxWrapReturn_short, short) mxWrapGetArrayDef_single(mxWrapGetArray_single_short, short) mxWrapCopyDef_single (mxWrapCopy_single_short, short) mxWrapReturnDef_single (mxWrapReturn_single_short, short) mxWrapGetArrayDef(mxWrapGetArray_size_t, size_t) mxWrapCopyDef (mxWrapCopy_size_t, size_t) mxWrapReturnDef (mxWrapReturn_size_t, size_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_size_t, size_t) mxWrapCopyDef_single (mxWrapCopy_single_size_t, size_t) mxWrapReturnDef_single (mxWrapReturn_single_size_t, size_t) /* ---- test_catch.mw: 9 ---- * toss(); */ static const char* stubids1_ = "toss()"; void mexStub1(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[1]++; try { toss(); } catch(...) { mw_err_txt_ = "Caught C++ exception from toss"; } if (mw_err_txt_) goto mw_err_label; mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]); static mwStubFunc_t mwStubs_[] = { NULL, mexStub1 }; static int mwNumStubs_ = 1; /* ---- */ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { if (nrhs == 0) { mexPrintf("Mex function installed\n"); return; } /* Fast path: integer stub ID */ if (!mxIsChar(prhs[0])) { int stub_id = (int) mxGetScalar(prhs[0]); if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(2 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 2 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_catch.mw:9\n", mexprofrecord_[1]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_catch.mw:9\n", mexprofrecord_[1]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_char.m000066400000000000000000000020631515063637600210170ustar00rootroot00000000000000function test_char % pass-fail test of the char- args and arrays. % must do either make test_char_cpp or make test_char_c99 first. % based on test_single.m, Barnett & Gimbutas 7/5/20-7/20/20. tol = 2e-16; tols = 1e-7; %format long g % for debug %fprintf('scalar char routines...\n') % ------------------------------------- x = 1/3; ce = x+x; xs = single(x); try c = addchar(xs,xs); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid scalar argument, mxCHAR_CLASS expected'))) end a = '1'; b = '2'; ce = a+b; c = addchar(a,b); assert(norm(c-ce) #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif #include typedef std::complex dcomplex; #define real_dcomplex(z) std::real(z) #define imag_dcomplex(z) std::imag(z) #define setz_dcomplex(z,r,i) *z = dcomplex(r,i) typedef std::complex fcomplex; #define real_fcomplex(z) std::real(z) #define imag_fcomplex(z) std::imag(z) #define setz_fcomplex(z,r,i) *z = fcomplex(r,i) void addchar(char a, char b, char *c) { *c = a + b; } void arraddchar(char *a, char *b, char *c, int n) { for (int i=0;i 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids2_) == 0) mexStub2(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(3 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 3 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_char.mw:14\n", mexprofrecord_[1]); mexPrintf("%d calls to test_char.mw:22\n", mexprofrecord_[2]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_char.mw:14\n", mexprofrecord_[1]); fprintf(logfp, "%d calls to test_char.mw:22\n", mexprofrecord_[2]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_cpp_complex.mw000066400000000000000000000011561515063637600226040ustar00rootroot00000000000000function test_cpp_complex; $ #include $ using std::complex; $ using std::conj; $ $ complex zsum(complex* zarray, int n) { $ complex sum(0); $ for (int i = 0; i < n; ++i) sum += zarray[i]; $ return sum; $ } zarray = rand(10,1) + 1i*rand(10,1); n = length(zarray); # dcomplex result = zsum(dcomplex[] zarray, int n); tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'C++ complex support'); # dcomplex cresult = conj(dcomplex result); tassert(conj(result) == cresult, 'C++ complex support (2)'); function tassert(pred, msg) if ~pred, fprintf('Failure: %s\n', msg); end zgimbutas-mwrap-25008ce/testing/test_cpp_complexmex.cc000066400000000000000000001015741515063637600232650ustar00rootroot00000000000000/* --------------------------------------------------- */ /* Automatically generated by mwrap */ /* --------------------------------------------------- */ /* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif #include typedef std::complex dcomplex; #define real_dcomplex(z) std::real(z) #define imag_dcomplex(z) std::imag(z) #define setz_dcomplex(z,r,i) *z = dcomplex(r,i) typedef std::complex fcomplex; #define real_fcomplex(z) std::real(z) #define imag_fcomplex(z) std::imag(z) #define setz_fcomplex(z,r,i) *z = fcomplex(r,i) #include using std::complex; using std::conj; complex zsum(complex* zarray, int n) { complex sum(0); for (int i = 0; i < n; ++i) sum += zarray[i]; return sum; } /* Array copier definitions */ mxWrapGetArrayDef(mxWrapGetArray_bool, bool) mxWrapCopyDef (mxWrapCopy_bool, bool) mxWrapReturnDef (mxWrapReturn_bool, bool) mxWrapGetArrayDef_single(mxWrapGetArray_single_bool, bool) mxWrapCopyDef_single (mxWrapCopy_single_bool, bool) mxWrapReturnDef_single (mxWrapReturn_single_bool, bool) mxWrapGetArrayDef(mxWrapGetArray_char, char) mxWrapCopyDef (mxWrapCopy_char, char) mxWrapReturnDef (mxWrapReturn_char, char) mxWrapGetArrayDef_single(mxWrapGetArray_single_char, char) mxWrapCopyDef_single (mxWrapCopy_single_char, char) mxWrapReturnDef_single (mxWrapReturn_single_char, char) mxWrapGetArrayDef(mxWrapGetArray_double, double) mxWrapCopyDef (mxWrapCopy_double, double) mxWrapReturnDef (mxWrapReturn_double, double) mxWrapGetArrayDef_single(mxWrapGetArray_single_double, double) mxWrapCopyDef_single (mxWrapCopy_single_double, double) mxWrapReturnDef_single (mxWrapReturn_single_double, double) mxWrapGetArrayDef(mxWrapGetArray_float, float) mxWrapCopyDef (mxWrapCopy_float, float) mxWrapReturnDef (mxWrapReturn_float, float) mxWrapGetArrayDef_single(mxWrapGetArray_single_float, float) mxWrapCopyDef_single (mxWrapCopy_single_float, float) mxWrapReturnDef_single (mxWrapReturn_single_float, float) mxWrapGetArrayDef(mxWrapGetArray_int, int) mxWrapCopyDef (mxWrapCopy_int, int) mxWrapReturnDef (mxWrapReturn_int, int) mxWrapGetArrayDef_single(mxWrapGetArray_single_int, int) mxWrapCopyDef_single (mxWrapCopy_single_int, int) mxWrapReturnDef_single (mxWrapReturn_single_int, int) mxWrapGetArrayDef(mxWrapGetArray_long, long) mxWrapCopyDef (mxWrapCopy_long, long) mxWrapReturnDef (mxWrapReturn_long, long) mxWrapGetArrayDef_single(mxWrapGetArray_single_long, long) mxWrapCopyDef_single (mxWrapCopy_single_long, long) mxWrapReturnDef_single (mxWrapReturn_single_long, long) mxWrapGetArrayDef(mxWrapGetArray_ptrdiff_t, ptrdiff_t) mxWrapCopyDef (mxWrapCopy_ptrdiff_t, ptrdiff_t) mxWrapReturnDef (mxWrapReturn_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_ptrdiff_t, ptrdiff_t) mxWrapCopyDef_single (mxWrapCopy_single_ptrdiff_t, ptrdiff_t) mxWrapReturnDef_single (mxWrapReturn_single_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef(mxWrapGetArray_short, short) mxWrapCopyDef (mxWrapCopy_short, short) mxWrapReturnDef (mxWrapReturn_short, short) mxWrapGetArrayDef_single(mxWrapGetArray_single_short, short) mxWrapCopyDef_single (mxWrapCopy_single_short, short) mxWrapReturnDef_single (mxWrapReturn_single_short, short) mxWrapGetArrayDef(mxWrapGetArray_size_t, size_t) mxWrapCopyDef (mxWrapCopy_size_t, size_t) mxWrapReturnDef (mxWrapReturn_size_t, size_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_size_t, size_t) mxWrapCopyDef_single (mxWrapCopy_single_size_t, size_t) mxWrapReturnDef_single (mxWrapReturn_single_size_t, size_t) mxWrapGetScalarZDef(mxWrapGetScalar_fcomplex, fcomplex, float, setz_fcomplex) mxWrapGetArrayZDef (mxWrapGetArray_fcomplex, fcomplex, float, setz_fcomplex) mxWrapCopyZDef (mxWrapCopy_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapReturnZDef (mxWrapReturn_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapGetScalarZDef_single(mxWrapGetScalar_single_fcomplex, fcomplex, float, setz_fcomplex) mxWrapGetArrayZDef_single (mxWrapGetArray_single_fcomplex, fcomplex, float, setz_fcomplex) mxWrapCopyZDef_single (mxWrapCopy_single_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapReturnZDef_single (mxWrapReturn_single_fcomplex, fcomplex, real_fcomplex, imag_fcomplex) mxWrapGetScalarZDef(mxWrapGetScalar_dcomplex, dcomplex, double, setz_dcomplex) mxWrapGetArrayZDef (mxWrapGetArray_dcomplex, dcomplex, double, setz_dcomplex) mxWrapCopyZDef (mxWrapCopy_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapReturnZDef (mxWrapReturn_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapGetScalarZDef_single(mxWrapGetScalar_single_dcomplex, dcomplex, double, setz_dcomplex) mxWrapGetArrayZDef_single (mxWrapGetArray_single_dcomplex, dcomplex, double, setz_dcomplex) mxWrapCopyZDef_single (mxWrapCopy_single_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) mxWrapReturnZDef_single (mxWrapReturn_single_dcomplex, dcomplex, real_dcomplex, imag_dcomplex) /* ---- test_cpp_complex.mw: 15 ---- * dcomplex result = zsum(dcomplex[] zarray, int n); */ static const char* stubids1_ = "c o dcomplex = zsum(c i dcomplex[], c i int)"; void mexStub1(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; dcomplex* in0_ =0; /* zarray */ int in1_; /* n */ dcomplex out0_; /* result */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = mxWrapGetArray_dcomplex(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (int) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[1]++; out0_ = zsum(in0_, in1_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_dcomplex(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_dcomplex(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_dcomplex(out0_); *mxGetPi(plhs[0]) = imag_dcomplex(out0_); #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_cpp_complex.mw: 17 ---- * dcomplex cresult = conj(dcomplex result); */ static const char* stubids2_ = "c o dcomplex = conj(c i dcomplex)"; void mexStub2(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; dcomplex in0_; /* result */ dcomplex out0_; /* cresult */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_dcomplex(&in0_, prhs[0]); if (mexprofrecord_) mexprofrecord_[2]++; out0_ = conj(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_dcomplex(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_dcomplex(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_dcomplex(out0_); *mxGetPi(plhs[0]) = imag_dcomplex(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]); static mwStubFunc_t mwStubs_[] = { NULL, mexStub1, mexStub2 }; static int mwNumStubs_ = 2; /* ---- */ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { if (nrhs == 0) { mexPrintf("Mex function installed\n"); return; } /* Fast path: integer stub ID */ if (!mxIsChar(prhs[0])) { int stub_id = (int) mxGetScalar(prhs[0]); if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids2_) == 0) mexStub2(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(3 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 3 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_cpp_complex.mw:15\n", mexprofrecord_[1]); mexPrintf("%d calls to test_cpp_complex.mw:17\n", mexprofrecord_[2]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_cpp_complex.mw:15\n", mexprofrecord_[1]); fprintf(logfp, "%d calls to test_cpp_complex.mw:17\n", mexprofrecord_[2]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_cpu.mw000066400000000000000000000004651515063637600210640ustar00rootroot00000000000000$void TimesTwo_cpu(double *A, $ double *B, $ int const N) ${ $ int i; $ for(i = 0; i>>(A, B, N); $} @function result = timestwo(a) n = numel(a) # TimesTwo(gpu double[] a, gpu output double[n] result, int n); end zgimbutas-mwrap-25008ce/testing/test_gpu_complex.m000066400000000000000000000007441515063637600224300ustar00rootroot00000000000000function test_gpu_complex % Test GPU complex double array passing via gpuArray. % Requires: CUDA toolkit, mexcuda, GPU device. % Run mwrap first: % ../mwrap -gpu -list -cppcomplex -mb -mex test_gpu_complex -c test_gpu_complex.cu test_gpu_complex.mw mexcuda test_gpu_complex.cu a = complex((1:7)', (7:-1:1)'); agpu = gpuArray(a); bgpu = timestwo_complex(agpu); b = gather(bgpu); assert(norm(b - 2*a) < 1e-14, 'GPU complex timestwo failed'); fprintf('test_gpu_complex: PASSED\n'); zgimbutas-mwrap-25008ce/testing/test_gpu_complex.mw000066400000000000000000000015141515063637600226130ustar00rootroot00000000000000$void __global__ TimesTwoKernel(cuDoubleComplex *A, $ cuDoubleComplex *B, $ int const N) ${ $ /* Calculate the global linear index, assuming a 1-d grid. */ $ int const i = blockDim.x * blockIdx.x + threadIdx.x; $ if (i < N) { $ /* B[i] = make_cuDoubleComplex(2.0,0.0) * A[i]; */ $ B[i] = cuCmul(make_cuDoubleComplex(2.0,0.0),A[i]); $ } $} $void TimesTwo(cuDoubleComplex *A, $ cuDoubleComplex *B, $ int const N) ${ $ int const threadsPerBlock = 256; $ int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; $ TimesTwoKernel<<>>(A, B, N); $} @function result = timestwo_complex(a) n = numel(a) # TimesTwo(gpu dcomplex[] a, gpu output dcomplex[n] result, int n); end zgimbutas-mwrap-25008ce/testing/test_gpu_int32.m000066400000000000000000000007171515063637600217200ustar00rootroot00000000000000function test_gpu_int32 % Test GPU int32 array passing via gpuArray. % Requires: CUDA toolkit, mexcuda, GPU device. % Run mwrap first: % ../mwrap -gpu -list -cppcomplex -mb -mex test_gpu_int32 -c test_gpu_int32.cu test_gpu_int32.mw mexcuda test_gpu_int32.cu a = int32((1:7)'); agpu = gpuArray(a); bgpu = timestwo_gpu_int32(agpu); b = gather(bgpu); assert(norm(double(b) - 2*double(a)) == 0, 'GPU int32 timestwo failed'); fprintf('test_gpu_int32: PASSED\n'); zgimbutas-mwrap-25008ce/testing/test_gpu_int32.mw000066400000000000000000000013211515063637600220770ustar00rootroot00000000000000$void __global__ TimesTwoKernel(int32_t *A, $ int32_t *B, $ int const N) ${ $ /* Calculate the global linear index, assuming a 1-d grid. */ $ int const i = blockDim.x * blockIdx.x + threadIdx.x; $ if (i < N) { $ B[i] = 2.0 * A[i]; $ } $} $void TimesTwo(int32_t *A, $ int32_t *B, $ int const N) ${ $ int const threadsPerBlock = 256; $ int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock; $ TimesTwoKernel<<>>(A, B, N); $} @function result = timestwo_gpu_int32(a) n = numel(a) # TimesTwo(gpu int32_t[] a, gpu output int32_t[n] result, int n); end zgimbutas-mwrap-25008ce/testing/test_include.mw000066400000000000000000000003421515063637600217120ustar00rootroot00000000000000function test_include() @include test_include2.mw tassert(j == 4, 'Include test'); % ================================================================ function tassert(pred, msg) if ~pred, fprintf('Failure: %s\n', msg); end zgimbutas-mwrap-25008ce/testing/test_include2.mw000066400000000000000000000000701515063637600217720ustar00rootroot00000000000000$int add2(int i) { return i+2; } # int j = add2(int 2); zgimbutas-mwrap-25008ce/testing/test_python.sh000077500000000000000000000124611515063637600216070ustar00rootroot00000000000000#!/usr/bin/env bash # # test_python.sh — test the Python mwrap port against reference files # and against C++ mwrap output. # # Usage: # bash testing/test_python.sh # # Example: # bash testing/test_python.sh build/mwrap python/mwrap set -euo pipefail if [ $# -ne 2 ]; then echo "Usage: $0 " exit 1 fi MWRAP_CPP="$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" MWRAP_PY="$(cd "$(dirname "$2")" && pwd)/$(basename "$2")" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" TMPDIR_BASE="$(mktemp -d)" trap 'rm -rf "$TMPDIR_BASE"' EXIT PASS=0 FAIL=0 ERRORS="" pass() { PASS=$((PASS + 1)) echo " PASS: $1" } fail() { FAIL=$((FAIL + 1)) ERRORS="${ERRORS} FAIL: $1\n" echo " FAIL: $1" } # ---------------------------------------------------------------- # Group A: Reference-file tests # Run from the testing directory with relative .mw paths so that # error messages use basenames (matching the .ref files). # ---------------------------------------------------------------- echo "=== Group A: Reference-file tests ===" run_ref_test() { local name="$1" local mw_basename="$2" local ref_file="$3" shift 3 local flags=("$@") local tmpout="$TMPDIR_BASE/${name}.stderr" # Run Python mwrap from SCRIPT_DIR with relative .mw path; expect nonzero exit if (cd "$SCRIPT_DIR" && "$MWRAP_PY" "${flags[@]}" "$mw_basename" 2>"$tmpout") ; then fail "$name (expected nonzero exit, got 0)" return fi # Normalize "end of file" -> "$end" to match Bison 3.x convention sed -i.bak 's/end of file/$end/g' "$tmpout" if diff -u "$ref_file" "$tmpout" >/dev/null 2>&1; then pass "$name" else fail "$name (stderr differs from reference)" diff -u "$ref_file" "$tmpout" || true fi } run_ref_test test_syntax \ test_syntax.mw \ "$SCRIPT_DIR/test_syntax.ref" \ -cppcomplex run_ref_test test_typecheck \ test_typecheck.mw \ "$SCRIPT_DIR/test_typecheck.ref" \ -cppcomplex # ---------------------------------------------------------------- # Group B: Output equivalence tests (Python vs C++) # ---------------------------------------------------------------- echo "" echo "=== Group B: Output equivalence tests ===" run_equiv_test() { local name="$1" local mw_file="$2" local cc_ext="$3" # .cc or .c local gen_m="$4" # "yes" or "no" shift 4 local flags=() if [ $# -gt 0 ]; then flags=("$@") fi local cpp_dir="$TMPDIR_BASE/cpp_${name}" local py_dir="$TMPDIR_BASE/py_${name}" mkdir -p "$cpp_dir" "$py_dir" local mex_name="${name}mex" local cc_file="${mex_name}${cc_ext}" # Copy test_include2.mw if needed (for @include) if [ -f "$SCRIPT_DIR/test_include2.mw" ]; then cp "$SCRIPT_DIR/test_include2.mw" "$cpp_dir/" cp "$SCRIPT_DIR/test_include2.mw" "$py_dir/" fi local cpp_args=(-mex "$mex_name" -c "$cc_file") local py_args=(-mex "$mex_name" -c "$cc_file") if [ "$gen_m" = "yes" ]; then cpp_args+=(-m "${name}.m") py_args+=(-m "${name}.m") else cpp_args+=(-mb) py_args+=(-mb) fi if [ ${#flags[@]} -gt 0 ]; then cpp_args+=("${flags[@]}") py_args+=("${flags[@]}") fi cpp_args+=("$mw_file") py_args+=("$mw_file") # Run C++ mwrap if ! (cd "$cpp_dir" && "$MWRAP_CPP" "${cpp_args[@]}" 2>/dev/null); then fail "$name (C++ mwrap failed)" return fi # Run Python mwrap if ! (cd "$py_dir" && "$MWRAP_PY" "${py_args[@]}" 2>/dev/null); then fail "$name (Python mwrap failed)" return fi # Compare generated C/C++ file if diff -u "$cpp_dir/$cc_file" "$py_dir/$cc_file" >/dev/null 2>&1; then pass "$name ($cc_file)" else fail "$name ($cc_file differs)" diff -u "$cpp_dir/$cc_file" "$py_dir/$cc_file" | head -40 || true fi # Compare generated .m file (if applicable) if [ "$gen_m" = "yes" ]; then if diff -u "$cpp_dir/${name}.m" "$py_dir/${name}.m" >/dev/null 2>&1; then pass "$name (${name}.m)" else fail "$name (${name}.m differs)" diff -u "$cpp_dir/${name}.m" "$py_dir/${name}.m" | head -40 || true fi fi } run_equiv_test test_transfers \ "$SCRIPT_DIR/test_transfers.mw" .cc yes run_equiv_test test_cpp_complex \ "$SCRIPT_DIR/test_cpp_complex.mw" .cc yes \ -cppcomplex run_equiv_test test_c99_complex \ "$SCRIPT_DIR/test_c99_complex.mw" .c yes \ -c99complex run_equiv_test test_catch \ "$SCRIPT_DIR/test_catch.mw" .cc yes \ -catch run_equiv_test test_fortran1 \ "$SCRIPT_DIR/test_fortran1.mw" .cc yes run_equiv_test test_fortran2 \ "$SCRIPT_DIR/test_fortran2.mw" .c yes run_equiv_test test_include \ "$SCRIPT_DIR/test_include.mw" .cc yes run_equiv_test test_single \ "$SCRIPT_DIR/test_single.mw" .cc no \ -cppcomplex run_equiv_test test_char \ "$SCRIPT_DIR/test_char.mw" .cc no \ -cppcomplex # ---------------------------------------------------------------- # Summary # ---------------------------------------------------------------- echo "" echo "=== Summary ===" echo " Passed: $PASS" echo " Failed: $FAIL" if [ $FAIL -ne 0 ]; then echo "" echo "Failures:" echo -e "$ERRORS" exit 1 fi exit 0 zgimbutas-mwrap-25008ce/testing/test_redirect.mw000066400000000000000000000002111515063637600220630ustar00rootroot00000000000000@function test_redirect if test_redirect1(42) ~= 42, fprint('Failure: Redirection failed?'); end @function x = test_redirect1(y) x = y; zgimbutas-mwrap-25008ce/testing/test_single.m000066400000000000000000000060711515063637600213660ustar00rootroot00000000000000function test_single % pass-fail test of the single- and double-precision args and arrays. % must do either make test_single_cpp or make test_single_c99 first. % Barnett & Gimbutas. 7/20/20 tol = 2e-16; tols = 1e-7; %format long g % for debug %fprintf('scalar real routines...\n') % ------------------------------------- x = 1/3; ce = x+x; xf = single(x); c = add(x,x); assert(abs(c-ce)tol) % test it's not doing double-prec! assert(strcmp(class(c),'single')) %fprintf('\narray real routines...\n') % ------------------------------------ x = x*ones(3,1); xf = xf*ones(3,1); ce=x+x; c = arradd(x,x); assert(norm(c-ce)double, as mwrap 0.33.3 designed for! try c = arradd(xf,xf); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid array argument, mxDOUBLE_CLASS expected'))); end try c = arraddf(x,x); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid array argument, mxSINGLE_CLASS expected'))); end c = arraddf(xf,xf); % input as designed, should give single assert(norm(double(c)-ce)tol) % test it's not doing double-prec! assert(strcmp(class(c),'single')) %fprintf('\nscalar complex routines...\n') % ------------------------------- z = (1+2i)/3; zf = single(z); ce = z+z; c = addz(z,z); assert(abs(c-ce)double, as mwrap 0.33.3 designed for! try c = addz(zf,zf); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid scalar argument, mxDOUBLE_CLASS expected'))); end try c = addc(z,z); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid scalar argument, mxSINGLE_CLASS expected'))); end c = addc(zf,zf); % input as designed, should give single assert(abs(double(c)-ce)tol) % test it's not doing double-prec! assert(strcmp(class(c),'single')) % fprintf('\narray complex routines...\n') % -------------------------------- z = z*ones(3,1); zf = zf*ones(3,1); ce = z+z; c = arraddz(z,z); % input as designed, double assert(norm(c-ce)double, as mwrap 0.33.3 designed for! try c = arraddz(zf,zf); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid array argument, mxDOUBLE_CLASS expected'))); end try c = arraddc(z,z); % should error catch ME assert(~isempty(strfind(ME.message,'Invalid array argument, mxSINGLE_CLASS expected'))); end c = arraddc(zf,zf); % input as designed, should give single assert(norm(double(c)-ce)tol) % test it's not doing double-prec! assert(strcmp(class(c),'single')) zgimbutas-mwrap-25008ce/testing/test_single.mw000066400000000000000000000034751515063637600215620ustar00rootroot00000000000000% test double and single precision, scalars and arrays, in mwrap. % Barnett & Gimbutas 7/5/20-7/20/20. % make as in Makefile, % then pass-fail test in octave/matlab with: % test_single.m % the old non-pass-fail is here: % test_single_humanreadable.m % REAL====================================================== % scalar real......... $ void add(double a, double b, double *c) { *c = a + b; } @function c=add(a,b) # add(double a, double b, output double[1]c); $ void addf(float a, float b, float *c) { *c = a + b; } @function c=addf(a,b) # addf(float a, float b, output float[1]c); % array real........ $ void arradd(double *a, double *b, double *c, int n) $ { for (int i=0;idouble, as mwrap 0.33.3 designed for! try c = arradd(xf,xf) % should error catch ME ME.message disp('good') end try c = arraddf(x,x), class(c) % should error catch ME ME.message disp('good') end c = arraddf(xf,xf) % input as designed, should give single fprintf('\nscalar complex routines...\n') z = (1+2i)/3; zf = single(z); c = addz(z,z), class(c) try c = addz(zf,zf) % should error catch ME ME.message disp('good') end try c = addc(z,z), class(c) % should error catch ME ME.message disp('good') end c = addc(zf,zf) % input as designed, should give single fprintf('\narray complex routines...\n') z = z*ones(3,1); zf = zf*ones(3,1); try c = arraddz(z,z), class(c) % input as designed, double catch ME ME.message disp('****** bad') end try c = arraddz(zf,zf) % should error catch ME ME.message disp('good') end try c = arraddc(z,z), class(c) % should error catch ME ME.message disp('good') end try c = arraddc(zf,zf) % input as designed, should give single catch ME ME.message disp('****** bad') end zgimbutas-mwrap-25008ce/testing/test_singlemex.cc000066400000000000000000001362161515063637600222360ustar00rootroot00000000000000/* --------------------------------------------------- */ /* Automatically generated by mwrap */ /* --------------------------------------------------- */ /* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif #include typedef std::complex dcomplex; #define real_dcomplex(z) std::real(z) #define imag_dcomplex(z) std::imag(z) #define setz_dcomplex(z,r,i) *z = dcomplex(r,i) typedef std::complex fcomplex; #define real_fcomplex(z) std::real(z) #define imag_fcomplex(z) std::imag(z) #define setz_fcomplex(z,r,i) *z = fcomplex(r,i) void add(double a, double b, double *c) { *c = a + b; } void addf(float a, float b, float *c) { *c = a + b; } void arradd(double *a, double *b, double *c, int n) { for (int i=0;i 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids2_) == 0) mexStub2(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids3_) == 0) mexStub3(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids4_) == 0) mexStub4(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids5_) == 0) mexStub5(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids6_) == 0) mexStub6(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids7_) == 0) mexStub7(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids8_) == 0) mexStub8(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(9 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 9 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_single.mw:18\n", mexprofrecord_[1]); mexPrintf("%d calls to test_single.mw:22\n", mexprofrecord_[2]); mexPrintf("%d calls to test_single.mw:30\n", mexprofrecord_[3]); mexPrintf("%d calls to test_single.mw:36\n", mexprofrecord_[4]); mexPrintf("%d calls to test_single.mw:45\n", mexprofrecord_[5]); mexPrintf("%d calls to test_single.mw:49\n", mexprofrecord_[6]); mexPrintf("%d calls to test_single.mw:57\n", mexprofrecord_[7]); mexPrintf("%d calls to test_single.mw:63\n", mexprofrecord_[8]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_single.mw:18\n", mexprofrecord_[1]); fprintf(logfp, "%d calls to test_single.mw:22\n", mexprofrecord_[2]); fprintf(logfp, "%d calls to test_single.mw:30\n", mexprofrecord_[3]); fprintf(logfp, "%d calls to test_single.mw:36\n", mexprofrecord_[4]); fprintf(logfp, "%d calls to test_single.mw:45\n", mexprofrecord_[5]); fprintf(logfp, "%d calls to test_single.mw:49\n", mexprofrecord_[6]); fprintf(logfp, "%d calls to test_single.mw:57\n", mexprofrecord_[7]); fprintf(logfp, "%d calls to test_single.mw:63\n", mexprofrecord_[8]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_syntax.mw000066400000000000000000000003071515063637600216160ustar00rootroot00000000000000 function badmojo # double z = sumpair(double x) // Missing semicolon should result in error // Another line just to double check lines # double z = sumpair(double x); # double z = sumpair(double x) zgimbutas-mwrap-25008ce/testing/test_syntax.ref000066400000000000000000000002401515063637600217430ustar00rootroot00000000000000Parse error (test_syntax.mw:4): syntax error, unexpected NON_C_LINE, expecting ';' Parse error (test_syntax.mw:8): syntax error, unexpected $end, expecting ';' zgimbutas-mwrap-25008ce/testing/test_transfers.mw000066400000000000000000000362071515063637600223070ustar00rootroot00000000000000function test_transfers test_mult_inherit; test_scopes; test_literals; test_types; test_complex; test_nulls; test_method; test_returns; test_inputs; test_outputs; test_inouts; test_mx; test_const; test_struct; % ================================================================ $[ #include #include struct Pair { Pair(double x, double y) { xy[0] = x; xy[1] = y; } double xy[2]; double x() { return xy[0]; } double y() { return xy[1]; } }; struct BadPair { double x; }; struct DerivedPair : public Pair { DerivedPair() : Pair(7,11) {} }; #include typedef std::complex cmplx; #define real_cmplx(z) (z).real() #define imag_cmplx(z) (z).imag() #define setz_cmplx(zp, r, i) *zp = cmplx(r,i) typedef unsigned char uchar; typedef unsigned long ulong; $] % ================================================================ function test_mult_inherit $[ class Parent1 { public: Parent1(int data) : data1_(data) {} virtual ~Parent1() {} virtual int data1() { return data1_; } protected: int data1_; }; class Parent2 { public: Parent2(int data) : data2_(data) {} virtual ~Parent2() {} virtual int data2() { return data2_; } protected: int data2_; }; class Child : public Parent1, public Parent2 { public: Child() : Parent1(1), Parent2(2) {} virtual int data1() { return data1_ + 1; } virtual int data2() { return data2_ + 1; } int datas() { return data1_ + data2_; } }; $] # class Child : Parent1, Parent2; # Child* c = new Child(); # int d1 = c->Parent1.data1(); # int d2 = c->Parent2.data2(); # int dd = c->Child.datas(); tassert(d1 == 2, 'Multiple inheritance handling (1)'); tassert(d2 == 3, 'Multiple inheritance handling (2)'); tassert(dd == 3, 'Multiple inheritance handling (3)'); % ================================================================ function test_scopes; $ class OuterClass { $ public: $ static int static_method() { return 123; } $ }; # int x = OuterClass::static_method(); tassert(x == 123, 'Access to static class method'); % ================================================================ function test_literals; $ int literal_plus1(int x) { return x+1; } # int y = literal_plus1(int 7); # int l = strlen(cstring 'Test'); tassert(y == 8, 'Integer literals'); tassert(l == 4, 'String literals'); % ================================================================ function test_types; $ typedef unsigned char byte; $ void takes_double(double& x) {} $ void takes_float(float& x) {} $ void takes_long(long& x) {} $ void takes_int(int& x) {} $ void takes_char(char& x) {} $ void takes_ulong(unsigned long& x) {} $ void takes_uint(unsigned int& x) {} $ void takes_uchar(unsigned char& x) {} $ void takes_bool(bool& x) {} $ void takes_size_t(size_t& x) {} x = 0; xs = single(x); xc=char(42); # typedef numeric byte; # takes_double(double& x); # takes_float(float& xs); # takes_long(long& x); # takes_int(int& x); # takes_char(char& xc); # takes_ulong(ulong& x); # takes_uint(uint& x); # takes_uchar(uchar& x); # takes_uchar(byte& x); # takes_bool(bool& x); # takes_size_t(size_t& x); # class DerivedPair : Pair; # DerivedPair* dp = new DerivedPair(); # double x = dp->Pair.x(); tassert(x == 7, 'Type casting'); % ================================================================ function test_complex; $ cmplx zsum(cmplx* zarray, int n) { $ cmplx sum(0); $ for (int i = 0; i < n; ++i) sum += zarray[i]; $ return sum; $ } zarray = rand(10,1) + 1i*rand(10,1); n = length(zarray); # typedef dcomplex cmplx; # cmplx result = zsum(cmplx[] zarray, int n); tassert(abs(result-sum(zarray)) < 1e-10*norm(zarray), 'Complex support'); % ================================================================ function test_nulls; $ Pair* null_pair() { return NULL; } # Pair* p = null_pair(); tassert(p == 0, 'Null pointer return'); $ int is_null(Pair* p) { return !p; } # int flag = is_null(Pair* p); tassert(flag, 'Null pointer input'); $ char* null_string() { return NULL; } # cstring s = null_string(); tassert(s == 0, 'Null string return'); # char* c = null_string(); tassert(isempty(c), 'Null scalar pointer return'); nil = []; $ int is_null(double* data) { return !data; } # int flag = is_null(double[] nil); tassert(flag, 'Null array input'); # char[1] ca = null_string(); tassert(isempty(ca), 'Null array return'); $ void test_null_obj(Pair& p) { } try # test_null_obj(Pair p); tassert(0, 'Null argument dereference 1'); end try # test_null_obj(Pair& p); tassert(0, 'Null argument dereference 1'); end try # double x = p->Pair.x(); tassert(0, 'Invalid this test'); end # BadPair* bp = new BadPair(); try $ void test_bad_pair(Pair* p) { } # test_bad_pair(Pair* bp); tassert(0, 'Invalid pointer test'); end # delete(BadPair* bp); % ================================================================ function test_method; x = 1; y = 2; # Pair* p = new Pair(double x, double y); # double xx = p->Pair.x(); # double yy = p->Pair.y(); # delete(Pair* p); tassert(xx == 1, 'Method call'); tassert(yy == 2, 'Method call'); % ================================================================ function test_returns; $ Pair test_return_obj() { return Pair(1.5, 2.5); } # Pair p1 = test_return_obj(); tassert(sscanf(p1, 'Pair:%x') > 0, 'Return object'); $ double* test_return_array(Pair& p) { return p.xy; } # double[2] xy = test_return_array(Pair& p1); tassert(norm(xy-[1.5; 2.5]) == 0, 'Return array'); $ double* test_return_array2(Pair& p) { return p.xy; } # double xy[2] = test_return_array2(Pair& p1); tassert(norm(xy-[1.5; 2.5]) == 0, 'Return array'); $ double test_return_scalar(double* xy) { return xy[0] + xy[1]; } # double sum = test_return_scalar(double[] xy); tassert(sum == 4, 'Return scalar'); xy_z = [1+5i, 7+11i]; $ cmplx test_return_zscalar(cmplx* xy) { return xy[0] + xy[1]; } # cmplx sum1 = test_return_zscalar(cmplx[] xy); # cmplx sum2 = test_return_zscalar(cmplx[] xy_z); tassert(sum1 == 4, 'Return zscalar (reals)'); tassert(sum2 == 8+16i, 'Return zscalar (complexes)'); $ const char* test_return_string() { return "Hello, world!"; } # cstring s = test_return_string(); tassert(strcmp(s, 'Hello, world!'), 'Return string'); $ Pair* test_return_p_obj() { return new Pair(3, 5); } # Pair* p2 = test_return_p_obj(); # double[2] xy = test_return_array(Pair& p2); tassert(norm(xy - [3;5]) == 0, 'Return obj*'); a = 7; b = 11; $ int* test_return_p_scalar(int* a, int* b) { return (*a > *b) ? a : b; } # int* z1 = test_return_p_scalar(int* a, int* b); tassert(z1 == 11, 'Return scalar*'); a_z = 7 + 10i; b_z = 11 + 15i; $ cmplx* test_return_p_zscalar(cmplx* a, cmplx* b) { $ return (a->real() > b->real()) ? a : b; $ } # cmplx* z1 = test_return_p_zscalar(cmplx* a, cmplx* b); # cmplx* z2 = test_return_p_zscalar(cmplx* a_z, cmplx* b_z); tassert(z1 == 11, 'Return zscalar*'); tassert(z2 == 11 + 15i, 'Return zscalar*'); $ Pair& test_return_r_obj(Pair& p) { return p; } # Pair& p2c = test_return_r_obj(Pair& p2); tassert(strcmp(p2, p2c), 'Return obj&'); $ int& test_return_r_scalar(int& a, int& b) { return (a > b) ? a : b; } # int& z2 = test_return_r_scalar(int& a, int& b); tassert(z2 == 11, 'Return scalar&'); $ cmplx& test_return_r_zscalar(cmplx& a, cmplx& b) { $ return (a.real() > b.real()) ? a : b; $ } # cmplx& z2 = test_return_r_zscalar(cmplx& a, cmplx& b); # cmplx& z3 = test_return_r_zscalar(cmplx& a_z, cmplx& b_z); tassert(z2 == 11, 'Return zscalar&'); tassert(z3 == 11 + 15i, 'Return zscalar&'); # delete(Pair* p1); # delete(Pair* p2); % ================================================================ function test_inputs x = 101; y = 202; # Pair* p = new Pair(double x, double y); $ double test_input_obj(Pair p) { return p.xy[0] + p.xy[1]; } # double sum = test_input_obj(input Pair p); tassert(sum == 303, 'Input obj'); xy = [11, 22]; $ double test_input_array(double* xy) { return xy[0] + xy[1]; } # double sum = test_input_array(double[2] xy); tassert(sum == 33, 'Input array'); $ double test_input_array2(double* xy) { return xy[0] + xy[1]; } # double sum = test_input_array2(double xy[2]); tassert(sum == 33, 'Input array'); xy_z = [11 + 5i, 22 + 6i]; $ cmplx test_input_zarray(cmplx* xy) { return xy[0] + xy[1]; } # cmplx sum = test_input_zarray(cmplx[2] xy); # cmplx sum2 = test_input_zarray(cmplx[2] xy_z); tassert(sum == 33, 'Input zarray'); tassert(sum2 == 33 + 11i, 'Input zarray'); $ int test_input_scalar(int x) { return x+1; } # int xp1 = test_input_scalar(int x); tassert(xp1 == 102, 'Input scalar'); x_z = 101 + 99i; $ cmplx test_input_zscalar(cmplx x) { return x+1.0; } # cmplx xp1 = test_input_zscalar(cmplx x); # cmplx xp1z = test_input_zscalar(cmplx x_z); tassert(xp1 == 102, 'Input zscalar'); tassert(xp1z == 102 + 99i, 'Input zscalar'); msg = 'Hello, world!'; $ int test_input_string(char* s) { return strlen(s); } # int msglen = test_input_string(cstring msg); tassert(msglen == length(msg), 'Input string'); $ double test_input_p_obj(Pair* p) { return p->xy[0] + p->xy[1]; } # double sum2 = test_input_p_obj(Pair* p); tassert(sum2 == 303, 'Input obj*'); $ int test_input_p_scalar(int* x) { return *x+1; } # int xp1b = test_input_p_scalar(int* x); tassert(xp1b == 102, 'Input scalar*'); $ cmplx test_input_p_zscalar(cmplx* x) { return *x+1.0; } # cmplx xp1b = test_input_p_zscalar(cmplx* x); # cmplx xp1c = test_input_p_zscalar(cmplx* x_z); tassert(xp1b == 102, 'Input zscalar*'); tassert(xp1c == 102 + 99i, 'Input zscalar*'); $ double test_input_r_obj(Pair& p) { return p.xy[0] + p.xy[1]; } # double sum3 = test_input_r_obj(Pair& p); tassert(sum3 == 303, 'Input obj&'); $ int test_input_r_scalar(int& x) { return x+1; } # int xp1c = test_input_r_scalar(input int& x); tassert(xp1c == 102, 'Input scalar&'); $ cmplx test_input_r_zscalar(cmplx& x) { return x+1.0; } # cmplx xp1c = test_input_r_zscalar(input cmplx& x); # cmplx xp1d = test_input_r_zscalar(input cmplx& x_z); tassert(xp1c == 102, 'Input scalar&'); tassert(xp1d == 102 + 99i, 'Input scalar&'); # delete(input Pair* p); % ================================================================ function test_outputs $ void test_output_array(double* xy) { xy[0] = 1; xy[1] = 2; } # test_output_array(output double[2] xy); tassert(norm(xy-[1;2]) == 0, 'Output array'); $ void test_output_rarray(const double*& xy) { $ static double result[2] = {7, 11}; $ xy = result; $ } # test_output_rarray(output double[2]& xyr); tassert(norm(xyr-[7;11]) == 0, 'Output rarray'); $ void test_output_rarray2(const double*& xy) { xy = NULL; } # test_output_rarray2(output double[2]& xyr2); tassert(isempty(xyr2), 'Output rarray'); $ void test_output_zarray(cmplx* xy) { xy[0] = 1; xy[1] = 2; } $ void test_output_zarray2(cmplx* xy) { xy[0] = cmplx(1,3); xy[1] = 2; } # test_output_zarray(output cmplx[2] xy); # test_output_zarray2(output cmplx[2] xy_z); tassert(norm(xy-[1;2]) == 0, 'Output array'); tassert(norm(xy_z-[1+3i;2]) == 0, 'Output array'); fmt = '= %d'; i = 101; # snprintf(output cstring[128] buf, input int 128, input cstring fmt, input int i); tassert(strcmp('= 101', buf), 'Output string'); $ void test_output_p_scalar(int* i) { *i = 202; } # test_output_p_scalar(output int* i2); tassert(i2 == 202, 'Output scalar*'); $ void test_output_p_zscalar(cmplx* z) { *z = cmplx(202,303); } # test_output_p_zscalar(output cmplx* z2); tassert(z2 == 202+303i, 'Output zscalar*'); $ void test_output_r_scalar(int& i) { i = 303; } # test_output_r_scalar(output int& i3); tassert(i3 == 303, 'Output scalar&'); $ void test_output_r_zscalar(cmplx& z) { z = cmplx(303,404); } # test_output_r_zscalar(output cmplx& z3); tassert(z3 == 303+404i, 'Output zscalar&'); % ================================================================ function test_inouts xy = [1, 2]; $ void test_inout_array(double* xy) { xy[0] += 1; xy[1] += 1; } # test_inout_array(inout double[] xy); tassert(norm(xy - [2,3]) == 0, 'Inout array'); s1 = 'foo'; s2 = 'bar'; # strcat(inout cstring[128] s1, input cstring s2); tassert(strcmp(s1, 'foobar'), 'Inout string'); i1 = 101; $ void test_inout_p_scalar(int* i) { *i += 202; } # test_inout_p_scalar(inout int* i1); tassert(i1 == 303, 'Inout scalar*'); i2 = 101; $ void test_inout_r_scalar(int& i) { i += 303; } # test_inout_r_scalar(inout int& i2); tassert(i2 == 404, 'Inout scalar&'); % ================================================================ function test_mx $ #include in1 = 42; $ double test_mx_input(const mxArray* x) { return *mxGetPr(x); } # double out1 = test_mx_input(input mxArray in1); tassert(out1 == 42, 'Input mx'); $ void test_mx_output(mxArray** x) $ { $ *x = mxCreateString("foobar"); $ } # test_mx_output(output mxArray out2); tassert(strcmp(out2, 'foobar'), 'Output mx'); $ mxArray* test_mx_return() $ { $ mxArray* m = mxCreateDoubleMatrix(1,1, mxREAL); $ *mxGetPr(m) = 42; $ return m; $ } # mxArray out3 = test_mx_return(); tassert(out3 == 42, 'Return mx'); % ================================================================ function test_const $ const int TEST_CONST = 42; $ int identity(int i) { return i; } # int result = identity(const TEST_CONST); tassert(result == 42, 'Constant transfer'); # int result2 = identity(const 'TEST_CONST'); tassert(result2 == 42, 'Constant transfer'); % ================================================================ function test_struct $[ struct my_struct_t { double x; double y; }; int my_struct_allocs = 0; int get_my_struct_allocs() { return my_struct_allocs; } my_struct_t* mxWrapGet_my_struct_t(const mxArray* a, const char** e) { // Note -- there really ought to be an error check here ++my_struct_allocs; my_struct_t* o = new my_struct_t; o->x = mxGetPr(a)[0]; o->y = mxGetPr(a)[1]; return o; } mxArray* mxWrapSet_my_struct_t(my_struct_t* o) { mxArray* a = mxCreateDoubleMatrix(2,1,mxREAL); mxGetPr(a)[0] = o->x; mxGetPr(a)[1] = o->y; return a; } my_struct_t* mxWrapAlloc_my_struct_t() { ++my_struct_allocs; return new my_struct_t; } void mxWrapFree_my_struct_t(my_struct_t* o) { --my_struct_allocs; delete o; } void unpack_struct(my_struct_t& o, double* xy) { xy[0] = o.x; xy[1] = o.y; } void pack_struct(my_struct_t& o, double* xy) { o.x = xy[0]; o.y = xy[1]; } void swap_struct(my_struct_t& o) { double tmp = o.x; o.x = o.y; o.y = tmp; } my_struct_t& rightmost(my_struct_t& p1, my_struct_t& p2) { return (p1.x >= p2.x) ? p1 : p2; } my_struct_t* add1(my_struct_t& o) { o.x += 1; o.y += 1; return &o; } $] # typedef mxArray my_struct_t; xy1 = [1, 2]; # unpack_struct(my_struct_t& xy1, output double xy2[2]); tassert(norm(xy2-[1;2]) == 0, 'Structure conversion on input'); # pack_struct(output my_struct_t xy3, double[] xy1); tassert(norm(xy3-[1;2]) == 0, 'Structure conversion on output'); xy4 = [3; 4]; # swap_struct(inout my_struct_t xy4); tassert(norm(xy4-[4; 3]) == 0, 'Structure on inout'); # my_struct_t& result = rightmost(my_struct_t& xy1, my_struct_t& xy4); tassert(norm(result-[4;3]) == 0, 'Structure on reference return'); # my_struct_t* xy5 = add1(my_struct_t& xy4); tassert(norm(xy5-[5;4]) == 0, 'Structure on pointer return'); # int alloc_count = get_my_struct_allocs(); tassert(alloc_count == 0, 'Balanced allocations in structure management'); % ================================================================ function tassert(pred, msg) if ~pred, fprintf('Failure: %s\n', msg); end zgimbutas-mwrap-25008ce/testing/test_transfersmex.cc000066400000000000000000004061761515063637600227710ustar00rootroot00000000000000/* --------------------------------------------------- */ /* Automatically generated by mwrap */ /* --------------------------------------------------- */ /* Code generated by mwrap 1.3 */ /* Copyright statement for mwrap: mwrap -- MEX file generation for MATLAB and Octave Copyright (c) 2007-2008 David Bindel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. You may distribute a work that contains part or all of the source code generated by mwrap under the terms of your choice. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #if MX_HAS_INTERLEAVED_COMPLEX #include #endif /* * Records for call profile. */ int* mexprofrecord_= NULL; double mxWrapGetScalar_char(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxCHAR_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid char argument"; return 0; } return (char) (*mxGetChars(a)); } /* * Support routines for copying data into and out of the MEX stubs, R2018a */ #if MX_HAS_INTERLEAVED_COMPLEX void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexDoubles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxDOUBLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetDoubles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetDoubles(z) = 0; return z; } } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (double) (*mxGetComplexDoubles(a)).real; else return (double) (*mxGetDoubles(a)); } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (double) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = (double) *q++; \ } \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetDoubles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (double) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) (*mxGetComplexDoubles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexDoubles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ mxComplexDouble* z; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetDoubles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p; \ mxComplexDouble* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexDoubles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetDoubles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexDouble* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ p = mxGetComplexDoubles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = NULL; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && (*mxGetComplexSingles(a)).real == 0 ) return NULL; } if (mxGetClassID(a) == mxSINGLE_CLASS && !mxIsComplex(a) ) { if( mxGetM(a)*mxGetN(a) == 1 && *mxGetSingles(a) == 0) return NULL; } if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *mxGetSingles(z) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } if( mxIsComplex(a) ) return (float) (*mxGetComplexSingles(a)).real; else return (float) (*mxGetSingles(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*z++).real; \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ } \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) \ (*z++).real = (float) *q++; \ (*z++).imag = 0; \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = (float) *q++; \ } \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL); \ p = mxGetSingles(a); \ for (i = 0; i < m*n; ++i) \ *p++ = (float) *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ if( mxIsComplex(a) ) \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) (*mxGetComplexSingles(a)).imag); \ } \ else \ { \ setz(z, (ZT) (*mxGetComplexSingles(a)).real, (ZT) 0); \ } \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ mxComplexSingle* z; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*z).real, (ZT) (*z).imag); \ ++p; ++z; } \ } \ else \ { \ q = mxGetSingles(a); \ for (i = 0; i < arraylen; ++i) { \ setz(p, (ZT) (*q), (ZT) 0 ); \ ++p; ++q; } \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, freal, fimag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p; \ mxComplexSingle* z; \ if( mxIsComplex(a) ) \ { \ z = mxGetComplexSingles(a); \ for (i = 0; i < n; ++i) { \ (*z).real = freal(*q); \ (*z).imag = fimag(*q); \ ++z; ++q; } \ } \ else \ { \ p = mxGetSingles(a); \ for (i = 0; i < n; ++i) \ *p++ = freal(*q++); \ } \ } #define mxWrapReturnZDef_single(func, T, freal, fimag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ mxComplexSingle* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX); \ p = mxGetComplexSingles(a); \ for (i = 0; i < m*n; ++i) { \ (*p).real = freal(*q); \ (*p).imag = fimag(*q); \ ++p; ++q; } \ return a; \ } \ } #else /* * Support routines for copying data into and out of the MEX stubs, -R2017b */ void* mxWrapGetP(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *mxGetPr(a) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(z) = 0; return z; } } double mxWrapGetScalar(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxDOUBLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *mxGetPr(a); } char* mxWrapGetString(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* q; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = mxGetPr(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* p = mxGetPr(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* p; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxREAL); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxREAL); \ p = mxGetPr(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ double* qr; \ double* qi; \ if (!a || mxGetClassID(a) != mxDOUBLE_CLASS) { \ *e = "Invalid array argument, mxDOUBLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = mxGetPr(a); \ qi = mxGetPi(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ double* pr = mxGetPr(a); \ double* pi = mxGetPi(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ double* pr; \ double* pi; \ if (!q) { \ return mxCreateDoubleMatrix(0,0, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateDoubleMatrix(m,n, mxCOMPLEX); \ pr = mxGetPr(a); \ pi = mxGetPi(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } void* mxWrapGetP_single(const mxArray* a, const char* fmt, const char** e) { void* p = 0; #ifdef R2008OO mxArray* ap; #endif if (mxGetClassID(a) == mxSINGLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && *((float*)mxGetData(a)) == 0) return p; if (mxIsChar(a)) { char pbuf[128]; mxGetString(a, pbuf, sizeof(pbuf)); sscanf(pbuf, fmt, &p); } #ifdef R2008OO else if (ap = mxGetProperty(a, 0, "mwptr")) { return mxWrapGetP(ap, fmt, e); } #endif if (p == 0) *e = "Invalid pointer"; return p; } mxArray* mxWrapCreateP_single(void* p, const char* fmt) { if (p == 0) { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } else { char pbuf[128]; snprintf(pbuf, sizeof(pbuf), fmt, p); return mxCreateString(pbuf); } } mxArray* mxWrapStrncpy_single(const char* s) { if (s) { return mxCreateString(s); } else { mxArray* z = mxCreateNumericMatrix(1,1, mxSINGLE_CLASS, mxREAL); *((float*)mxGetData(z)) = 0; return z; } } float mxWrapGetScalar_single(const mxArray* a, const char** e) { if (!a || mxGetClassID(a) != mxSINGLE_CLASS || mxGetM(a)*mxGetN(a) != 1) { *e = "Invalid scalar argument"; return 0; } return *((float*)mxGetData(a)); } char* mxWrapGetString_single(const mxArray* a, const char** e) { char* s; mwSize slen; if (!a || (!mxIsChar(a) && mxGetM(a)*mxGetN(a) > 0)) { *e = "Invalid string argument, mxSINGLE_CLASS expected"; return NULL; } slen = mxGetM(a)*mxGetN(a) + 1; s = (char*) mxMalloc(slen); if (mxGetM(a)*mxGetN(a) == 0) *s = 0; else mxGetString(a, s, slen); return s; } #define mxWrapGetArrayDef_single(func, T) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* q; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ q = (float*) mxGetData(a); \ for (i = 0; i < arraylen; ++i) \ *p++ = (T) (*q++); \ return array; \ } #define mxWrapCopyDef_single(func, T) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* p = (float*) mxGetData(a); \ for (i = 0; i < n; ++i) \ *p++ = *q++; \ } #define mxWrapReturnDef_single(func, T) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* p; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxREAL); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxREAL);\ p = (float*) mxGetData(a); \ for (i = 0; i < m*n; ++i) \ *p++ = *q++; \ return a; \ } \ } #define mxWrapGetScalarZDef_single(func, T, ZT, setz) \ void func(T* z, const mxArray* a) \ { \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ setz(z, (ZT) *pr, (pi ? (ZT) *pi : (ZT) 0)); \ } #define mxWrapGetArrayZDef_single(func, T, ZT, setz) \ T* func(const mxArray* a, const char** e) \ { \ T* array; \ mwSize arraylen; \ mwIndex i; \ T* p; \ float* qr; \ float* qi; \ if (!a || mxGetClassID(a) != mxSINGLE_CLASS) { \ *e = "Invalid array argument, mxSINGLE_CLASS expected"; \ return 0; \ } \ arraylen = mxGetM(a)*mxGetN(a); \ array = (T*) mxMalloc(mxGetM(a)*mxGetN(a) * sizeof(T)); \ p = array; \ qr = (float*) mxGetData(a); \ qi = (float*) mxGetImagData(a); \ for (i = 0; i < arraylen; ++i) { \ ZT val_qr = *qr++; \ ZT val_qi = (qi ? (ZT) *qi++ : (ZT) 0); \ setz(p, val_qr, val_qi); \ ++p; \ } \ return array; \ } #define mxWrapCopyZDef_single(func, T, real, imag) \ void func(mxArray* a, const T* q, mwSize n) \ { \ mwIndex i; \ float* pr = (float*) mxGetData(a); \ float* pi = (float*) mxGetImagData(a); \ for (i = 0; i < n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ } #define mxWrapReturnZDef_single(func, T, real, imag) \ mxArray* func(const T* q, mwSize m, mwSize n) \ { \ mwIndex i; \ float* pr; \ float* pi; \ if (!q) { \ return mxCreateNumericMatrix(0,0, mxSINGLE_CLASS, mxCOMPLEX); \ } else { \ mxArray* a = mxCreateNumericMatrix(m,n, mxSINGLE_CLASS, mxCOMPLEX);\ pr = (float*) mxGetData(a); \ pi = (float*) mxGetImagData(a); \ for (i = 0; i < m*n; ++i) { \ *pr++ = real(*q); \ *pi++ = imag(*q); \ ++q; \ } \ return a; \ } \ } #endif #include #include struct Pair { Pair(double x, double y) { xy[0] = x; xy[1] = y; } double xy[2]; double x() { return xy[0]; } double y() { return xy[1]; } }; struct BadPair { double x; }; struct DerivedPair : public Pair { DerivedPair() : Pair(7,11) {} }; #include typedef std::complex cmplx; #define real_cmplx(z) (z).real() #define imag_cmplx(z) (z).imag() #define setz_cmplx(zp, r, i) *zp = cmplx(r,i) typedef unsigned char uchar; typedef unsigned long ulong; class Parent1 { public: Parent1(int data) : data1_(data) {} virtual ~Parent1() {} virtual int data1() { return data1_; } protected: int data1_; }; class Parent2 { public: Parent2(int data) : data2_(data) {} virtual ~Parent2() {} virtual int data2() { return data2_; } protected: int data2_; }; class Child : public Parent1, public Parent2 { public: Child() : Parent1(1), Parent2(2) {} virtual int data1() { return data1_ + 1; } virtual int data2() { return data2_ + 1; } int datas() { return data1_ + data2_; } }; class OuterClass { public: static int static_method() { return 123; } }; int literal_plus1(int x) { return x+1; } typedef unsigned char byte; void takes_double(double& x) {} void takes_float(float& x) {} void takes_long(long& x) {} void takes_int(int& x) {} void takes_char(char& x) {} void takes_ulong(unsigned long& x) {} void takes_uint(unsigned int& x) {} void takes_uchar(unsigned char& x) {} void takes_bool(bool& x) {} void takes_size_t(size_t& x) {} cmplx zsum(cmplx* zarray, int n) { cmplx sum(0); for (int i = 0; i < n; ++i) sum += zarray[i]; return sum; } Pair* null_pair() { return NULL; } int is_null(Pair* p) { return !p; } char* null_string() { return NULL; } int is_null(double* data) { return !data; } void test_null_obj(Pair& p) { } void test_bad_pair(Pair* p) { } Pair test_return_obj() { return Pair(1.5, 2.5); } double* test_return_array(Pair& p) { return p.xy; } double* test_return_array2(Pair& p) { return p.xy; } double test_return_scalar(double* xy) { return xy[0] + xy[1]; } cmplx test_return_zscalar(cmplx* xy) { return xy[0] + xy[1]; } const char* test_return_string() { return "Hello, world!"; } Pair* test_return_p_obj() { return new Pair(3, 5); } int* test_return_p_scalar(int* a, int* b) { return (*a > *b) ? a : b; } cmplx* test_return_p_zscalar(cmplx* a, cmplx* b) { return (a->real() > b->real()) ? a : b; } Pair& test_return_r_obj(Pair& p) { return p; } int& test_return_r_scalar(int& a, int& b) { return (a > b) ? a : b; } cmplx& test_return_r_zscalar(cmplx& a, cmplx& b) { return (a.real() > b.real()) ? a : b; } double test_input_obj(Pair p) { return p.xy[0] + p.xy[1]; } double test_input_array(double* xy) { return xy[0] + xy[1]; } double test_input_array2(double* xy) { return xy[0] + xy[1]; } cmplx test_input_zarray(cmplx* xy) { return xy[0] + xy[1]; } int test_input_scalar(int x) { return x+1; } cmplx test_input_zscalar(cmplx x) { return x+1.0; } int test_input_string(char* s) { return strlen(s); } double test_input_p_obj(Pair* p) { return p->xy[0] + p->xy[1]; } int test_input_p_scalar(int* x) { return *x+1; } cmplx test_input_p_zscalar(cmplx* x) { return *x+1.0; } double test_input_r_obj(Pair& p) { return p.xy[0] + p.xy[1]; } int test_input_r_scalar(int& x) { return x+1; } cmplx test_input_r_zscalar(cmplx& x) { return x+1.0; } void test_output_array(double* xy) { xy[0] = 1; xy[1] = 2; } void test_output_rarray(const double*& xy) { static double result[2] = {7, 11}; xy = result; } void test_output_rarray2(const double*& xy) { xy = NULL; } void test_output_zarray(cmplx* xy) { xy[0] = 1; xy[1] = 2; } void test_output_zarray2(cmplx* xy) { xy[0] = cmplx(1,3); xy[1] = 2; } void test_output_p_scalar(int* i) { *i = 202; } void test_output_p_zscalar(cmplx* z) { *z = cmplx(202,303); } void test_output_r_scalar(int& i) { i = 303; } void test_output_r_zscalar(cmplx& z) { z = cmplx(303,404); } void test_inout_array(double* xy) { xy[0] += 1; xy[1] += 1; } void test_inout_p_scalar(int* i) { *i += 202; } void test_inout_r_scalar(int& i) { i += 303; } #include double test_mx_input(const mxArray* x) { return *mxGetPr(x); } void test_mx_output(mxArray** x) { *x = mxCreateString("foobar"); } mxArray* test_mx_return() { mxArray* m = mxCreateDoubleMatrix(1,1, mxREAL); *mxGetPr(m) = 42; return m; } const int TEST_CONST = 42; int identity(int i) { return i; } struct my_struct_t { double x; double y; }; int my_struct_allocs = 0; int get_my_struct_allocs() { return my_struct_allocs; } my_struct_t* mxWrapGet_my_struct_t(const mxArray* a, const char** e) { // Note -- there really ought to be an error check here ++my_struct_allocs; my_struct_t* o = new my_struct_t; o->x = mxGetPr(a)[0]; o->y = mxGetPr(a)[1]; return o; } mxArray* mxWrapSet_my_struct_t(my_struct_t* o) { mxArray* a = mxCreateDoubleMatrix(2,1,mxREAL); mxGetPr(a)[0] = o->x; mxGetPr(a)[1] = o->y; return a; } my_struct_t* mxWrapAlloc_my_struct_t() { ++my_struct_allocs; return new my_struct_t; } void mxWrapFree_my_struct_t(my_struct_t* o) { --my_struct_allocs; delete o; } void unpack_struct(my_struct_t& o, double* xy) { xy[0] = o.x; xy[1] = o.y; } void pack_struct(my_struct_t& o, double* xy) { o.x = xy[0]; o.y = xy[1]; } void swap_struct(my_struct_t& o) { double tmp = o.x; o.x = o.y; o.y = tmp; } my_struct_t& rightmost(my_struct_t& p1, my_struct_t& p2) { return (p1.x >= p2.x) ? p1 : p2; } my_struct_t* add1(my_struct_t& o) { o.x += 1; o.y += 1; return &o; } /* Array copier definitions */ mxWrapGetArrayDef(mxWrapGetArray_bool, bool) mxWrapCopyDef (mxWrapCopy_bool, bool) mxWrapReturnDef (mxWrapReturn_bool, bool) mxWrapGetArrayDef_single(mxWrapGetArray_single_bool, bool) mxWrapCopyDef_single (mxWrapCopy_single_bool, bool) mxWrapReturnDef_single (mxWrapReturn_single_bool, bool) mxWrapGetArrayDef(mxWrapGetArray_byte, byte) mxWrapCopyDef (mxWrapCopy_byte, byte) mxWrapReturnDef (mxWrapReturn_byte, byte) mxWrapGetArrayDef_single(mxWrapGetArray_single_byte, byte) mxWrapCopyDef_single (mxWrapCopy_single_byte, byte) mxWrapReturnDef_single (mxWrapReturn_single_byte, byte) mxWrapGetArrayDef(mxWrapGetArray_char, char) mxWrapCopyDef (mxWrapCopy_char, char) mxWrapReturnDef (mxWrapReturn_char, char) mxWrapGetArrayDef_single(mxWrapGetArray_single_char, char) mxWrapCopyDef_single (mxWrapCopy_single_char, char) mxWrapReturnDef_single (mxWrapReturn_single_char, char) mxWrapGetArrayDef(mxWrapGetArray_double, double) mxWrapCopyDef (mxWrapCopy_double, double) mxWrapReturnDef (mxWrapReturn_double, double) mxWrapGetArrayDef_single(mxWrapGetArray_single_double, double) mxWrapCopyDef_single (mxWrapCopy_single_double, double) mxWrapReturnDef_single (mxWrapReturn_single_double, double) mxWrapGetArrayDef(mxWrapGetArray_float, float) mxWrapCopyDef (mxWrapCopy_float, float) mxWrapReturnDef (mxWrapReturn_float, float) mxWrapGetArrayDef_single(mxWrapGetArray_single_float, float) mxWrapCopyDef_single (mxWrapCopy_single_float, float) mxWrapReturnDef_single (mxWrapReturn_single_float, float) mxWrapGetArrayDef(mxWrapGetArray_int, int) mxWrapCopyDef (mxWrapCopy_int, int) mxWrapReturnDef (mxWrapReturn_int, int) mxWrapGetArrayDef_single(mxWrapGetArray_single_int, int) mxWrapCopyDef_single (mxWrapCopy_single_int, int) mxWrapReturnDef_single (mxWrapReturn_single_int, int) mxWrapGetArrayDef(mxWrapGetArray_long, long) mxWrapCopyDef (mxWrapCopy_long, long) mxWrapReturnDef (mxWrapReturn_long, long) mxWrapGetArrayDef_single(mxWrapGetArray_single_long, long) mxWrapCopyDef_single (mxWrapCopy_single_long, long) mxWrapReturnDef_single (mxWrapReturn_single_long, long) mxWrapGetArrayDef(mxWrapGetArray_ptrdiff_t, ptrdiff_t) mxWrapCopyDef (mxWrapCopy_ptrdiff_t, ptrdiff_t) mxWrapReturnDef (mxWrapReturn_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_ptrdiff_t, ptrdiff_t) mxWrapCopyDef_single (mxWrapCopy_single_ptrdiff_t, ptrdiff_t) mxWrapReturnDef_single (mxWrapReturn_single_ptrdiff_t, ptrdiff_t) mxWrapGetArrayDef(mxWrapGetArray_short, short) mxWrapCopyDef (mxWrapCopy_short, short) mxWrapReturnDef (mxWrapReturn_short, short) mxWrapGetArrayDef_single(mxWrapGetArray_single_short, short) mxWrapCopyDef_single (mxWrapCopy_single_short, short) mxWrapReturnDef_single (mxWrapReturn_single_short, short) mxWrapGetArrayDef(mxWrapGetArray_size_t, size_t) mxWrapCopyDef (mxWrapCopy_size_t, size_t) mxWrapReturnDef (mxWrapReturn_size_t, size_t) mxWrapGetArrayDef_single(mxWrapGetArray_single_size_t, size_t) mxWrapCopyDef_single (mxWrapCopy_single_size_t, size_t) mxWrapReturnDef_single (mxWrapReturn_single_size_t, size_t) mxWrapGetArrayDef(mxWrapGetArray_uchar, uchar) mxWrapCopyDef (mxWrapCopy_uchar, uchar) mxWrapReturnDef (mxWrapReturn_uchar, uchar) mxWrapGetArrayDef_single(mxWrapGetArray_single_uchar, uchar) mxWrapCopyDef_single (mxWrapCopy_single_uchar, uchar) mxWrapReturnDef_single (mxWrapReturn_single_uchar, uchar) mxWrapGetArrayDef(mxWrapGetArray_uint, uint) mxWrapCopyDef (mxWrapCopy_uint, uint) mxWrapReturnDef (mxWrapReturn_uint, uint) mxWrapGetArrayDef_single(mxWrapGetArray_single_uint, uint) mxWrapCopyDef_single (mxWrapCopy_single_uint, uint) mxWrapReturnDef_single (mxWrapReturn_single_uint, uint) mxWrapGetArrayDef(mxWrapGetArray_ulong, ulong) mxWrapCopyDef (mxWrapCopy_ulong, ulong) mxWrapReturnDef (mxWrapReturn_ulong, ulong) mxWrapGetArrayDef_single(mxWrapGetArray_single_ulong, ulong) mxWrapCopyDef_single (mxWrapCopy_single_ulong, ulong) mxWrapReturnDef_single (mxWrapReturn_single_ulong, ulong) mxWrapGetScalarZDef(mxWrapGetScalar_cmplx, cmplx, double, setz_cmplx) mxWrapGetArrayZDef (mxWrapGetArray_cmplx, cmplx, double, setz_cmplx) mxWrapCopyZDef (mxWrapCopy_cmplx, cmplx, real_cmplx, imag_cmplx) mxWrapReturnZDef (mxWrapReturn_cmplx, cmplx, real_cmplx, imag_cmplx) mxWrapGetScalarZDef_single(mxWrapGetScalar_single_cmplx, cmplx, double, setz_cmplx) mxWrapGetArrayZDef_single (mxWrapGetArray_single_cmplx, cmplx, double, setz_cmplx) mxWrapCopyZDef_single (mxWrapCopy_single_cmplx, cmplx, real_cmplx, imag_cmplx) mxWrapReturnZDef_single (mxWrapReturn_single_cmplx, cmplx, real_cmplx, imag_cmplx) Pair* mxWrapGetP_Pair(const mxArray* a, const char** e) { char pbuf[128]; if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && #if MX_HAS_INTERLEAVED_COMPLEX ((mxIsComplex(a) ? ((*mxGetComplexDoubles(a)).real == 0 && (*mxGetComplexDoubles(a)).imag == 0) : *mxGetDoubles(a) == 0)) #else *mxGetPr(a) == 0 #endif ) return NULL; if (!mxIsChar(a)) { #ifdef R2008OO mxArray* ap = mxGetProperty(a, 0, "mwptr"); if (ap) return mxWrapGetP_Pair(ap, e); #endif *e = "Invalid pointer"; return NULL; } mxGetString(a, pbuf, sizeof(pbuf)); Pair* p_Pair = NULL; sscanf(pbuf, "Pair:%p", &p_Pair); if (p_Pair) return p_Pair; DerivedPair* p_DerivedPair = NULL; sscanf(pbuf, "DerivedPair:%p", &p_DerivedPair); if (p_DerivedPair) return p_DerivedPair; *e = "Invalid pointer to Pair"; return NULL; } Parent1* mxWrapGetP_Parent1(const mxArray* a, const char** e) { char pbuf[128]; if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && #if MX_HAS_INTERLEAVED_COMPLEX ((mxIsComplex(a) ? ((*mxGetComplexDoubles(a)).real == 0 && (*mxGetComplexDoubles(a)).imag == 0) : *mxGetDoubles(a) == 0)) #else *mxGetPr(a) == 0 #endif ) return NULL; if (!mxIsChar(a)) { #ifdef R2008OO mxArray* ap = mxGetProperty(a, 0, "mwptr"); if (ap) return mxWrapGetP_Parent1(ap, e); #endif *e = "Invalid pointer"; return NULL; } mxGetString(a, pbuf, sizeof(pbuf)); Parent1* p_Parent1 = NULL; sscanf(pbuf, "Parent1:%p", &p_Parent1); if (p_Parent1) return p_Parent1; Child* p_Child = NULL; sscanf(pbuf, "Child:%p", &p_Child); if (p_Child) return p_Child; *e = "Invalid pointer to Parent1"; return NULL; } Parent2* mxWrapGetP_Parent2(const mxArray* a, const char** e) { char pbuf[128]; if (mxGetClassID(a) == mxDOUBLE_CLASS && mxGetM(a)*mxGetN(a) == 1 && #if MX_HAS_INTERLEAVED_COMPLEX ((mxIsComplex(a) ? ((*mxGetComplexDoubles(a)).real == 0 && (*mxGetComplexDoubles(a)).imag == 0) : *mxGetDoubles(a) == 0)) #else *mxGetPr(a) == 0 #endif ) return NULL; if (!mxIsChar(a)) { #ifdef R2008OO mxArray* ap = mxGetProperty(a, 0, "mwptr"); if (ap) return mxWrapGetP_Parent2(ap, e); #endif *e = "Invalid pointer"; return NULL; } mxGetString(a, pbuf, sizeof(pbuf)); Parent2* p_Parent2 = NULL; sscanf(pbuf, "Parent2:%p", &p_Parent2); if (p_Parent2) return p_Parent2; Child* p_Child = NULL; sscanf(pbuf, "Child:%p", &p_Child); if (p_Child) return p_Child; *e = "Invalid pointer to Parent2"; return NULL; } /* ---- test_transfers.mw: 81 ---- * Child* c = new(); */ static const char* stubids1_ = "c o Child* = new()"; void mexStub1(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Child* out0_=0; /* c */ if (mexprofrecord_) mexprofrecord_[1]++; out0_ = new Child(); plhs[0] = mxWrapCreateP(out0_, "Child:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 82 ---- * int d1 = c->Parent1.data1(); */ static const char* stubids2_ = "c o int = c->Parent1.data1()"; void mexStub2(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Parent1* in0_ =0; /* c */ int out0_; /* d1 */ in0_ = mxWrapGetP_Parent1(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[2]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->data1(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 83 ---- * int d2 = c->Parent2.data2(); */ static const char* stubids3_ = "c o int = c->Parent2.data2()"; void mexStub3(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Parent2* in0_ =0; /* c */ int out0_; /* d2 */ in0_ = mxWrapGetP_Parent2(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[3]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->data2(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 84 ---- * int dd = c->Child.datas(); */ static const char* stubids4_ = "c o int = c->Child.datas()"; void mexStub4(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Child* in0_ =0; /* c */ int out0_; /* dd */ in0_ = (Child*) mxWrapGetP(prhs[0], "Child:%p", &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[4]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->datas(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 97 ---- * int x = OuterClass::static_method(); */ static const char* stubids5_ = "c o int = OuterClass::static_method()"; void mexStub5(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int out0_; /* x */ if (mexprofrecord_) mexprofrecord_[5]++; out0_ = OuterClass::static_method(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 105 ---- * int y = literal_plus1(int 7); */ static const char* stubids6_ = "c o int = literal_plus1(c i int)"; void mexStub6(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* 7 */ int out0_; /* y */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[6]++; out0_ = literal_plus1(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 106 ---- * int l = strlen(cstring 'Test'); */ static const char* stubids7_ = "c o int = strlen(c i cstring)"; void mexStub7(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; char* in0_ =0; /* 'Test' */ int out0_; /* l */ in0_ = mxWrapGetString(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[7]++; out0_ = strlen(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 127 ---- * takes_double(double& x); */ static const char* stubids8_ = "takes_double(c i double&)"; void mexStub8(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (double) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[8]++; takes_double(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 128 ---- * takes_float(float& xs); */ static const char* stubids9_ = "takes_float(c i float&)"; void mexStub9(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; float in0_; /* xs */ if( mxGetClassID(prhs[0]) != mxSINGLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxSINGLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (float) mxWrapGetScalar_single(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[9]++; takes_float(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 129 ---- * takes_long(long& x); */ static const char* stubids10_ = "takes_long(c i long&)"; void mexStub10(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; long in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (long) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[10]++; takes_long(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 130 ---- * takes_int(int& x); */ static const char* stubids11_ = "takes_int(c i int&)"; void mexStub11(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[11]++; takes_int(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 131 ---- * takes_char(char& xc); */ static const char* stubids12_ = "takes_char(c i char&)"; void mexStub12(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; char in0_; /* xc */ if( mxGetClassID(prhs[0]) != mxCHAR_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxCHAR_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (char) mxWrapGetScalar_char(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[12]++; takes_char(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 132 ---- * takes_ulong(ulong& x); */ static const char* stubids13_ = "takes_ulong(c i ulong&)"; void mexStub13(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; ulong in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (ulong) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[13]++; takes_ulong(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 133 ---- * takes_uint(uint& x); */ static const char* stubids14_ = "takes_uint(c i uint&)"; void mexStub14(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; uint in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (uint) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[14]++; takes_uint(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 134 ---- * takes_uchar(uchar& x); */ static const char* stubids15_ = "takes_uchar(c i uchar&)"; void mexStub15(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; uchar in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (uchar) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[15]++; takes_uchar(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 135 ---- * takes_uchar(byte& x); */ static const char* stubids16_ = "takes_uchar(c i byte&)"; void mexStub16(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; byte in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (byte) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[16]++; takes_uchar(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 136 ---- * takes_bool(bool& x); */ static const char* stubids17_ = "takes_bool(c i bool&)"; void mexStub17(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; bool in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (bool) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[17]++; takes_bool(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 137 ---- * takes_size_t(size_t& x); */ static const char* stubids18_ = "takes_size_t(c i size_t&)"; void mexStub18(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; size_t in0_; /* x */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (size_t) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[18]++; takes_size_t(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 140 ---- * DerivedPair* dp = new(); */ static const char* stubids19_ = "c o DerivedPair* = new()"; void mexStub19(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; DerivedPair* out0_=0; /* dp */ if (mexprofrecord_) mexprofrecord_[19]++; out0_ = new DerivedPair(); plhs[0] = mxWrapCreateP(out0_, "DerivedPair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 141 ---- * double x = dp->Pair.x(); */ static const char* stubids20_ = "c o double = dp->Pair.x()"; void mexStub20(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* dp */ double out0_; /* x */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[20]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->x(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 156 ---- * cmplx result = zsum(cmplx[] zarray, int n); */ static const char* stubids21_ = "c o cmplx = zsum(c i cmplx[], c i int)"; void mexStub21(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx* in0_ =0; /* zarray */ int in1_; /* n */ cmplx out0_; /* result */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { in0_ = mxWrapGetArray_cmplx(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (int) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[21]++; out0_ = zsum(in0_, in1_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 164 ---- * Pair* p = null_pair(); */ static const char* stubids22_ = "c o Pair* = null_pair()"; void mexStub22(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* out0_=0; /* p */ if (mexprofrecord_) mexprofrecord_[22]++; out0_ = null_pair(); plhs[0] = mxWrapCreateP(out0_, "Pair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 168 ---- * int flag = is_null(Pair* p); */ static const char* stubids23_ = "c o int = is_null(c i Pair*)"; void mexStub23(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ int out0_; /* flag */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[23]++; out0_ = is_null(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 172 ---- * cstring s = null_string(); */ static const char* stubids24_ = "c o cstring = null_string()"; void mexStub24(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[24]++; plhs[0] = mxWrapStrncpy(null_string()); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 175 ---- * char* c = null_string(); */ static const char* stubids25_ = "c o char* = null_string()"; void mexStub25(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[25]++; plhs[0] = mxWrapReturn_char(null_string(), 1, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 180 ---- * int flag = is_null(double[] nil); */ static const char* stubids26_ = "c o int = is_null(c i double[])"; void mexStub26(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* nil */ int out0_; /* flag */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; #if MX_HAS_INTERLEAVED_COMPLEX in0_ = mxGetDoubles(prhs[0]); #else in0_ = mxGetPr(prhs[0]); #endif } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[26]++; out0_ = is_null(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 183 ---- * char[1] ca = null_string(); */ static const char* stubids27_ = "c o char[x] = null_string()"; void mexStub27(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; mwSize dim0_; /* 1 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mexprofrecord_) mexprofrecord_[27]++; plhs[0] = mxWrapReturn_char(null_string(), dim0_, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 188 ---- * test_null_obj(Pair p); */ static const char* stubids28_ = "test_null_obj(c i Pair)"; void mexStub28(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[28]++; test_null_obj(*in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 192 ---- * test_null_obj(Pair& p); */ static const char* stubids29_ = "test_null_obj(c i Pair&)"; void mexStub29(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[29]++; test_null_obj(*in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 197 ---- * double x = p->Pair.x(); * Also at test_transfers.mw: 216 */ static const char* stubids30_ = "c o double = p->Pair.x()"; void mexStub30(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ double out0_; /* x */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[30]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->x(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 201 ---- * BadPair* bp = new(); */ static const char* stubids31_ = "c o BadPair* = new()"; void mexStub31(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; BadPair* out0_=0; /* bp */ if (mexprofrecord_) mexprofrecord_[31]++; out0_ = new BadPair(); plhs[0] = mxWrapCreateP(out0_, "BadPair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 204 ---- * test_bad_pair(Pair* bp); */ static const char* stubids32_ = "test_bad_pair(c i Pair*)"; void mexStub32(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* bp */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[32]++; test_bad_pair(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 207 ---- * delete(BadPair* bp); */ static const char* stubids33_ = "delete(c i BadPair*)"; void mexStub33(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; BadPair* in0_ =0; /* bp */ in0_ = (BadPair*) mxWrapGetP(prhs[0], "BadPair:%p", &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[33]++; delete(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 215 ---- * Pair* p = new(double x, double y); * Also at test_transfers.mw: 296 */ static const char* stubids34_ = "c o Pair* = new(c i double, c i double)"; void mexStub34(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double in0_; /* x */ double in1_; /* y */ Pair* out0_=0; /* p */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (double) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (double) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[34]++; out0_ = new Pair(in0_, in1_); plhs[0] = mxWrapCreateP(out0_, "Pair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 217 ---- * double yy = p->Pair.y(); */ static const char* stubids36_ = "c o double = p->Pair.y()"; void mexStub36(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ double out0_; /* yy */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[36]++; if (!in0_) { mw_err_txt_ = "Cannot dispatch to NULL"; goto mw_err_label; } out0_ = in0_->y(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 218 ---- * delete(Pair* p); * Also at test_transfers.mw: 288 */ static const char* stubids37_ = "delete(c i Pair*)"; void mexStub37(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[37]++; delete(in0_); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 227 ---- * Pair p1 = test_return_obj(); */ static const char* stubids38_ = "c o Pair = test_return_obj()"; void mexStub38(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* out0_=0; /* p1 */ if (mexprofrecord_) mexprofrecord_[38]++; out0_ = new Pair(test_return_obj()); plhs[0] = mxWrapCreateP(out0_, "Pair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 231 ---- * double[2] xy = test_return_array(Pair& p1); * Also at test_transfers.mw: 255 */ static const char* stubids39_ = "c o double[x] = test_return_array(c i Pair&)"; void mexStub39(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p1 */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p1 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[39]++; plhs[0] = mxWrapReturn_double(test_return_array(*in0_), dim1_, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 235 ---- * double[2] xy = test_return_array2(Pair& p1); */ static const char* stubids40_ = "c o double[x] = test_return_array2(c i Pair&)"; void mexStub40(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p1 */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p1 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[40]++; plhs[0] = mxWrapReturn_double(test_return_array2(*in0_), dim1_, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 239 ---- * double sum = test_return_scalar(double[] xy); */ static const char* stubids41_ = "c o double = test_return_scalar(c i double[])"; void mexStub41(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* xy */ double out0_; /* sum */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; #if MX_HAS_INTERLEAVED_COMPLEX in0_ = mxGetDoubles(prhs[0]); #else in0_ = mxGetPr(prhs[0]); #endif } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[41]++; out0_ = test_return_scalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 244 ---- * cmplx sum1 = test_return_zscalar(cmplx[] xy); * Also at test_transfers.mw: 245 */ static const char* stubids42_ = "c o cmplx = test_return_zscalar(c i cmplx[])"; void mexStub42(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx* in0_ =0; /* xy */ cmplx out0_; /* sum1 */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { in0_ = mxWrapGetArray_cmplx(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[42]++; out0_ = test_return_zscalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 250 ---- * cstring s = test_return_string(); */ static const char* stubids44_ = "c o cstring = test_return_string()"; void mexStub44(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[44]++; plhs[0] = mxWrapStrncpy(test_return_string()); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 254 ---- * Pair* p2 = test_return_p_obj(); */ static const char* stubids45_ = "c o Pair* = test_return_p_obj()"; void mexStub45(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* out0_=0; /* p2 */ if (mexprofrecord_) mexprofrecord_[45]++; out0_ = test_return_p_obj(); plhs[0] = mxWrapCreateP(out0_, "Pair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 260 ---- * int* z1 = test_return_p_scalar(int* a, int* b); */ static const char* stubids47_ = "c o int* = test_return_p_scalar(c i int*, c i int*)"; void mexStub47(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* a */ int in1_; /* b */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (int) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[47]++; plhs[0] = mxWrapReturn_int(test_return_p_scalar(&in0_, &in1_), 1, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 267 ---- * cmplx* z1 = test_return_p_zscalar(cmplx* a, cmplx* b); * Also at test_transfers.mw: 268 */ static const char* stubids48_ = "c o cmplx* = test_return_p_zscalar(c i cmplx*, c i cmplx*)"; void mexStub48(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx in0_; /* a */ cmplx in1_; /* b */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in0_, prhs[0]); if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in1_, prhs[1]); if (mexprofrecord_) mexprofrecord_[48]++; plhs[0] = mxWrapReturn_cmplx(test_return_p_zscalar(&in0_, &in1_), 1, 1); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 273 ---- * Pair& p2c = test_return_r_obj(Pair& p2); */ static const char* stubids50_ = "c o Pair& = test_return_r_obj(c i Pair&)"; void mexStub50(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p2 */ Pair* out0_=0; /* p2c */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p2 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[50]++; out0_ = &(test_return_r_obj(*in0_)); plhs[0] = mxWrapCreateP(out0_, "Pair:%p"); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 277 ---- * int& z2 = test_return_r_scalar(int& a, int& b); */ static const char* stubids51_ = "c o int& = test_return_r_scalar(c i int&, c i int&)"; void mexStub51(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* a */ int in1_; /* b */ int out0_; /* z2 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in1_ = (int) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[51]++; out0_ = test_return_r_scalar(in0_, in1_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 283 ---- * cmplx& z2 = test_return_r_zscalar(cmplx& a, cmplx& b); * Also at test_transfers.mw: 284 */ static const char* stubids52_ = "c o cmplx& = test_return_r_zscalar(c i cmplx&, c i cmplx&)"; void mexStub52(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx in0_; /* a */ cmplx in1_; /* b */ cmplx out0_; /* z2 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in0_, prhs[0]); if( mxGetClassID(prhs[1]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in1_, prhs[1]); if (mexprofrecord_) mexprofrecord_[52]++; out0_ = test_return_r_zscalar(in0_, in1_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 298 ---- * double sum = test_input_obj(Pair p); */ static const char* stubids57_ = "c o double = test_input_obj(c i Pair)"; void mexStub57(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ double out0_; /* sum */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[57]++; out0_ = test_input_obj(*in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 303 ---- * double sum = test_input_array(double[2] xy); */ static const char* stubids58_ = "c o double = test_input_array(c i double[x])"; void mexStub58(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* xy */ double out0_; /* sum */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mxGetM(prhs[0])*mxGetN(prhs[0]) != dim1_) { mw_err_txt_ = "Bad argument size: xy"; goto mw_err_label; } if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; #if MX_HAS_INTERLEAVED_COMPLEX in0_ = mxGetDoubles(prhs[0]); #else in0_ = mxGetPr(prhs[0]); #endif } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[58]++; out0_ = test_input_array(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 307 ---- * double sum = test_input_array2(double[2] xy); */ static const char* stubids59_ = "c o double = test_input_array2(c i double[x])"; void mexStub59(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* xy */ double out0_; /* sum */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mxGetM(prhs[0])*mxGetN(prhs[0]) != dim1_) { mw_err_txt_ = "Bad argument size: xy"; goto mw_err_label; } if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; #if MX_HAS_INTERLEAVED_COMPLEX in0_ = mxGetDoubles(prhs[0]); #else in0_ = mxGetPr(prhs[0]); #endif } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[59]++; out0_ = test_input_array2(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 312 ---- * cmplx sum = test_input_zarray(cmplx[2] xy); * Also at test_transfers.mw: 313 */ static const char* stubids60_ = "c o cmplx = test_input_zarray(c i cmplx[x])"; void mexStub60(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx* in0_ =0; /* xy */ cmplx out0_; /* sum */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); if (mxGetM(prhs[0])*mxGetN(prhs[0]) != dim1_) { mw_err_txt_ = "Bad argument size: xy"; goto mw_err_label; } if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { in0_ = mxWrapGetArray_cmplx(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[60]++; out0_ = test_input_zarray(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 318 ---- * int xp1 = test_input_scalar(int x); */ static const char* stubids62_ = "c o int = test_input_scalar(c i int)"; void mexStub62(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* x */ int out0_; /* xp1 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[62]++; out0_ = test_input_scalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 323 ---- * cmplx xp1 = test_input_zscalar(cmplx x); * Also at test_transfers.mw: 324 */ static const char* stubids63_ = "c o cmplx = test_input_zscalar(c i cmplx)"; void mexStub63(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx in0_; /* x */ cmplx out0_; /* xp1 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in0_, prhs[0]); if (mexprofrecord_) mexprofrecord_[63]++; out0_ = test_input_zscalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 330 ---- * int msglen = test_input_string(cstring msg); */ static const char* stubids65_ = "c o int = test_input_string(c i cstring)"; void mexStub65(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; char* in0_ =0; /* msg */ int out0_; /* msglen */ in0_ = mxWrapGetString(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[65]++; out0_ = test_input_string(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 334 ---- * double sum2 = test_input_p_obj(Pair* p); */ static const char* stubids66_ = "c o double = test_input_p_obj(c i Pair*)"; void mexStub66(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ double out0_; /* sum2 */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[66]++; out0_ = test_input_p_obj(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 338 ---- * int xp1b = test_input_p_scalar(int* x); */ static const char* stubids67_ = "c o int = test_input_p_scalar(c i int*)"; void mexStub67(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* x */ int out0_; /* xp1b */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[67]++; out0_ = test_input_p_scalar(&in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 342 ---- * cmplx xp1b = test_input_p_zscalar(cmplx* x); * Also at test_transfers.mw: 343 */ static const char* stubids68_ = "c o cmplx = test_input_p_zscalar(c i cmplx*)"; void mexStub68(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx in0_; /* x */ cmplx out0_; /* xp1b */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in0_, prhs[0]); if (mexprofrecord_) mexprofrecord_[68]++; out0_ = test_input_p_zscalar(&in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 348 ---- * double sum3 = test_input_r_obj(Pair& p); */ static const char* stubids70_ = "c o double = test_input_r_obj(c i Pair&)"; void mexStub70(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; Pair* in0_ =0; /* p */ double out0_; /* sum3 */ in0_ = mxWrapGetP_Pair(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument p cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[70]++; out0_ = test_input_r_obj(*in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 352 ---- * int xp1c = test_input_r_scalar(int& x); */ static const char* stubids71_ = "c o int = test_input_r_scalar(c i int&)"; void mexStub71(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* x */ int out0_; /* xp1c */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[71]++; out0_ = test_input_r_scalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 356 ---- * cmplx xp1c = test_input_r_zscalar(cmplx& x); * Also at test_transfers.mw: 357 */ static const char* stubids72_ = "c o cmplx = test_input_r_zscalar(c i cmplx&)"; void mexStub72(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx in0_; /* x */ cmplx out0_; /* xp1c */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; mxWrapGetScalar_cmplx(&in0_, prhs[0]); if (mexprofrecord_) mexprofrecord_[72]++; out0_ = test_input_r_zscalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 368 ---- * test_output_array(output double[2] xy); */ static const char* stubids75_ = "test_output_array(c o double[x])"; void mexStub75(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* out0_=0; /* xy */ mwSize dim0_; /* 2 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); out0_ = (double*) mxMalloc(dim0_*sizeof(double)); if (mexprofrecord_) mexprofrecord_[75]++; test_output_array(out0_); plhs[0] = mxCreateDoubleMatrix(dim0_, 1, mxREAL); mxWrapCopy_double(plhs[0], out0_, dim0_); mw_err_label: if (out0_) mxFree(out0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 375 ---- * test_output_rarray(output doubler xyr); */ static const char* stubids76_ = "test_output_rarray(c o doubler)"; void mexStub76(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; const double* out0_; /* xyr */ mwSize dim0_; /* 2 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); out0_ = (double*) NULL; if (mexprofrecord_) mexprofrecord_[76]++; test_output_rarray(out0_); if (out0_ == NULL) { plhs[0] = mxCreateDoubleMatrix(0,0, mxREAL); } else { plhs[0] = mxCreateDoubleMatrix(dim0_, 1, mxREAL); mxWrapCopy_double(plhs[0], out0_, dim0_); } mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 379 ---- * test_output_rarray2(output doubler xyr2); */ static const char* stubids77_ = "test_output_rarray2(c o doubler)"; void mexStub77(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; const double* out0_; /* xyr2 */ mwSize dim0_; /* 2 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); out0_ = (double*) NULL; if (mexprofrecord_) mexprofrecord_[77]++; test_output_rarray2(out0_); if (out0_ == NULL) { plhs[0] = mxCreateDoubleMatrix(0,0, mxREAL); } else { plhs[0] = mxCreateDoubleMatrix(dim0_, 1, mxREAL); mxWrapCopy_double(plhs[0], out0_, dim0_); } mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 384 ---- * test_output_zarray(output cmplx[2] xy); */ static const char* stubids78_ = "test_output_zarray(c o cmplx[x])"; void mexStub78(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx* out0_=0; /* xy */ mwSize dim0_; /* 2 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); out0_ = (cmplx*) mxMalloc(dim0_*sizeof(cmplx)); if (mexprofrecord_) mexprofrecord_[78]++; test_output_zarray(out0_); plhs[0] = mxCreateDoubleMatrix(dim0_, 1, mxCOMPLEX); mxWrapCopy_cmplx(plhs[0], out0_, dim0_); mw_err_label: if (out0_) mxFree(out0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 385 ---- * test_output_zarray2(output cmplx[2] xy_z); */ static const char* stubids79_ = "test_output_zarray2(c o cmplx[x])"; void mexStub79(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx* out0_=0; /* xy_z */ mwSize dim0_; /* 2 */ dim0_ = (mwSize) mxWrapGetScalar(prhs[0], &mw_err_txt_); out0_ = (cmplx*) mxMalloc(dim0_*sizeof(cmplx)); if (mexprofrecord_) mexprofrecord_[79]++; test_output_zarray2(out0_); plhs[0] = mxCreateDoubleMatrix(dim0_, 1, mxCOMPLEX); mxWrapCopy_cmplx(plhs[0], out0_, dim0_); mw_err_label: if (out0_) mxFree(out0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 390 ---- * snprintf(output cstring[128] buf, int 128, cstring fmt, int i); */ static const char* stubids80_ = "snprintf(c o cstring[x], c i int, c i cstring, c i int)"; void mexStub80(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* 128 */ char* in1_ =0; /* fmt */ int in2_; /* i */ char* out0_=0; /* buf */ mwSize dim3_; /* 128 */ dim3_ = (mwSize) mxWrapGetScalar(prhs[3], &mw_err_txt_); if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; in1_ = mxWrapGetString(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if( mxGetClassID(prhs[2]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in2_ = (int) mxWrapGetScalar(prhs[2], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; out0_ = (char*) mxMalloc(dim3_*sizeof(char)); if (mexprofrecord_) mexprofrecord_[80]++; snprintf(out0_, in0_, in1_, in2_); plhs[0] = mxCreateString(out0_); mw_err_label: if (out0_) mxFree(out0_); if (in1_) mxFree(in1_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 394 ---- * test_output_p_scalar(output int* i2); */ static const char* stubids81_ = "test_output_p_scalar(c o int*)"; void mexStub81(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int out0_; /* i2 */ if (mexprofrecord_) mexprofrecord_[81]++; test_output_p_scalar(&out0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 398 ---- * test_output_p_zscalar(output cmplx* z2); */ static const char* stubids82_ = "test_output_p_zscalar(c o cmplx*)"; void mexStub82(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx out0_; /* z2 */ if (mexprofrecord_) mexprofrecord_[82]++; test_output_p_zscalar(&out0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 402 ---- * test_output_r_scalar(output int& i3); */ static const char* stubids83_ = "test_output_r_scalar(c o int&)"; void mexStub83(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int out0_; /* i3 */ if (mexprofrecord_) mexprofrecord_[83]++; test_output_r_scalar(out0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 406 ---- * test_output_r_zscalar(output cmplx& z3); */ static const char* stubids84_ = "test_output_r_zscalar(c o cmplx&)"; void mexStub84(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; cmplx out0_; /* z3 */ if (mexprofrecord_) mexprofrecord_[84]++; test_output_r_zscalar(out0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); mxGetComplexDoubles(plhs[0])->real = real_cmplx(out0_); mxGetComplexDoubles(plhs[0])->imag = imag_cmplx(out0_); #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX); *mxGetPr(plhs[0]) = real_cmplx(out0_); *mxGetPi(plhs[0]) = imag_cmplx(out0_); #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 415 ---- * test_inout_array(inout double[] xy); */ static const char* stubids85_ = "test_inout_array(c io double[])"; void mexStub85(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* xy */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { in0_ = mxWrapGetArray_double(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; } else in0_ = NULL; if (mexprofrecord_) mexprofrecord_[85]++; test_inout_array(in0_); plhs[0] = mxCreateDoubleMatrix(mxGetM(prhs[0]), mxGetN(prhs[0]), mxREAL); mxWrapCopy_double(plhs[0], in0_, mxGetM(prhs[0])*mxGetN(prhs[0])); mw_err_label: if (in0_) mxFree(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 420 ---- * strcat(inout cstring[128] s1, cstring s2); */ static const char* stubids86_ = "strcat(c io cstring[x], c i cstring)"; void mexStub86(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; char* in0_ =0; /* s1 */ char* in1_ =0; /* s2 */ mwSize dim2_; /* 128 */ dim2_ = (mwSize) mxWrapGetScalar(prhs[2], &mw_err_txt_); in0_ = (char*) mxMalloc(dim2_*sizeof(char)); if (mxGetString(prhs[0], in0_, dim2_) != 0) { mw_err_txt_ = "Invalid string argument"; goto mw_err_label; } in1_ = mxWrapGetString(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[86]++; strcat(in0_, in1_); plhs[0] = mxCreateString(in0_); mw_err_label: if (in0_) mxFree(in0_); if (in1_) mxFree(in1_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 425 ---- * test_inout_p_scalar(inout int* i1); */ static const char* stubids87_ = "test_inout_p_scalar(c io int*)"; void mexStub87(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* i1 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[87]++; test_inout_p_scalar(&in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = in0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = in0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 430 ---- * test_inout_r_scalar(inout int& i2); */ static const char* stubids88_ = "test_inout_r_scalar(c io int&)"; void mexStub88(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int in0_; /* i2 */ if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid scalar argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; in0_ = (int) mxWrapGetScalar(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (mexprofrecord_) mexprofrecord_[88]++; test_inout_r_scalar(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = in0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = in0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 441 ---- * double out1 = test_mx_input(mxArray in1); */ static const char* stubids89_ = "c o double = test_mx_input(c i mxArray)"; void mexStub89(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; const mxArray* in0_; /* in1 */ double out0_; /* out1 */ in0_ = prhs[0]; if (mexprofrecord_) mexprofrecord_[89]++; out0_ = test_mx_input(in0_); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 448 ---- * test_mx_output(output mxArray out2); */ static const char* stubids90_ = "test_mx_output(c o mxArray)"; void mexStub90(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[90]++; test_mx_output(plhs+0); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 457 ---- * mxArray out3 = test_mx_return(); */ static const char* stubids91_ = "c o mxArray = test_mx_return()"; void mexStub91(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; if (mexprofrecord_) mexprofrecord_[91]++; plhs[0] = test_mx_return(); mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 466 ---- * int result = identity(const TEST_CONST); * Also at test_transfers.mw: 468 */ static const char* stubids92_ = "c o int = identity(c i const TEST_CONST)"; void mexStub92(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int out0_; /* result */ if (mexprofrecord_) mexprofrecord_[92]++; out0_ = identity(TEST_CONST); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 554 ---- * unpack_struct(my_struct_t& xy1, output double[2] xy2); */ static const char* stubids94_ = "unpack_struct(c i my_struct_t&, c o double[x])"; void mexStub94(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; my_struct_t* in0_ =0; /* xy1 */ double* out0_=0; /* xy2 */ mwSize dim1_; /* 2 */ dim1_ = (mwSize) mxWrapGetScalar(prhs[1], &mw_err_txt_); in0_ = mxWrapGet_my_struct_t(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument xy1 cannot be null"; goto mw_err_label; } out0_ = (double*) mxMalloc(dim1_*sizeof(double)); if (mexprofrecord_) mexprofrecord_[94]++; unpack_struct(*in0_, out0_); plhs[0] = mxCreateDoubleMatrix(dim1_, 1, mxREAL); mxWrapCopy_double(plhs[0], out0_, dim1_); mw_err_label: if (in0_) mxWrapFree_my_struct_t(in0_); if (out0_) mxFree(out0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 557 ---- * pack_struct(output my_struct_t xy3, double[] xy1); */ static const char* stubids95_ = "pack_struct(c o my_struct_t, c i double[])"; void mexStub95(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; double* in0_ =0; /* xy1 */ my_struct_t* out0_=0; /* xy3 */ if (mxGetM(prhs[0])*mxGetN(prhs[0]) != 0) { if( mxGetClassID(prhs[0]) != mxDOUBLE_CLASS ) mw_err_txt_ = "Invalid array argument, mxDOUBLE_CLASS expected"; if (mw_err_txt_) goto mw_err_label; #if MX_HAS_INTERLEAVED_COMPLEX in0_ = mxGetDoubles(prhs[0]); #else in0_ = mxGetPr(prhs[0]); #endif } else in0_ = NULL; out0_ = mxWrapAlloc_my_struct_t(); if (mexprofrecord_) mexprofrecord_[95]++; pack_struct(*out0_, in0_); plhs[0] = mxWrapSet_my_struct_t(out0_); mw_err_label: if (out0_) mxWrapFree_my_struct_t(out0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 561 ---- * swap_struct(inout my_struct_t xy4); */ static const char* stubids96_ = "swap_struct(c io my_struct_t)"; void mexStub96(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; my_struct_t* in0_ =0; /* xy4 */ in0_ = mxWrapGet_my_struct_t(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument xy4 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[96]++; swap_struct(*in0_); plhs[0] = mxWrapSet_my_struct_t(in0_); mw_err_label: if (in0_) mxWrapFree_my_struct_t(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 564 ---- * my_struct_t& result = rightmost(my_struct_t& xy1, my_struct_t& xy4); */ static const char* stubids97_ = "c o my_struct_t& = rightmost(c i my_struct_t&, c i my_struct_t&)"; void mexStub97(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; my_struct_t* in0_ =0; /* xy1 */ my_struct_t* in1_ =0; /* xy4 */ my_struct_t* out0_=0; /* result */ in0_ = mxWrapGet_my_struct_t(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; in1_ = mxWrapGet_my_struct_t(prhs[1], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument xy1 cannot be null"; goto mw_err_label; } if (!in1_) { mw_err_txt_ = "Argument xy4 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[97]++; plhs[0] = mxWrapSet_my_struct_t(&(rightmost(*in0_, *in1_))); mw_err_label: if (in0_) mxWrapFree_my_struct_t(in0_); if (in1_) mxWrapFree_my_struct_t(in1_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 567 ---- * my_struct_t* xy5 = add1(my_struct_t& xy4); */ static const char* stubids98_ = "c o my_struct_t* = add1(c i my_struct_t&)"; void mexStub98(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; my_struct_t* in0_ =0; /* xy4 */ my_struct_t* out0_=0; /* xy5 */ in0_ = mxWrapGet_my_struct_t(prhs[0], &mw_err_txt_); if (mw_err_txt_) goto mw_err_label; if (!in0_) { mw_err_txt_ = "Argument xy4 cannot be null"; goto mw_err_label; } if (mexprofrecord_) mexprofrecord_[98]++; plhs[0] = mxWrapSet_my_struct_t(add1(*in0_)); mw_err_label: if (in0_) mxWrapFree_my_struct_t(in0_); if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } /* ---- test_transfers.mw: 570 ---- * int alloc_count = get_my_struct_allocs(); */ static const char* stubids99_ = "c o int = get_my_struct_allocs()"; void mexStub99(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { const char* mw_err_txt_ = 0; int out0_; /* alloc_count */ if (mexprofrecord_) mexprofrecord_[99]++; out0_ = get_my_struct_allocs(); #if MX_HAS_INTERLEAVED_COMPLEX plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetDoubles(plhs[0]) = out0_; #else plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL); *mxGetPr(plhs[0]) = out0_; #endif mw_err_label: if (mw_err_txt_) mexErrMsgTxt(mw_err_txt_); } typedef void (*mwStubFunc_t)(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]); static mwStubFunc_t mwStubs_[] = { NULL, mexStub1, mexStub2, mexStub3, mexStub4, mexStub5, mexStub6, mexStub7, mexStub8, mexStub9, mexStub10, mexStub11, mexStub12, mexStub13, mexStub14, mexStub15, mexStub16, mexStub17, mexStub18, mexStub19, mexStub20, mexStub21, mexStub22, mexStub23, mexStub24, mexStub25, mexStub26, mexStub27, mexStub28, mexStub29, mexStub30, mexStub31, mexStub32, mexStub33, mexStub34, mexStub30, mexStub36, mexStub37, mexStub38, mexStub39, mexStub40, mexStub41, mexStub42, mexStub42, mexStub44, mexStub45, mexStub39, mexStub47, mexStub48, mexStub48, mexStub50, mexStub51, mexStub52, mexStub52, mexStub37, mexStub37, mexStub34, mexStub57, mexStub58, mexStub59, mexStub60, mexStub60, mexStub62, mexStub63, mexStub63, mexStub65, mexStub66, mexStub67, mexStub68, mexStub68, mexStub70, mexStub71, mexStub72, mexStub72, mexStub37, mexStub75, mexStub76, mexStub77, mexStub78, mexStub79, mexStub80, mexStub81, mexStub82, mexStub83, mexStub84, mexStub85, mexStub86, mexStub87, mexStub88, mexStub89, mexStub90, mexStub91, mexStub92, mexStub92, mexStub94, mexStub95, mexStub96, mexStub97, mexStub98, mexStub99 }; static int mwNumStubs_ = 99; /* ---- */ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { if (nrhs == 0) { mexPrintf("Mex function installed\n"); return; } /* Fast path: integer stub ID */ if (!mxIsChar(prhs[0])) { int stub_id = (int) mxGetScalar(prhs[0]); if (stub_id > 0 && stub_id <= mwNumStubs_ && mwStubs_[stub_id]) mwStubs_[stub_id](nlhs, plhs, nrhs-1, prhs+1); else mexErrMsgTxt("Unknown function ID"); return; } char id[1024]; if (mxGetString(prhs[0], id, sizeof(id)) != 0) mexErrMsgTxt("Identifier should be a string"); else if (strcmp(id, stubids1_) == 0) mexStub1(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids2_) == 0) mexStub2(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids3_) == 0) mexStub3(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids4_) == 0) mexStub4(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids5_) == 0) mexStub5(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids6_) == 0) mexStub6(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids7_) == 0) mexStub7(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids8_) == 0) mexStub8(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids9_) == 0) mexStub9(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids10_) == 0) mexStub10(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids11_) == 0) mexStub11(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids12_) == 0) mexStub12(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids13_) == 0) mexStub13(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids14_) == 0) mexStub14(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids15_) == 0) mexStub15(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids16_) == 0) mexStub16(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids17_) == 0) mexStub17(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids18_) == 0) mexStub18(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids19_) == 0) mexStub19(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids20_) == 0) mexStub20(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids21_) == 0) mexStub21(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids22_) == 0) mexStub22(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids23_) == 0) mexStub23(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids24_) == 0) mexStub24(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids25_) == 0) mexStub25(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids26_) == 0) mexStub26(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids27_) == 0) mexStub27(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids28_) == 0) mexStub28(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids29_) == 0) mexStub29(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids30_) == 0) mexStub30(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids31_) == 0) mexStub31(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids32_) == 0) mexStub32(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids33_) == 0) mexStub33(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids34_) == 0) mexStub34(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids36_) == 0) mexStub36(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids37_) == 0) mexStub37(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids38_) == 0) mexStub38(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids39_) == 0) mexStub39(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids40_) == 0) mexStub40(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids41_) == 0) mexStub41(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids42_) == 0) mexStub42(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids44_) == 0) mexStub44(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids45_) == 0) mexStub45(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids47_) == 0) mexStub47(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids48_) == 0) mexStub48(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids50_) == 0) mexStub50(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids51_) == 0) mexStub51(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids52_) == 0) mexStub52(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids57_) == 0) mexStub57(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids58_) == 0) mexStub58(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids59_) == 0) mexStub59(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids60_) == 0) mexStub60(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids62_) == 0) mexStub62(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids63_) == 0) mexStub63(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids65_) == 0) mexStub65(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids66_) == 0) mexStub66(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids67_) == 0) mexStub67(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids68_) == 0) mexStub68(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids70_) == 0) mexStub70(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids71_) == 0) mexStub71(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids72_) == 0) mexStub72(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids75_) == 0) mexStub75(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids76_) == 0) mexStub76(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids77_) == 0) mexStub77(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids78_) == 0) mexStub78(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids79_) == 0) mexStub79(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids80_) == 0) mexStub80(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids81_) == 0) mexStub81(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids82_) == 0) mexStub82(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids83_) == 0) mexStub83(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids84_) == 0) mexStub84(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids85_) == 0) mexStub85(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids86_) == 0) mexStub86(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids87_) == 0) mexStub87(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids88_) == 0) mexStub88(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids89_) == 0) mexStub89(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids90_) == 0) mexStub90(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids91_) == 0) mexStub91(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids92_) == 0) mexStub92(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids94_) == 0) mexStub94(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids95_) == 0) mexStub95(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids96_) == 0) mexStub96(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids97_) == 0) mexStub97(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids98_) == 0) mexStub98(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, stubids99_) == 0) mexStub99(nlhs,plhs, nrhs-1,prhs+1); else if (strcmp(id, "*profile on*") == 0) { if (!mexprofrecord_) { mexprofrecord_ = (int*) malloc(100 * sizeof(int)); mexLock(); } memset(mexprofrecord_, 0, 100 * sizeof(int)); } else if (strcmp(id, "*profile off*") == 0) { if (mexprofrecord_) { free(mexprofrecord_); mexUnlock(); } mexprofrecord_ = NULL; } else if (strcmp(id, "*profile report*") == 0) { if (!mexprofrecord_) mexPrintf("Profiler inactive\n"); mexPrintf("%d calls to test_transfers.mw:81\n", mexprofrecord_[1]); mexPrintf("%d calls to test_transfers.mw:82\n", mexprofrecord_[2]); mexPrintf("%d calls to test_transfers.mw:83\n", mexprofrecord_[3]); mexPrintf("%d calls to test_transfers.mw:84\n", mexprofrecord_[4]); mexPrintf("%d calls to test_transfers.mw:97\n", mexprofrecord_[5]); mexPrintf("%d calls to test_transfers.mw:105\n", mexprofrecord_[6]); mexPrintf("%d calls to test_transfers.mw:106\n", mexprofrecord_[7]); mexPrintf("%d calls to test_transfers.mw:127\n", mexprofrecord_[8]); mexPrintf("%d calls to test_transfers.mw:128\n", mexprofrecord_[9]); mexPrintf("%d calls to test_transfers.mw:129\n", mexprofrecord_[10]); mexPrintf("%d calls to test_transfers.mw:130\n", mexprofrecord_[11]); mexPrintf("%d calls to test_transfers.mw:131\n", mexprofrecord_[12]); mexPrintf("%d calls to test_transfers.mw:132\n", mexprofrecord_[13]); mexPrintf("%d calls to test_transfers.mw:133\n", mexprofrecord_[14]); mexPrintf("%d calls to test_transfers.mw:134\n", mexprofrecord_[15]); mexPrintf("%d calls to test_transfers.mw:135\n", mexprofrecord_[16]); mexPrintf("%d calls to test_transfers.mw:136\n", mexprofrecord_[17]); mexPrintf("%d calls to test_transfers.mw:137\n", mexprofrecord_[18]); mexPrintf("%d calls to test_transfers.mw:140\n", mexprofrecord_[19]); mexPrintf("%d calls to test_transfers.mw:141\n", mexprofrecord_[20]); mexPrintf("%d calls to test_transfers.mw:156\n", mexprofrecord_[21]); mexPrintf("%d calls to test_transfers.mw:164\n", mexprofrecord_[22]); mexPrintf("%d calls to test_transfers.mw:168\n", mexprofrecord_[23]); mexPrintf("%d calls to test_transfers.mw:172\n", mexprofrecord_[24]); mexPrintf("%d calls to test_transfers.mw:175\n", mexprofrecord_[25]); mexPrintf("%d calls to test_transfers.mw:180\n", mexprofrecord_[26]); mexPrintf("%d calls to test_transfers.mw:183\n", mexprofrecord_[27]); mexPrintf("%d calls to test_transfers.mw:188\n", mexprofrecord_[28]); mexPrintf("%d calls to test_transfers.mw:192\n", mexprofrecord_[29]); mexPrintf("%d calls to test_transfers.mw:197 (test_transfers.mw:216)\n", mexprofrecord_[30]); mexPrintf("%d calls to test_transfers.mw:201\n", mexprofrecord_[31]); mexPrintf("%d calls to test_transfers.mw:204\n", mexprofrecord_[32]); mexPrintf("%d calls to test_transfers.mw:207\n", mexprofrecord_[33]); mexPrintf("%d calls to test_transfers.mw:215 (test_transfers.mw:296)\n", mexprofrecord_[34]); mexPrintf("%d calls to test_transfers.mw:217\n", mexprofrecord_[36]); mexPrintf("%d calls to test_transfers.mw:218 (test_transfers.mw:288)\n", mexprofrecord_[37]); mexPrintf("%d calls to test_transfers.mw:227\n", mexprofrecord_[38]); mexPrintf("%d calls to test_transfers.mw:231 (test_transfers.mw:255)\n", mexprofrecord_[39]); mexPrintf("%d calls to test_transfers.mw:235\n", mexprofrecord_[40]); mexPrintf("%d calls to test_transfers.mw:239\n", mexprofrecord_[41]); mexPrintf("%d calls to test_transfers.mw:244 (test_transfers.mw:245)\n", mexprofrecord_[42]); mexPrintf("%d calls to test_transfers.mw:250\n", mexprofrecord_[44]); mexPrintf("%d calls to test_transfers.mw:254\n", mexprofrecord_[45]); mexPrintf("%d calls to test_transfers.mw:260\n", mexprofrecord_[47]); mexPrintf("%d calls to test_transfers.mw:267 (test_transfers.mw:268)\n", mexprofrecord_[48]); mexPrintf("%d calls to test_transfers.mw:273\n", mexprofrecord_[50]); mexPrintf("%d calls to test_transfers.mw:277\n", mexprofrecord_[51]); mexPrintf("%d calls to test_transfers.mw:283 (test_transfers.mw:284)\n", mexprofrecord_[52]); mexPrintf("%d calls to test_transfers.mw:298\n", mexprofrecord_[57]); mexPrintf("%d calls to test_transfers.mw:303\n", mexprofrecord_[58]); mexPrintf("%d calls to test_transfers.mw:307\n", mexprofrecord_[59]); mexPrintf("%d calls to test_transfers.mw:312 (test_transfers.mw:313)\n", mexprofrecord_[60]); mexPrintf("%d calls to test_transfers.mw:318\n", mexprofrecord_[62]); mexPrintf("%d calls to test_transfers.mw:323 (test_transfers.mw:324)\n", mexprofrecord_[63]); mexPrintf("%d calls to test_transfers.mw:330\n", mexprofrecord_[65]); mexPrintf("%d calls to test_transfers.mw:334\n", mexprofrecord_[66]); mexPrintf("%d calls to test_transfers.mw:338\n", mexprofrecord_[67]); mexPrintf("%d calls to test_transfers.mw:342 (test_transfers.mw:343)\n", mexprofrecord_[68]); mexPrintf("%d calls to test_transfers.mw:348\n", mexprofrecord_[70]); mexPrintf("%d calls to test_transfers.mw:352\n", mexprofrecord_[71]); mexPrintf("%d calls to test_transfers.mw:356 (test_transfers.mw:357)\n", mexprofrecord_[72]); mexPrintf("%d calls to test_transfers.mw:368\n", mexprofrecord_[75]); mexPrintf("%d calls to test_transfers.mw:375\n", mexprofrecord_[76]); mexPrintf("%d calls to test_transfers.mw:379\n", mexprofrecord_[77]); mexPrintf("%d calls to test_transfers.mw:384\n", mexprofrecord_[78]); mexPrintf("%d calls to test_transfers.mw:385\n", mexprofrecord_[79]); mexPrintf("%d calls to test_transfers.mw:390\n", mexprofrecord_[80]); mexPrintf("%d calls to test_transfers.mw:394\n", mexprofrecord_[81]); mexPrintf("%d calls to test_transfers.mw:398\n", mexprofrecord_[82]); mexPrintf("%d calls to test_transfers.mw:402\n", mexprofrecord_[83]); mexPrintf("%d calls to test_transfers.mw:406\n", mexprofrecord_[84]); mexPrintf("%d calls to test_transfers.mw:415\n", mexprofrecord_[85]); mexPrintf("%d calls to test_transfers.mw:420\n", mexprofrecord_[86]); mexPrintf("%d calls to test_transfers.mw:425\n", mexprofrecord_[87]); mexPrintf("%d calls to test_transfers.mw:430\n", mexprofrecord_[88]); mexPrintf("%d calls to test_transfers.mw:441\n", mexprofrecord_[89]); mexPrintf("%d calls to test_transfers.mw:448\n", mexprofrecord_[90]); mexPrintf("%d calls to test_transfers.mw:457\n", mexprofrecord_[91]); mexPrintf("%d calls to test_transfers.mw:466 (test_transfers.mw:468)\n", mexprofrecord_[92]); mexPrintf("%d calls to test_transfers.mw:554\n", mexprofrecord_[94]); mexPrintf("%d calls to test_transfers.mw:557\n", mexprofrecord_[95]); mexPrintf("%d calls to test_transfers.mw:561\n", mexprofrecord_[96]); mexPrintf("%d calls to test_transfers.mw:564\n", mexprofrecord_[97]); mexPrintf("%d calls to test_transfers.mw:567\n", mexprofrecord_[98]); mexPrintf("%d calls to test_transfers.mw:570\n", mexprofrecord_[99]); } else if (strcmp(id, "*profile log*") == 0) { FILE* logfp; if (nrhs != 2 || mxGetString(prhs[1], id, sizeof(id)) != 0) mexErrMsgTxt("Must have two string arguments"); logfp = fopen(id, "w+"); if (!logfp) mexErrMsgTxt("Cannot open log for output"); if (!mexprofrecord_) fprintf(logfp, "Profiler inactive\n"); fprintf(logfp, "%d calls to test_transfers.mw:81\n", mexprofrecord_[1]); fprintf(logfp, "%d calls to test_transfers.mw:82\n", mexprofrecord_[2]); fprintf(logfp, "%d calls to test_transfers.mw:83\n", mexprofrecord_[3]); fprintf(logfp, "%d calls to test_transfers.mw:84\n", mexprofrecord_[4]); fprintf(logfp, "%d calls to test_transfers.mw:97\n", mexprofrecord_[5]); fprintf(logfp, "%d calls to test_transfers.mw:105\n", mexprofrecord_[6]); fprintf(logfp, "%d calls to test_transfers.mw:106\n", mexprofrecord_[7]); fprintf(logfp, "%d calls to test_transfers.mw:127\n", mexprofrecord_[8]); fprintf(logfp, "%d calls to test_transfers.mw:128\n", mexprofrecord_[9]); fprintf(logfp, "%d calls to test_transfers.mw:129\n", mexprofrecord_[10]); fprintf(logfp, "%d calls to test_transfers.mw:130\n", mexprofrecord_[11]); fprintf(logfp, "%d calls to test_transfers.mw:131\n", mexprofrecord_[12]); fprintf(logfp, "%d calls to test_transfers.mw:132\n", mexprofrecord_[13]); fprintf(logfp, "%d calls to test_transfers.mw:133\n", mexprofrecord_[14]); fprintf(logfp, "%d calls to test_transfers.mw:134\n", mexprofrecord_[15]); fprintf(logfp, "%d calls to test_transfers.mw:135\n", mexprofrecord_[16]); fprintf(logfp, "%d calls to test_transfers.mw:136\n", mexprofrecord_[17]); fprintf(logfp, "%d calls to test_transfers.mw:137\n", mexprofrecord_[18]); fprintf(logfp, "%d calls to test_transfers.mw:140\n", mexprofrecord_[19]); fprintf(logfp, "%d calls to test_transfers.mw:141\n", mexprofrecord_[20]); fprintf(logfp, "%d calls to test_transfers.mw:156\n", mexprofrecord_[21]); fprintf(logfp, "%d calls to test_transfers.mw:164\n", mexprofrecord_[22]); fprintf(logfp, "%d calls to test_transfers.mw:168\n", mexprofrecord_[23]); fprintf(logfp, "%d calls to test_transfers.mw:172\n", mexprofrecord_[24]); fprintf(logfp, "%d calls to test_transfers.mw:175\n", mexprofrecord_[25]); fprintf(logfp, "%d calls to test_transfers.mw:180\n", mexprofrecord_[26]); fprintf(logfp, "%d calls to test_transfers.mw:183\n", mexprofrecord_[27]); fprintf(logfp, "%d calls to test_transfers.mw:188\n", mexprofrecord_[28]); fprintf(logfp, "%d calls to test_transfers.mw:192\n", mexprofrecord_[29]); fprintf(logfp, "%d calls to test_transfers.mw:197 (test_transfers.mw:216)\n", mexprofrecord_[30]); fprintf(logfp, "%d calls to test_transfers.mw:201\n", mexprofrecord_[31]); fprintf(logfp, "%d calls to test_transfers.mw:204\n", mexprofrecord_[32]); fprintf(logfp, "%d calls to test_transfers.mw:207\n", mexprofrecord_[33]); fprintf(logfp, "%d calls to test_transfers.mw:215 (test_transfers.mw:296)\n", mexprofrecord_[34]); fprintf(logfp, "%d calls to test_transfers.mw:217\n", mexprofrecord_[36]); fprintf(logfp, "%d calls to test_transfers.mw:218 (test_transfers.mw:288)\n", mexprofrecord_[37]); fprintf(logfp, "%d calls to test_transfers.mw:227\n", mexprofrecord_[38]); fprintf(logfp, "%d calls to test_transfers.mw:231 (test_transfers.mw:255)\n", mexprofrecord_[39]); fprintf(logfp, "%d calls to test_transfers.mw:235\n", mexprofrecord_[40]); fprintf(logfp, "%d calls to test_transfers.mw:239\n", mexprofrecord_[41]); fprintf(logfp, "%d calls to test_transfers.mw:244 (test_transfers.mw:245)\n", mexprofrecord_[42]); fprintf(logfp, "%d calls to test_transfers.mw:250\n", mexprofrecord_[44]); fprintf(logfp, "%d calls to test_transfers.mw:254\n", mexprofrecord_[45]); fprintf(logfp, "%d calls to test_transfers.mw:260\n", mexprofrecord_[47]); fprintf(logfp, "%d calls to test_transfers.mw:267 (test_transfers.mw:268)\n", mexprofrecord_[48]); fprintf(logfp, "%d calls to test_transfers.mw:273\n", mexprofrecord_[50]); fprintf(logfp, "%d calls to test_transfers.mw:277\n", mexprofrecord_[51]); fprintf(logfp, "%d calls to test_transfers.mw:283 (test_transfers.mw:284)\n", mexprofrecord_[52]); fprintf(logfp, "%d calls to test_transfers.mw:298\n", mexprofrecord_[57]); fprintf(logfp, "%d calls to test_transfers.mw:303\n", mexprofrecord_[58]); fprintf(logfp, "%d calls to test_transfers.mw:307\n", mexprofrecord_[59]); fprintf(logfp, "%d calls to test_transfers.mw:312 (test_transfers.mw:313)\n", mexprofrecord_[60]); fprintf(logfp, "%d calls to test_transfers.mw:318\n", mexprofrecord_[62]); fprintf(logfp, "%d calls to test_transfers.mw:323 (test_transfers.mw:324)\n", mexprofrecord_[63]); fprintf(logfp, "%d calls to test_transfers.mw:330\n", mexprofrecord_[65]); fprintf(logfp, "%d calls to test_transfers.mw:334\n", mexprofrecord_[66]); fprintf(logfp, "%d calls to test_transfers.mw:338\n", mexprofrecord_[67]); fprintf(logfp, "%d calls to test_transfers.mw:342 (test_transfers.mw:343)\n", mexprofrecord_[68]); fprintf(logfp, "%d calls to test_transfers.mw:348\n", mexprofrecord_[70]); fprintf(logfp, "%d calls to test_transfers.mw:352\n", mexprofrecord_[71]); fprintf(logfp, "%d calls to test_transfers.mw:356 (test_transfers.mw:357)\n", mexprofrecord_[72]); fprintf(logfp, "%d calls to test_transfers.mw:368\n", mexprofrecord_[75]); fprintf(logfp, "%d calls to test_transfers.mw:375\n", mexprofrecord_[76]); fprintf(logfp, "%d calls to test_transfers.mw:379\n", mexprofrecord_[77]); fprintf(logfp, "%d calls to test_transfers.mw:384\n", mexprofrecord_[78]); fprintf(logfp, "%d calls to test_transfers.mw:385\n", mexprofrecord_[79]); fprintf(logfp, "%d calls to test_transfers.mw:390\n", mexprofrecord_[80]); fprintf(logfp, "%d calls to test_transfers.mw:394\n", mexprofrecord_[81]); fprintf(logfp, "%d calls to test_transfers.mw:398\n", mexprofrecord_[82]); fprintf(logfp, "%d calls to test_transfers.mw:402\n", mexprofrecord_[83]); fprintf(logfp, "%d calls to test_transfers.mw:406\n", mexprofrecord_[84]); fprintf(logfp, "%d calls to test_transfers.mw:415\n", mexprofrecord_[85]); fprintf(logfp, "%d calls to test_transfers.mw:420\n", mexprofrecord_[86]); fprintf(logfp, "%d calls to test_transfers.mw:425\n", mexprofrecord_[87]); fprintf(logfp, "%d calls to test_transfers.mw:430\n", mexprofrecord_[88]); fprintf(logfp, "%d calls to test_transfers.mw:441\n", mexprofrecord_[89]); fprintf(logfp, "%d calls to test_transfers.mw:448\n", mexprofrecord_[90]); fprintf(logfp, "%d calls to test_transfers.mw:457\n", mexprofrecord_[91]); fprintf(logfp, "%d calls to test_transfers.mw:466 (test_transfers.mw:468)\n", mexprofrecord_[92]); fprintf(logfp, "%d calls to test_transfers.mw:554\n", mexprofrecord_[94]); fprintf(logfp, "%d calls to test_transfers.mw:557\n", mexprofrecord_[95]); fprintf(logfp, "%d calls to test_transfers.mw:561\n", mexprofrecord_[96]); fprintf(logfp, "%d calls to test_transfers.mw:564\n", mexprofrecord_[97]); fprintf(logfp, "%d calls to test_transfers.mw:567\n", mexprofrecord_[98]); fprintf(logfp, "%d calls to test_transfers.mw:570\n", mexprofrecord_[99]); fclose(logfp); } else mexErrMsgTxt("Unknown identifier"); } zgimbutas-mwrap-25008ce/testing/test_typecheck.mw000066400000000000000000000012371515063637600222520ustar00rootroot00000000000000 function badmojo # double z = sumpair(inout Pair p); # double z = sumpair(output Pair p); # dble(inout int y); # dble(output int y); # strcat(inout cstring s1, cstring s2); # strcat(output cstring s1, cstring s2); # double z = sumpair(inout Pair& p); # double z = sumpair(inout Pair* p); # double z = sumpair(output Pair& p); # double z = sumpair(output Pair* p); # get34(output int[] z); # get34(output fcomplex[] z); # get34(output dcomplex[] z); # get(output int[1,2,3] z); # typedef bozo byte; %# An okay line -- should be ignored, since it doesn't start with # # // Another okay line -- comments should be ignored // Another okay line -- comments should be ignored zgimbutas-mwrap-25008ce/testing/test_typecheck.ref000066400000000000000000000011761515063637600224050ustar00rootroot00000000000000Error (3): Object p cannot be output Error (4): Object p cannot be output Error (5): Scalar y cannot be output Error (6): Scalar y cannot be output Error (7): String s1 cannot be output without size Error (8): String s1 cannot be output without size Error (9): Object p cannot be output Error (10): Object p cannot be output Error (11): Object p cannot be output Error (12): Object p cannot be output Error (13): Output array z must have dims Error (14): Output array z must have dims Error (15): Output array z must have dims Error (16): Array z should be 1D or 2D Unrecognized typespace: bozo test_typecheck.mw: 15 type errors detected