pax_global_header00006660000000000000000000000064127757005530014525gustar00rootroot0000000000000052 comment=bf01bd03861f6f214be560c654abecd12909e382 sopt-2.0.0/000077500000000000000000000000001277570055300125115ustar00rootroot00000000000000sopt-2.0.0/.clang-format000066400000000000000000000045101277570055300150640ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: true AlignConsecutiveAssignments: false AlignEscapedNewlinesLeft: false AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BreakBeforeBinaryOperators: All BreakBeforeBraces: Attach BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false ColumnLimit: 100 CommentPragmas: '^ IWYU pragma:' ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] IndentCaseLabels: false IndentWidth: 2 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: true MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 10 PointerAlignment: Right SpaceAfterCStyleCast: false SpaceBeforeAssignmentOperators: true SpaceBeforeParens: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp11 TabWidth: 8 UseTab: Never IncludeCategories: - Regex: '^(<|")sopt/config.h(>|")$' Priority: 2 - Regex: '^(<|")sopt/wavelets/' Priority: 10 - Regex: '^(<|")sopt/' Priority: 9 - Regex: '^(<.*/.*>)' Priority: 7 - Regex: '^(<.*>)' Priority: 6 - Regex: '".\*"' Priority: 8 ... sopt-2.0.0/.gitignore000066400000000000000000000027011277570055300145010ustar00rootroot00000000000000doc/c/bdwn.png doc/c/dir_*.html doc/c/dir_*.html doc/c/dir_*.html doc/c/dynsections.js doc/c/form_0.png doc/c/form_1.png doc/c/form_10.png doc/c/form_11.png doc/c/form_12.png doc/c/form_13.png doc/c/form_14.png doc/c/form_15.png doc/c/form_16.png doc/c/form_17.png doc/c/form_18.png doc/c/form_19.png doc/c/form_2.png doc/c/form_20.png doc/c/form_21.png doc/c/form_22.png doc/c/form_23.png doc/c/form_24.png doc/c/form_25.png doc/c/form_26.png doc/c/form_27.png doc/c/form_28.png doc/c/form_29.png doc/c/form_3.png doc/c/form_30.png doc/c/form_31.png doc/c/form_32.png doc/c/form_33.png doc/c/form_34.png doc/c/form_35.png doc/c/form_36.png doc/c/form_37.png doc/c/form_38.png doc/c/form_39.png doc/c/form_4.png doc/c/form_40.png doc/c/form_41.png doc/c/form_42.png doc/c/form_43.png doc/c/form_44.png doc/c/form_45.png doc/c/form_46.png doc/c/form_5.png doc/c/form_6.png doc/c/form_7.png doc/c/form_8.png doc/c/form_9.png doc/c/formula.repository doc/c/ftv2blank.png doc/c/ftv2cl.png doc/c/ftv2doc.png doc/c/ftv2folderclosed.png doc/c/ftv2folderopen.png doc/c/ftv2lastnode.png doc/c/ftv2link.png doc/c/ftv2mlastnode.png doc/c/ftv2mnode.png doc/c/ftv2mo.png doc/c/ftv2node.png doc/c/ftv2ns.png doc/c/ftv2plastnode.png doc/c/ftv2pnode.png doc/c/ftv2splitbar.png doc/c/ftv2vertline.png doc/c/nav_g.png doc/c/sopt__about_8c.html doc/c/sopt__about_8c_source.html doc/c/sync_off.png doc/c/sync_on.png images/wavedec.tiff lib/*.a build/ .*.swp .settings python/tests/__pycache__ sopt-2.0.0/CMakeLists.txt000066400000000000000000000035331277570055300152550ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8) project(Sopt CXX) # Location of extra cmake includes for the project list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_files) # Downloads and installs GreatCMakeCookOff # It contains a number of cmake recipes include(LookUp-GreatCMakeCookOff) # Version and git hash id include(VersionAndGitRef) set_version(2.0.0) get_gitref() option(tests "Enable testing" on) option(python "Enable python" on) option(benchmarks "Enable benchmarking" on) option(examples "Enable Examples" on) option(logging "Enable logging" on) option(regressions "Enable regressions" on) option(openmp "Enable OpenMP" on) option(archer "Compiling on ARCHER" off) if(regressions) enable_language(C) endif() if(tests) enable_testing() endif() # Add c++11 stuff include(AddCPP11Flags) include(CheckCXX11Features) if(tests AND python) include(AddPyTest) endif() cxx11_feature_check(REQUIRED unique_ptr nullptr override constructor_delegate) include(compilations) # search/install dependencies include(dependencies) # sets rpath policy explicitly if(CMAKE_VERSION VERSION_LESS 3.0) set_property(GLOBAL PROPERTY MACOSX_RPATH ON) else() cmake_policy(SET CMP0042 NEW) endif() if(tests OR examples) enable_testing() endif() if(tests) include(AddCatchTest) endif() if(examples) include(AddExample) endif() if(benchmarks) include(AddBenchmark) endif() if(regressions) include(AddRegression) endif() if(python) include(python_dependencies) include(PythonModule) endif() if(python) add_subdirectory(python) endif() add_subdirectory(cpp) # Exports all Sopt so other packages can access it include(export_sopt) sopt-2.0.0/LICENSE.txt000066400000000000000000000354231277570055300143430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS sopt-2.0.0/README.md000066400000000000000000000114421277570055300137720ustar00rootroot00000000000000 # SOPT: Sparse OPTimisation ------------------------------------------------------------------ ## Description SOPT is a C++ package to perform Sparse OPTimisation. It solves a variety of sparse regularisation problems, including the SARA algorithm. Prototype Matlab implementations of various algorithms are also included. ## Contributors SOPT was initially created by Rafael Carrillo, Jason McEwen and Yves Wiaux but major contributions have since been made by a number of others. The full list of contributors is as follows: * [Rafael E. Carrillo](http://people.epfl.ch/rafael.carrillo) * [Jason D. McEwen](http://www.jasonmcewen.org) * [Yves Wiaux](http://basp.eps.hw.ac.uk) * [Vijay Kartik](https://people.epfl.ch/vijay.kartik) * [Mayeul d'Avezac](https://github.com/mdavezac) * [Luke Pratley](https://about.me/luke.pratley) * [David Perez-Suarez](https://dpshelio.github.io) ## References When referencing this code, please cite our related papers: 1. R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-P. Thiran, and Y. Wiaux. "Sparsity averaging for compressive imaging", IEEE Signal Processing Letters, 20(6):591-594, 2013, [arXiv:1208.2330](http://arxiv.org/abs/arXiv:1208.2330) 1. A. Onose, R. E. Carrillo, A. Repetti, J. D. McEwen, J.-P. Thiran, J.-C. Pesquet, and Y. Wiaux. "Scalable splitting algorithms for big-data interferometric imaging in the SKA era". Mon. Not. Roy. Astron. Soc., 462(4):4314-4335, 2016, [arXiv:1601.04026](http://arxiv.org/abs/arXiv:1601.04026) ## Webpage http://basp-group.github.io/sopt/ ## Installation ### C++ pre-requisites and dependencies - [CMake](http://www.cmake.org/): a free software that allows cross-platform compilation - [tiff](http://www.libtiff.org/): Tag Image File Format library - [OpenMP](http://openmp.org/wp/): Optional. Speeds up some of the operations. - [UCL/GreatCMakeCookOff](https://github.com/UCL/GreatCMakeCookOff): Collection of cmake recipes. Downloaded automatically if absent. - [Eigen 3](http://eigen.tuxfamily.org/index.php?title=Main_Page): Modern C++ linear algebra. Downloaded automatically if absent. - [spdlog](https://github.com/gabime/spdlog): Optional. Logging library. Downloaded automatically if absent. - [philsquared/Catch](https://github.com/philsquared/Catch): Optional - only for testing. A C++ unit-testing framework. Downloaded automatically if absent. - [google/benchmark](https://github.com/google/benchmar): Optional - only for benchmarks. A C++ micro-benchmarking framework. Downloaded automatically if absent. ### Python pre-requisites and dependencies - [numpy](http://www.numpy.org/): Fundamental package for scientific computing with Python - [scipy](https://www.scipy.org/): User-friendly and efficient numerical routines such as routines for numerical integration and optimization - [pandas](http://pandas.pydata.org/): library providing high-performance, easy-to-use data structures and data analysis tools - [cython](http://cython.org/): Makes writing C extensions for Python as easy as Python itself. Downloaded automatically if absent. - [pytest](http://doc.pytest.org/en/latest/): Optional - for testing only. Unit-testing framework for python. Downloaded automatically if absent and testing is not disabled. ### Installing Sopt Once the dependencies are present, the program can be built with: ``` cd /path/to/code mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release .. make ``` To test everything went all right: ``` cd /path/to/code/build ctest . ``` To install in directory `/X`, with libraries going to `X/lib`, python modules to `X/lib/pythonA.B/site-packages/sopt`, etc, do: ``` cd /path/to/code/build cmake -DCMAKE_INSTALL_PREFIX=/X .. make install ``` ## Support If you have any questions or comments, feel free to contact Rafael Carrillo or Jason McEwen, or add an issue in the [issue tracker](https://github.com/basp-group/sopt/issues). ## Notes The code is given for educational purpose. For the matlab version of the code see the folder matlab. ## License SOPT: Sparse OPTimisation package Copyright (C) 2013 Rafael Carrillo, Jason McEwen, Yves Wiaux This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (LICENSE.txt). You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. sopt-2.0.0/cmake_files/000077500000000000000000000000001277570055300147535ustar00rootroot00000000000000sopt-2.0.0/cmake_files/AddExample.cmake000066400000000000000000000027111277570055300177620ustar00rootroot00000000000000if(NOT TARGET examples) add_custom_target(examples COMMAND ctest -L examples ${PROJECT_BINARY_DIR}) endif() function(add_example targetname) cmake_parse_arguments(example "NOTEST" "WORKING_DIRECTORY" "LIBRARIES;LABELS;DEPENDS" ${ARGN}) # Source deduce from targetname if possible unset(source) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${targetname}.cc") set(source ${targetname}.cc) elseif("${example_UNPARSED_ARGUMENTS}" STREQUAL "") message(FATAL_ERROR "No source given or found for ${targetname}") endif() add_executable(example_${targetname} ${source} ${example_UNPARSED_ARGUMENTS}) set_target_properties(example_${targetname} PROPERTIES OUTPUT_NAME ${targetname}) if(example_LIBRARIES) target_link_libraries(example_${targetname} ${example_LIBRARIES}) endif() add_dependencies(examples example_${targetname}) if(example_DEPENDS) add_dependencies(example_${targetname} ${example_DEPENDS}) endif() if(TARGET lookup_dependencies) add_dependencies(example_${targetname} lookup_dependencies) endif() # Add to tests if(NOT example_NOTEST) unset(EXTRA_ARGS) if(example_WORKING_DIRECTORY) set(EXTRA_ARGS WORKING_DIRECTORY ${example_WORKING_DIRECTORY}) endif() add_test(NAME test_example_${targetname} COMMAND example_${targetname} ${EXTRA_ARGS}) list(APPEND example_LABELS examples) set_tests_properties(test_example_${targetname} PROPERTIES LABELS "${example_LABELS}") endif() endfunction() sopt-2.0.0/cmake_files/AddRegression.cmake000066400000000000000000000006741277570055300205150ustar00rootroot00000000000000if(NOT TARGET regressions) add_custom_target(regressions COMMAND ctest -L regressions ${PROJECT_BINARY_DIR}) endif() include(AddCatchTest) function(add_regression targetname) cmake_parse_arguments(regr "" "" "LIBRARIES;LABELS;INCLUDES" ${ARGN}) add_catch_test(${targetname} ${regr_UNPARSED_ARGUMENTS} LIBRARIES ${Sopt_LIBRARIES} ${regr_LIBRARIES} LABELS ${regr_LABELS} "regression" INCLUDES ${regr_INCLUDE} ) endfunction() sopt-2.0.0/cmake_files/LookUp-GreatCMakeCookOff.cmake000066400000000000000000000037741277570055300224110ustar00rootroot00000000000000# This file is part of the GreatCMakeCookOff package and distributed under the MIT Licences. # Upon inclusion in a cmake file, it will download the GreatCMakeCookOff and make itself known to # CMake. It should be added explicitely to build systems that make use of recipes from the cook-off. # And it should be included prior to using cook-off recipes: # # ```{CMake} # include(LookUp-GreatCMakeCookOff) # ``` # First attempts to find the package set(COOKOFF_DOWNLOAD_DIR "${PROJECT_BINARY_DIR}/external/src/GreatCMakeCookOff") find_package(GreatCMakeCookOff NO_MODULE PATHS "${COOKOFF_DOWNLOAD_DIR}" QUIET) # Otherwise attempts to download it. # Does not use ExternalProject_Add to avoid doing a recursive cmake step. if(NOT GreatCMakeCookOff_FOUND) message(STATUS "[GreatCMakeCookOff] not found. Will attempt to clone it.") # Need git for cloning. find_package(Git) if(NOT GIT_FOUND) message(FATAL_ERROR "[Git] not found. Cannot download GreatCMakeCookOff") endif() # Remove GreatCMakeCookOff directory if it exists if(EXISTS "${COOKOFF_DOWNLOAD_DIR}") execute_process( COMMAND ${CMAKE_COMMAND} -E remove_directory "${COOKOFF_DOWNLOAD_DIR}" OUTPUT_QUIET ) endif() if(NOT COOKOFF_GITREPO) set(COOKOFF_GITREPO https://github.com/UCL/GreatCMakeCookOff.git) endif() execute_process( COMMAND ${GIT_EXECUTABLE} clone "${COOKOFF_GITREPO}" "${COOKOFF_DOWNLOAD_DIR}" RESULT_VARIABLE CLONING_COOKOFF OUTPUT_QUIET ERROR_VARIABLE CLONING_ERROR ) if(NOT ${CLONING_COOKOFF} EQUAL 0) message(STATUS "${CLONING_ERROR}") message(FATAL_ERROR "[GreatCMakeCookOff] git cloning failed.") else() message(STATUS "[GreatCMakeCookOff] downloaded to ${COOKOFF_DOWNLOAD_DIR}") find_package(GreatCMakeCookOff NO_MODULE PATHS "${COOKOFF_DOWNLOAD_DIR}" QUIET) endif() set(GreatCMakeCookOff_DIR "${COOKOFF_DOWNLOAD_DIR}/cmake") set(GreatCMakeCookOff_FOUND TRUE) endif() unset(COOKOFF_DOWNLOAD_DIR) # Adds GreatCMakeCookOff to module paths initialize_cookoff() sopt-2.0.0/cmake_files/LookUpSopt.cmake000066400000000000000000000032011277570055300200300ustar00rootroot00000000000000# Looks up [Sopt](http://basp-group.github.io/sopt/) # # - GIT_REPOSITORY: defaults to https://github.com/UCL/sopt.git # - GIT_TAG: defaults to master # - BUILD_TYPE: defaults to Release # if(Sopt_ARGUMENTS) cmake_parse_arguments(Sopt "" "GIT_REPOSITORY;GIT_TAG;BUILD_TYPE" "" ${Sopt_ARGUMENTS}) endif() if(NOT Sopt_GIT_REPOSITORY) set(Sopt_GIT_REPOSITORY https://github.com/UCL/sopt.git) endif() if(NOT Sopt_GIT_TAG) set(Sopt_GIT_TAG master) endif() if(NOT Sopt_BUILD_TYPE) set(Sopt_BUILD_TYPE Release) endif() # write subset of variables to cache for sopt to use include(PassonVariables) passon_variables(Lookup-Sopt FILENAME "${EXTERNAL_ROOT}/src/SoptVariables.cmake" PATTERNS "CMAKE_[^_]*_R?PATH" "CMAKE_C_.*" "BLAS_.*" "FFTW3_.*" "TIFF_.*" "GreatCMakeCookOff_DIR" ALSOADD "\nset(CMAKE_INSTALL_PREFIX \"${EXTERNAL_ROOT}\" CACHE STRING \"\")\n" ) ExternalProject_Add( Lookup-Sopt PREFIX ${EXTERNAL_ROOT} GIT_REPOSITORY ${Sopt_GIT_REPOSITORY} GIT_TAG ${Sopt_GIT_TAG} CMAKE_ARGS -C "${EXTERNAL_ROOT}/src/SoptVariables.cmake" -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=${Sopt_BUILD_TYPE} -DNOEXPORT=TRUE -Dtests=FALSE -Dpython=FALSE -Dexamples=FALSE -Dlogging=FALSE -Dregressions=FALSE -Dopenmp=FALSE -Dcpp=FALSE -DCLIBS_ONLY=FALSE INSTALL_DIR ${EXTERNAL_ROOT} LOG_DOWNLOAD ON LOG_CONFIGURE ON LOG_BUILD ON ) add_recursive_cmake_step(Lookup-Sopt DEPENDEES install) foreach(dep Eigen3 spdlog) lookup_package(${dep}) if(TARGET ${dep}) add_dependencies(Lookup-Sopt ${dep}) endif() endforeach() sopt-2.0.0/cmake_files/SoptConfig.in.cmake000066400000000000000000000012571277570055300204420ustar00rootroot00000000000000get_filename_component(Sopt_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) message(STATUS "Linking to sopt package in ${Sopt_CMAKE_DIR}") set(Sopt_INCLUDE_DIRS "@ALL_INCLUDE_DIRS@") if(NOT TARGET libsopt AND EXISTS "${Sopt_CMAKE_DIR}/SoptCTargets.cmake") include("${Sopt_CMAKE_DIR}/SoptCTargets.cmake") endif() if(NOT TARGET sopt AND EXISTS "${Sopt_CMAKE_DIR}/SoptCPPTargets.cmake") include("${Sopt_CMAKE_DIR}/SoptCPPTargets.cmake") endif() unset(Sopt_LIBRARIES) if(TARGET sopt) list(APPEND Sopt_LIBRARIES sopt) set(Sopt_CPP_LIBRARY sopt) endif() if(TARGET libsopt) list(APPEND Sopt_LIBRARIES libsopt) set(Sopt_C_LIBRARY libsopt) endif() set(Sopt_ABOUT_EXECUTABLE sopt_about) sopt-2.0.0/cmake_files/SoptConfigVersion.in.cmake000066400000000000000000000005021277570055300220000ustar00rootroot00000000000000set(PACKAGE_VERSION "@Sopt_VERSION@") if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_COMPATIBLE FALSE) else() set(PACKAGE_VERSION_COMPATIBLE TRUE) if("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") set(PACKAGE_VERSION_EXACT FALSE) endif() endif() sopt-2.0.0/cmake_files/compilations.cmake000066400000000000000000000001511277570055300204530ustar00rootroot00000000000000try_compile(SOPT_HAS_USING "${CMAKE_CURRENT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/cmake_files/using.cc") sopt-2.0.0/cmake_files/dependencies.cmake000066400000000000000000000024241277570055300204050ustar00rootroot00000000000000include(PackageLookup) # check for existence, or install external projects lookup_package(Eigen3 ARGUMENTS HG_REPOSITORY https://bitbucket.org/LukePratley/eigen) if(logging) lookup_package(spdlog REQUIRED) endif() find_package(TIFF) if(examples OR regression) if(NOT TIFF_FOUND) message(FATAL_ERROR "Examples and regressions require TIFF") endif() endif() if(regressions) find_package(FFTW3 REQUIRED DOUBLE) set(REGRESSION_ORACLE_ID "last_of_c" CACHE STRING "Commmit/tag/branch againts which to run regressions") lookup_package(Sopt REQUIRED DOWNLOAD_BY_DEFAULT PATHS "${EXTERNAL_ROOT}" NO_DEFAULT_PATH ARGUMENTS GIT_REPOSITORY "https://www.github.com/basp-group/sopt.git" GIT_TAG ${REGRESSION_ORACLE_ID} BUILD_TYPE Release ) endif() if(openmp) find_package(OpenMP) if(OPENMP_FOUND) set(SOPT_DEFAULT_OPENMP_THREADS 4 CACHE STRING "Number of threads used in testing") set(SOPT_OPENMP TRUE) add_library(openmp::openmp INTERFACE IMPORTED GLOBAL) set_target_properties(openmp::openmp PROPERTIES INTERFACE_COMPILE_OPTIONS "${OpenMP_CXX_FLAGS}" INTERFACE_LINK_LIBRARIES "${OpenMP_CXX_FLAGS}") else() message(STATUS "Could not find OpenMP. Compiling without.") set(SOPT_OPENMP FALSE) endif() endif() sopt-2.0.0/cmake_files/export_sopt.cmake000066400000000000000000000021661277570055300203500ustar00rootroot00000000000000# Exports Sopt so other packages can access it export(TARGETS sopt FILE "${PROJECT_BINARY_DIR}/SoptCPPTargets.cmake") # Avoids creating an entry in the cmake registry. if(NOT NOEXPORT) export(PACKAGE Sopt) endif() # First in binary dir set(ALL_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/cpp" "${PROJECT_BINARY_DIR}/include") configure_File(cmake_files/SoptConfig.in.cmake "${PROJECT_BINARY_DIR}/SoptConfig.cmake" @ONLY ) configure_File(cmake_files/SoptConfigVersion.in.cmake "${PROJECT_BINARY_DIR}/SoptConfigVersion.cmake" @ONLY ) # Then for installation tree file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/share/cmake/sopt" "${CMAKE_INSTALL_PREFIX}/include" ) set(ALL_INCLUDE_DIRS "\${Sopt_CMAKE_DIR}/${REL_INCLUDE_DIR}") configure_file(cmake_files/SoptConfig.in.cmake "${PROJECT_BINARY_DIR}/CMakeFiles/SoptConfig.cmake" @ONLY ) # Finally install all files install(FILES "${PROJECT_BINARY_DIR}/CMakeFiles/SoptConfig.cmake" "${PROJECT_BINARY_DIR}/SoptConfigVersion.cmake" DESTINATION share/cmake/sopt COMPONENT dev ) install(EXPORT SoptCPPTargets DESTINATION share/cmake/sopt COMPONENT dev) sopt-2.0.0/cmake_files/python_dependencies.cmake000066400000000000000000000033161277570055300220070ustar00rootroot00000000000000# Scripts to run purify from build directory. Good for testing/debuggin. include(EnvironmentScript) # Function to install python files in python path ${PYTHON_PKG_DIR} include(PythonInstall) # Ability to find installed python packages include(PythonPackage) # Installs python packages that are missing. # We choose to do this only for packages that are required to build purify. # Leave it to the user to install packages that are needed for running # purify. include(PythonPackageLookup) # Creates script for running python with the bempp package available # Also makes python packages and selected directories available to the # build system add_to_python_path("${PROJECT_BINARY_DIR}/python") add_to_python_path("${EXTERNAL_ROOT}/python") add_python_eggs("${PROJECT_SOURCE_DIR}" EXCLUDE "${PROJECT_SOURCE_DIR}/purify*egg" "${PROJECT_BINARY_DIR}/Purify*egg" ) set(LOCAL_PYTHON_EXECUTABLE "${PROJECT_BINARY_DIR}/localpython.sh") create_environment_script( EXECUTABLE "${PYTHON_EXECUTABLE}" PATH "${LOCAL_PYTHON_EXECUTABLE}" PYTHON ) # Python interpreter + libraries find_package(CoherentPython) # Only required for building if(NOT cython_EXECUTABLE) lookup_python_package(Cython REQUIRED PATH "${EXTERNAL_ROOT}/python") endif() # Also required for production find_python_package(numpy) find_python_package(scipy) # Finds additional info, like libraries, include dirs... # no need check numpy features, it's all handled by cython. set(no_numpy_feature_tests TRUE) find_package(Numpy REQUIRED) if(tests) include(AddPyTest) setup_pytest("${EXTERNAL_ROOT}/python" "${PROJECT_BINARY_DIR}/py.test.sh") lookup_python_package(pywt PIPNAME PyWavelets REQUIRED PATH "${EXTERNAL_ROOT}/python") endif() sopt-2.0.0/cmake_files/using.cc000066400000000000000000000003441277570055300164100ustar00rootroot00000000000000#include //! Sparsity Averaging Reweighted Analysis class SARA : public std::vector { public: // Constructors using std::vector::vector; }; int main(int, char const**) { SARA s = {0, 0}; return 0; } sopt-2.0.0/cpp/000077500000000000000000000000001277570055300132735ustar00rootroot00000000000000sopt-2.0.0/cpp/CMakeLists.txt000066400000000000000000000020401277570055300160270ustar00rootroot00000000000000# Setup logging set(SOPT_LOGGER_NAME "sopt" CACHE STRING "NAME of the logger") set(SOPT_COLOR_LOGGING true CACHE BOOL "Whether to add color to the log") if(logging) set(SOPT_DO_LOGGING 1) set(SOPT_TEST_LOG_LEVEL critical CACHE STRING "Level when logging tests") set_property(CACHE SOPT_TEST_LOG_LEVEL PROPERTY STRINGS off critical error warn info debug trace) else() unset(SOPT_DO_LOGGING) set(SOPT_TEST_LOG_LEVEL off) endif() set(version ${Sopt_VERSION}) string(REGEX REPLACE "\\." ";" version "${Sopt_VERSION}") list(GET version 0 Sopt_VERSION_MAJOR) list(GET version 1 Sopt_VERSION_MINOR) list(GET version 2 Sopt_VERSION_PATCH) configure_file(sopt/config.in.h "${PROJECT_BINARY_DIR}/include/sopt/config.h") add_subdirectory(sopt) if(regressions OR examples) # Tiff wrappers and whatnot add_subdirectory(tools_for_tests) endif() if(tests) add_subdirectory(tests) endif() if(examples) add_subdirectory(examples) endif() if(benchmarks) add_subdirectory(benchmarks) endif() if(regressions) add_subdirectory(regressions) endif() sopt-2.0.0/cpp/benchmarks/000077500000000000000000000000001277570055300154105ustar00rootroot00000000000000sopt-2.0.0/cpp/benchmarks/CMakeLists.txt000066400000000000000000000002021277570055300201420ustar00rootroot00000000000000add_benchmark(wavelets LIBRARIES sopt) add_benchmark(conjugate_gradient LIBRARIES sopt) add_benchmark(l1_proximal LIBRARIES sopt) sopt-2.0.0/cpp/benchmarks/conjugate_gradient.cc000066400000000000000000000035051277570055300215560ustar00rootroot00000000000000#include "sopt/conjugate_gradient.h" #include #include template void matrix_cg(benchmark::State &state) { auto const N = state.range_x(); auto const epsilon = std::pow(10, -state.range_y()); auto const A = sopt::Image::Random(N, N).eval(); auto const b = sopt::Array::Random(N).eval(); auto const AhA = A.matrix().transpose().conjugate() * A.matrix(); auto const Ahb = A.matrix().transpose().conjugate() * b.matrix(); auto output = sopt::Vector::Zero(N).eval(); sopt::ConjugateGradient cg(0, epsilon); while(state.KeepRunning()) cg(output, AhA, Ahb); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(N) * sizeof(TYPE)); } template void function_cg(benchmark::State &state) { auto const N = state.range_x(); auto const epsilon = std::pow(10, -state.range_y()); auto const A = sopt::Image::Random(N, N).eval(); auto const b = sopt::Array::Random(N).eval(); auto const AhA = A.matrix().transpose().conjugate() * A.matrix(); auto const Ahb = A.matrix().transpose().conjugate() * b.matrix(); typedef sopt::Vector t_Vector; auto func = [&AhA](t_Vector &out, t_Vector const &input) { out = AhA * input; }; auto output = sopt::Vector::Zero(N).eval(); sopt::ConjugateGradient cg(0, epsilon); while(state.KeepRunning()) cg(output, func, Ahb); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(N) * sizeof(TYPE)); } BENCHMARK_TEMPLATE(matrix_cg, sopt::t_complex)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_TEMPLATE(matrix_cg, sopt::t_real)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_TEMPLATE(function_cg, sopt::t_complex)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_TEMPLATE(function_cg, sopt::t_real)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_MAIN() sopt-2.0.0/cpp/benchmarks/l1_proximal.cc000066400000000000000000000024721277570055300201530ustar00rootroot00000000000000#include #include #include #include #include template void function_l1p(benchmark::State &state) { typedef typename sopt::real_type::type Real; auto const N = state.range_x(); auto const input = sopt::Vector::Random(N).eval(); auto const Psi = sopt::Matrix::Random(input.size(), input.size() * 10).eval(); sopt::Vector const weights = sopt::Vector::Random(Psi.cols()).normalized().array().abs(); auto const l1 = sopt::proximal::L1() .tolerance(std::pow(10, -state.range_y())) .itermax(100) .fista_mixing(true) .positivity_constraint(true) .nu(1) .Psi(Psi) .weights(weights); Real const gamma = 1e-2 / Psi.array().abs().sum(); auto output = sopt::Vector::Zero(N).eval(); while(state.KeepRunning()) l1(output, gamma, input); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(N) * sizeof(TYPE)); } BENCHMARK_TEMPLATE(function_l1p, sopt::t_complex)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_TEMPLATE(function_l1p, sopt::t_real)->RangePair(1, 256, 4, 12)->UseRealTime(); BENCHMARK_MAIN() sopt-2.0.0/cpp/benchmarks/wavelets.cc000066400000000000000000000073411277570055300175560ustar00rootroot00000000000000#include #include #include unsigned get_size(unsigned requested, unsigned levels) { auto const N = (1u << levels); return requested % N == 0 ? requested : requested + N - requested % N; } std::string get_name(unsigned db) { std::ostringstream sstr; sstr << "DB" << db; return sstr.str(); } template void direct_matrix(benchmark::State &state) { auto const Nx = get_size(state.range_x(), LEVEL); auto const Ny = get_size(state.range_y(), LEVEL); auto const input = sopt::Image::Random(Nx, Ny).eval(); auto output = sopt::Image::Zero(Nx, Ny).eval(); auto const wavelet = sopt::wavelets::factory(get_name(DB), LEVEL); while(state.KeepRunning()) wavelet.direct(output, input); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(Nx) * int64_t(Ny) * sizeof(TYPE)); } template void indirect_matrix(benchmark::State &state) { auto const Nx = get_size(state.range_x(), LEVEL); auto const Ny = get_size(state.range_y(), LEVEL); auto const input = sopt::Image::Random(Nx, Ny).eval(); auto output = sopt::Image::Zero(Nx, Ny).eval(); auto const wavelet = sopt::wavelets::factory(get_name(DB), LEVEL); while(state.KeepRunning()) wavelet.indirect(input, output); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(Nx) * int64_t(Ny) * sizeof(TYPE)); } template void direct_vector(benchmark::State &state) { auto const Nx = get_size(state.range_x(), LEVEL); auto const input = sopt::Array::Random(Nx).eval(); auto output = sopt::Array::Zero(Nx).eval(); auto const wavelet = sopt::wavelets::factory(get_name(DB), LEVEL); while(state.KeepRunning()) wavelet.direct(output, input); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(Nx) * sizeof(TYPE)); } template void indirect_vector(benchmark::State &state) { auto const Nx = get_size(state.range_x(), LEVEL); auto const input = sopt::Array::Random(Nx).eval(); auto output = sopt::Array::Zero(Nx).eval(); auto const wavelet = sopt::wavelets::factory(get_name(DB), LEVEL); while(state.KeepRunning()) wavelet.indirect(input, output); state.SetBytesProcessed(int64_t(state.iterations()) * int64_t(Nx) * sizeof(TYPE)); } auto const n = 64; auto const N = 256 * 3; BENCHMARK_TEMPLATE(direct_matrix, sopt::t_complex, 1, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_matrix, sopt::t_real, 1, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_matrix, sopt::t_complex, 10, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_vector, sopt::t_complex, 1, 1)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_vector, sopt::t_complex, 10, 1)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_vector, sopt::t_complex, 1, 2)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(direct_vector, sopt::t_real, 1, 1)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_matrix, sopt::t_complex, 1, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_matrix, sopt::t_real, 1, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_matrix, sopt::t_complex, 10, 1)->RangePair(n, N, n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_vector, sopt::t_complex, 1, 1)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_vector, sopt::t_complex, 10, 1)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_vector, sopt::t_complex, 1, 2)->Range(n, N)->UseRealTime(); BENCHMARK_TEMPLATE(indirect_vector, sopt::t_real, 1, 1)->Range(n, N)->UseRealTime(); BENCHMARK_MAIN() sopt-2.0.0/cpp/examples/000077500000000000000000000000001277570055300151115ustar00rootroot00000000000000sopt-2.0.0/cpp/examples/CMakeLists.txt000066400000000000000000000006611277570055300176540ustar00rootroot00000000000000add_example(wavelets LIBRARIES sopt LABELS wavelets) add_example(sara LIBRARIES sopt LABELS wavelets) add_example(positive_quadrant_projection LIBRARIES sopt LABELS proximals) add_example(l1_norm LIBRARIES sopt LABELS proximals) add_example(soft_threshhold LIBRARIES sopt LABELS proximals) add_example(conjugate_gradient LIBRARIES sopt) add_example(l1_proximal LIBRARIES sopt) add_subdirectory(sdmm) add_subdirectory(proximal_admm) sopt-2.0.0/cpp/examples/conjugate_gradient.cc000066400000000000000000000037271277570055300212650ustar00rootroot00000000000000#include #include #include int main(int, char const **) { // Conjugate-gradient solves Ax=b, where A is positive definite. // The input to our conjugate gradient can be a matrix or a function // Lets try both approaches. // Creates the input. typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; t_Vector const b = t_Vector::Random(8); t_Matrix const A = t_Matrix::Random(b.size(), b.size()); // Transform to solvable problem A^hA x = A^hb, where A^h is the conjugate transpose t_Matrix const AhA = A.conjugate().transpose() * A; t_Vector const Ahb = A.conjugate().transpose() * b; // The same transform can be realised using a function, where out = A^h * A * input. // This will recompute AhA every time the function is applied by the conjugate gradient. It is not // optmial for this case. But the function interface means A could be an FFT. auto aha_function = [&A](t_Vector &out, t_Vector const &input) { out = A.conjugate().transpose() * A * input; }; // Conjugate gradient with unlimited iterations and a convergence criteria of 1e-12 sopt::ConjugateGradient cg(std::numeric_limits::max(), 1e-12); // Call conjugate gradient using both approaches auto as_matrix = cg(AhA, Ahb); auto as_function = cg(aha_function, Ahb); // Check result if(not(as_matrix.good and as_function.good)) throw std::runtime_error("Expected convergence"); if(as_matrix.niters != as_function.niters) throw std::runtime_error("Expected same number of iterations"); if(as_matrix.residual > cg.tolerance() or as_function.residual > cg.tolerance()) throw std::runtime_error("Expected better convergence"); if(not as_matrix.result.isApprox(as_function.result, 1e-6)) throw std::runtime_error("Expected same result"); if(not(A * as_matrix.result).isApprox(b, 1e-6)) throw std::runtime_error("Expected solution to Ax=b"); return 0; } sopt-2.0.0/cpp/examples/l1_norm.cc000066400000000000000000000004601277570055300167670ustar00rootroot00000000000000#include #include int main(int, char const **) { sopt::Image> input(2, 2), weights(2, 2); input << 1, -2, 3, -4; weights << 5, 6, 7, 8; if(sopt::l1_norm(input, weights) != 1 * 5 + 2 * 6 + 3 * 7 + 4 * 8) throw std::exception(); return 0; } sopt-2.0.0/cpp/examples/l1_proximal.cc000066400000000000000000000032551277570055300176540ustar00rootroot00000000000000#include #include #include int main(int, char const **) { sopt::logging::initialize(); typedef sopt::t_complex Scalar; typedef sopt::real_type::type Real; auto const input = sopt::Vector::Random(10).eval(); auto const Psi = sopt::Matrix::Random(input.size(), input.size() * 10).eval(); sopt::Vector const weights = sopt::Vector::Random(Psi.cols()).normalized().array().abs(); auto const l1 = sopt::proximal::L1() .tolerance(1e-12) .itermax(100) .fista_mixing(true) .positivity_constraint(true) .nu(1) .Psi(Psi) .weights(weights); // gamma should be sufficiently small. Or is it nu should not be 1? // In any case, this seems to work. Real const gamma = 1e-2 / Psi.array().abs().sum(); auto const result = l1(gamma, input); if(not result.good) SOPT_THROW("Did not converge"); // Check the proximal is a minimum in any allowed direction (positivity constraint) Real const eps = 1e-4; for(size_t i(0); i < 10; ++i) { sopt::Vector const dir = sopt::Vector::Random(input.size()).normalized() * eps; sopt::Vector const position = sopt::positive_quadrant(result.proximal + dir); Real const dobj = l1.objective(input, position, gamma); // Fuzzy logic if(dobj < result.objective - 1e-8) SOPT_THROW("This is not the minimum we are looking for: ") << dobj << " <~ " << result.objective; } return 0; } sopt-2.0.0/cpp/examples/positive_quadrant_projection.cc000066400000000000000000000012761277570055300234230ustar00rootroot00000000000000#include #include int main(int, char const **) { // Create a matrix with a single negative real numbers typedef sopt::Image> t_Matrix; t_Matrix input = 2 * t_Matrix::Ones(5, 5) + t_Matrix::Random(5, 5); // Apply projection t_Matrix posquad = sopt::positive_quadrant(input); // imaginary part and negative real part becomes zero if((posquad.array().imag() != 0).any()) throw std::runtime_error("Imaginary part not zero"); // positive real part unchanged posquad.real()(2, 3) = input.real()(2, 3); if((posquad.array().real() != input.array().real()).all()) throw std::runtime_error("Real part was modified"); return 0; } sopt-2.0.0/cpp/examples/proximal_admm/000077500000000000000000000000001277570055300177425ustar00rootroot00000000000000sopt-2.0.0/cpp/examples/proximal_admm/CMakeLists.txt000066400000000000000000000007441277570055300225070ustar00rootroot00000000000000add_example(padmm_euclidian_norm euclidian_norm.cc LIBRARIES sopt LABELS padmm) set_target_properties(example_padmm_euclidian_norm PROPERTIES OUTPUT_NAME euclidian_norm) add_example(padmm_inpainting inpainting.cc LIBRARIES sopt tools_for_tests) set_target_properties(example_padmm_inpainting PROPERTIES OUTPUT_NAME inpainting) add_example(padmm_reweighted reweighted.cc LIBRARIES sopt tools_for_tests) set_target_properties(example_padmm_reweighted PROPERTIES OUTPUT_NAME reweighted) sopt-2.0.0/cpp/examples/proximal_admm/euclidian_norm.cc000066400000000000000000000046611277570055300232500ustar00rootroot00000000000000#include #include #include #include #include // We will minimize ||x - x_0|| + ||x - x_1||, ||.|| the euclidian norm int main(int, char const **) { // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); // Some typedefs for simplicity typedef sopt::t_real t_Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; // Creates the target vectors auto const N = 5; t_Vector const target0 = t_Vector::Random(N); t_Vector const target1 = t_Vector::Random(N) * 4; // Creates the resulting proximal // In practice g_0 and g_1 are any functions with the signature // void(t_Vector &output, t_Vector::Scalar gamma, t_Vector const &input) // They are the proximal of ||x - x_0|| and ||x - x_1|| auto prox_g0 = sopt::proximal::translate(sopt::proximal::EuclidianNorm(), -target0); auto prox_g1 = sopt::proximal::translate(sopt::proximal::EuclidianNorm(), -target1); auto padmm = sopt::algorithm::ProximalADMM(prox_g0, prox_g1, t_Vector::Zero(N)) .itermax(5000) .is_converged(sopt::RelativeVariation(1e-12)) .gamma(0.01) // Phi == -1, so that we can minimize f(x) + g(x), as per problem definition in // padmm. .Phi(-t_Matrix::Identity(N, N)); // Alternatively, padmm can be called with a tuple (x, residual) as argument // Here, we default to (Φ^Ty/ν, ΦΦ^Ty/ν - y) auto const diagnostic = padmm(); // diagnostic should tell us the function converged // it also contains diagnostic.niters - the number of iterations, and cg_diagnostic - the // diagnostic from the last call to the conjugate gradient. if(not diagnostic.good) throw std::runtime_error("Did not converge!"); // x should be any point on the segment linking x_0 and x_1 t_Vector const segment = (target1 - target0).normalized(); t_Scalar const alpha = (diagnostic.x - target0).transpose() * segment; if((target1 - target0).transpose() * segment < alpha) throw std::runtime_error("Point beyond x_1 plane"); if(alpha < 0e0) throw std::runtime_error("Point before x_0 plane"); if((diagnostic.x - target0 - alpha * segment).stableNorm() > 1e-8) throw std::runtime_error("Point not on (x_0, x_1) line"); return 0; } sopt-2.0.0/cpp/examples/proximal_admm/inpainting.cc000066400000000000000000000114151277570055300224130ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include // This header is not part of the installed sopt interface // It is only present in tests #include #include // \min_{x} ||\Psi^Tx||_1 \quad \mbox{s.t.} \quad ||y - Ax||_2 < \epsilon and x \geq 0 int main(int argc, char const **argv) { // Some typedefs for simplicity typedef double Scalar; // Column vector - linear algebra - A * x is a matrix-vector multiplication // type expected by ProximalADMM typedef sopt::Vector Vector; // Matrix - linear algebra - A * x is a matrix-vector multiplication // type expected by ProximalADMM typedef sopt::Matrix Matrix; // Image - 2D array - A * x is a coefficient-wise multiplication // Type expected by wavelets and image write/read functions typedef sopt::Image Image; std::string const input = argc >= 2 ? argv[1] : "cameraman256"; std::string const output = argc == 3 ? argv[2] : "none"; if(argc > 3) { std::cout << "Usage:\n" "$ " << argv[0] << " [input [output]]\n\n" "- input: path to the image to clean (or name of standard SOPT image)\n" "- output: filename pattern for output image\n"; exit(0); } // Set up random numbers for C and C++ auto const seed = std::time(0); std::srand((unsigned int)seed); std::mt19937 mersenne(std::time(0)); // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); SOPT_HIGH_LOG("Read input file {}", input); Image const image = sopt::notinstalled::read_standard_tiff(input); SOPT_HIGH_LOG("Initializing sensing operator"); sopt::t_uint nmeasure = 0.33 * image.size(); auto const sampling = sopt::linear_transform(sopt::Sampling(image.size(), nmeasure, mersenne)); SOPT_HIGH_LOG("Initializing wavelets"); auto const wavelet = sopt::wavelets::factory("DB4", 4); auto const psi = sopt::linear_transform(wavelet, image.rows(), image.cols()); SOPT_HIGH_LOG("Computing proximal-ADMM parameters"); Vector const y0 = sampling * Vector::Map(image.data(), image.size()); auto const snr = 30.0; auto const sigma = y0.stableNorm() / std::sqrt(y0.size()) * std::pow(10.0, -(snr / 20.0)); auto const epsilon = std::sqrt(nmeasure + 2 * std::sqrt(y0.size())) * sigma; SOPT_HIGH_LOG("Create dirty vector"); std::normal_distribution<> gaussian_dist(0, sigma); Vector y(y0.size()); for(sopt::t_int i = 0; i < y0.size(); i++) y(i) = y0(i) + gaussian_dist(mersenne); // Write dirty imagte to file if(output != "none") { Vector const dirty = sampling.adjoint() * y; sopt::utilities::write_tiff(Matrix::Map(dirty.data(), image.rows(), image.cols()), "dirty_" + output + ".tiff"); } SOPT_HIGH_LOG("Creating proximal-ADMM Functor"); auto const padmm = sopt::algorithm::ImagingProximalADMM(y) .itermax(500) .gamma(1e-1) .relative_variation(5e-4) .l2ball_proximal_epsilon(epsilon) .tight_frame(false) .l1_proximal_tolerance(1e-2) .l1_proximal_nu(1) .l1_proximal_itermax(50) .l1_proximal_positivity_constraint(true) .l1_proximal_real_constraint(true) .residual_convergence(epsilon * 1.001) .lagrange_update_scale(0.9) .nu(1e0) .Psi(psi) .Phi(sampling); SOPT_HIGH_LOG("Starting proximal-ADMM"); // Alternatively, padmm can be called with a tuple (x, residual) as argument // Here, we default to (Φ^Ty/ν, ΦΦ^Ty/ν - y) auto const diagnostic = padmm(); SOPT_HIGH_LOG("proximal-ADMM returned {}", diagnostic.good); // diagnostic should tell us the function converged // it also contains diagnostic.niters - the number of iterations, and cg_diagnostic - the // diagnostic from the last call to the conjugate gradient. if(not diagnostic.good) throw std::runtime_error("Did not converge!"); SOPT_HIGH_LOG("SOPT-proximal-ADMM converged in {} iterations", diagnostic.niters); if(output != "none") sopt::utilities::write_tiff(Matrix::Map(diagnostic.x.data(), image.rows(), image.cols()), output + ".tiff"); return 0; } sopt-2.0.0/cpp/examples/proximal_admm/reweighted.cc000066400000000000000000000123031277570055300223770ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // This header is not part of the installed sopt interface // It is only present in tests #include #include // \min_{x} ||\Psi^Tx||_1 \quad \mbox{s.t.} \quad ||y - Ax||_2 < \epsilon and x \geq 0 int main(int argc, char const **argv) { // Some typedefs for simplicity typedef double Scalar; // Column vector - linear algebra - A * x is a matrix-vector multiplication // type expected by ProximalADMM typedef sopt::Vector Vector; // Matrix - linear algebra - A * x is a matrix-vector multiplication // type expected by ProximalADMM typedef sopt::Matrix Matrix; // Image - 2D array - A * x is a coefficient-wise multiplication // Type expected by wavelets and image write/read functions typedef sopt::Image Image; std::string const input = argc >= 2 ? argv[1] : "cameraman256"; std::string const output = argc == 3 ? argv[2] : "none"; if(argc > 3) { std::cout << "Usage:\n" "$ " << argv[0] << " [input [output]]\n\n" "- input: path to the image to clean (or name of standard SOPT image)\n" "- output: filename pattern for output image\n"; exit(0); } // Set up random numbers for C and C++ auto const seed = std::time(0); std::srand((unsigned int)seed); std::mt19937 mersenne(std::time(0)); // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); SOPT_MEDIUM_LOG("Read input file {}", input); Image const image = sopt::notinstalled::read_standard_tiff(input); SOPT_MEDIUM_LOG("Initializing sensing operator"); sopt::t_uint nmeasure = 0.33 * image.size(); auto const sampling = sopt::linear_transform(sopt::Sampling(image.size(), nmeasure, mersenne)); SOPT_MEDIUM_LOG("Initializing wavelets"); sopt::wavelets::SARA const sara{std::make_tuple(std::string{"DB3"}, 1u), std::make_tuple(std::string{"DB1"}, 2u), std::make_tuple(std::string{"DB1"}, 3u)}; auto const psi = sopt::linear_transform(sara, image.rows(), image.cols()); SOPT_MEDIUM_LOG("Computing proximal-ADMM parameters"); Vector const y0 = sampling * Vector::Map(image.data(), image.size()); auto const snr = 30.0; auto const sigma = y0.stableNorm() / std::sqrt(y0.size()) * std::pow(10.0, -(snr / 20.0)); auto const epsilon = std::sqrt(nmeasure + 2 * std::sqrt(y0.size())) * sigma; SOPT_MEDIUM_LOG("Create dirty vector"); std::normal_distribution<> gaussian_dist(0, sigma); Vector y(y0.size()); for(sopt::t_int i = 0; i < y0.size(); i++) y(i) = y0(i) + gaussian_dist(mersenne); // Write dirty imagte to file if(output != "none") { Vector const dirty = sampling.adjoint() * y; sopt::utilities::write_tiff(Matrix::Map(dirty.data(), image.rows(), image.cols()), "dirty_" + output + ".tiff"); } SOPT_MEDIUM_LOG("Creating proximal-ADMM Functor"); auto const padmm = sopt::algorithm::ImagingProximalADMM(y) .itermax(500) .gamma(1e-1) .relative_variation(5e-4) .l2ball_proximal_epsilon(epsilon) .tight_frame(false) .l1_proximal_tolerance(1e-2) .l1_proximal_nu(1) .l1_proximal_itermax(50) .l1_proximal_positivity_constraint(true) .l1_proximal_real_constraint(true) .residual_convergence(epsilon * 1.001) .lagrange_update_scale(0.9) .nu(1e0) .Psi(psi) .Phi(sampling); SOPT_MEDIUM_LOG("Creating the reweighted algorithm"); // positive_quadrant projects the result of PADMM on the positive quadrant. // This follows the reweighted algorithm for SDMM auto const min_delta = sigma * std::sqrt(y.size()) / std::sqrt(8 * image.size()); auto const reweighted = sopt::algorithm::reweighted(padmm).itermax(5).min_delta(min_delta).is_converged( sopt::RelativeVariation(1e-3)); SOPT_MEDIUM_LOG("Starting proximal-ADMM"); // Alternatively, padmm can be called with a tuple (x, residual) as argument // Here, we default to (Φ^Ty/ν, ΦΦ^Ty/ν - y) auto const diagnostic = reweighted(); SOPT_MEDIUM_LOG("proximal-ADMM returned {}", diagnostic.good); SOPT_MEDIUM_LOG("SOPT-proximal-ADMM converged in {} iterations", diagnostic.niters); if(output != "none") sopt::utilities::write_tiff(Matrix::Map(diagnostic.algo.x.data(), image.rows(), image.cols()), output + ".tiff"); return 0; } sopt-2.0.0/cpp/examples/sara.cc000066400000000000000000000021501277570055300163440ustar00rootroot00000000000000#include int main(int, char const **) { // Creates SARA with two wavelets typedef std::tuple t_i; sopt::wavelets::SARA sara{t_i{"DB4", 5}, t_i{"DB8", 2}}; // Then another one for good measure sara.emplace_back("DB3", 7); // Creates a random signal sopt::Image input = sopt::Image::Random(128, 128); // Now gets its coefficients auto coefficients = sara.direct(input); // And transform back. We pass a pre-defined matrix explicitly to illustrate that API. // But we could just store the return value as above. sopt::Image recover; // This matrix will be resized if necessary sara.indirect(coefficients, recover); // Check the reconstruction is corrrect if(not input.isApprox(recover)) throw std::exception(); // The coefficient for each wavelet basis is stored alongs columns: sopt::Image const DB3_coeffs = sara[2].direct(input) / std::sqrt(sara.size()); if(not coefficients.rightCols(input.cols()).isApprox(DB3_coeffs)) throw std::exception(); return 0; } sopt-2.0.0/cpp/examples/sdmm/000077500000000000000000000000001277570055300160515ustar00rootroot00000000000000sopt-2.0.0/cpp/examples/sdmm/CMakeLists.txt000066400000000000000000000002751277570055300206150ustar00rootroot00000000000000add_example(euclidian_norm LIBRARIES sopt LABELS sdmm) add_example(inpainting LIBRARIES sopt tools_for_tests LABELS sdmm) add_example(reweighted LIBRARIES sopt tools_for_tests LABELS sdmm) sopt-2.0.0/cpp/examples/sdmm/euclidian_norm.cc000066400000000000000000000076721277570055300213640ustar00rootroot00000000000000#include #include #include // We will minimize ||L_0 x - x_0|| + ||L_1 x - x_1||, ||.|| the euclidian norm int main(int, char const **) { // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); // Some typedefs for simplicity typedef sopt::t_complex t_Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; // Creates the transformation matrices auto const N = 10; t_Matrix const L0 = t_Matrix::Random(N, N) * 2; t_Matrix const L1 = t_Matrix::Random(N, N) * 4; // L1_direct and L1_adjoint are used to demonstrate that we can define L_i in SDMM both directly // as matrices, or as a pair of functions that apply a linear operator and its transpose. auto L1_direct = [&L1](t_Vector &out, t_Vector const &input) { out = L1 * input; }; auto L1_adjoint = [&L1](t_Vector &out, t_Vector const &input) { out = L1.adjoint() * input; }; // Creates the target vectors t_Vector const target0 = t_Vector::Random(N); t_Vector const target1 = t_Vector::Random(N); // Creates the resulting proximal // In practice g_0 and g_1 are any functions with the signature // void(t_Vector &output, t_Vector::Scalar gamma, t_Vector const &input) auto prox_g0 = sopt::proximal::translate(sopt::proximal::EuclidianNorm(), -target0); auto prox_g1 = sopt::proximal::translate(sopt::proximal::EuclidianNorm(), -target1); // This function is called at every iteration. It should return true when convergence is achieved. // Otherwise the convex optimizer will trudge on until the requisite number of iterations have // been achieved. // It takes the convex minimizer and the current candidate output vector as arguments. // The example below assumes convergence when the candidate vector does not change anymore. std::shared_ptr previous; auto relative = [&previous](t_Vector const &candidate) { if(not previous) { previous = std::make_shared(candidate); return false; } auto const norm = (*previous - candidate).stableNorm(); SOPT_TRACE(" - Checking convergence {}", norm); auto const result = norm < 1e-8 * candidate.size(); *previous = candidate; return result; }; // Now we can create the sdmm convex minimizer // Its parameters are set by calling member functions with appropriate names. auto sdmm = sopt::algorithm::SDMM() .itermax(500) // maximum number of iterations .gamma(1) .conjugate_gradient(std::numeric_limits::max(), 1e-12) .is_converged(relative) // Any number of (proximal g_i, L_i) pairs can be added // L_i can be a matrix .append(prox_g0, L0) // L_i can be a pair of functions applying a linear transform and its adjoint .append(prox_g1, L1_direct, L1_adjoint); t_Vector result; t_Vector const input = t_Vector::Random(N); auto const diagnostic = sdmm(result, input); // diagnostic should tell us the function converged // it also contains diagnostic.niters - the number of iterations, and cg_diagnostic - the // diagnostic from the last call to the conjugate gradient. if(not diagnostic.good) throw std::runtime_error("Did not converge!"); // Lets test we are at a minimum by recreating the objective function // and checking that stepping in any direction raises its value auto const objective = [&target0, &target1, &L0, &L1](t_Vector const &x) { return (L0 * x - target0).stableNorm() + (L1 * x - target1).stableNorm(); }; auto const minimum = objective(result); for(int i(0); i < N; ++i) { t_Vector epsilon = t_Vector::Zero(N); epsilon(i) = 1e-4; auto const at_x_plus_epsilon = objective(input + epsilon); if(minimum >= at_x_plus_epsilon) throw std::runtime_error("That's no minimum!"); } return 0; } sopt-2.0.0/cpp/examples/sdmm/inpainting.cc000066400000000000000000000117201277570055300205210ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include // This header is not part of the installed sopt interface // It is only present in tests #include #include // \min_{x} ||\Psi^Tx||_1 \quad \mbox{s.t.} \quad ||y - Ax||_2 < \epsilon and x \geq 0 int main(int argc, char const **argv) { // Some typedefs for simplicity typedef double Scalar; // Column vector - linear algebra - A * x is a matrix-vector multiplication // type expected by SDMM typedef sopt::Vector Vector; // Matrix - linear algebra - A * x is a matrix-vector multiplication // type expected by SDMM typedef sopt::Matrix Matrix; // Image - 2D array - A * x is a coefficient-wise multiplication // Type expected by wavelets and image write/read functions typedef sopt::Image Image; std::string const input = argc >= 2 ? argv[1] : "cameraman256"; std::string const output = argc == 3 ? argv[2] : "none"; if(argc > 3) { std::cout << "Usage:\n" "$ " << argv[0] << " [input [output]]\n\n" "- input: path to the image to clean (or name of standard SOPT image)\n" "- output: filename pattern for output image\n"; exit(0); } // Set up random numbers for C and C++ auto const seed = std::time(0); std::srand((unsigned int)seed); std::mt19937 mersenne(std::time(0)); // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); SOPT_HIGH_LOG("Read input file {}", input); Image const image = sopt::notinstalled::read_standard_tiff(input); SOPT_HIGH_LOG("Initializing sensing operator"); sopt::t_uint nmeasure = 0.33 * image.size(); auto const sampling = sopt::linear_transform(sopt::Sampling(image.size(), nmeasure, mersenne)); SOPT_HIGH_LOG("Initializing wavelets"); auto const wavelet = sopt::wavelets::factory("DB4", 4); auto const psi = sopt::linear_transform(wavelet, image.rows(), image.cols()); SOPT_HIGH_LOG("Computing sdmm parameters"); Vector const y0 = sampling * Vector::Map(image.data(), image.size()); auto const snr = 30.0; auto const sigma = y0.stableNorm() / std::sqrt(y0.size()) * std::pow(10.0, -(snr / 20.0)); auto const epsilon = std::sqrt(nmeasure + 2 * std::sqrt(y0.size())) * sigma; SOPT_HIGH_LOG("Create dirty vector"); std::normal_distribution<> gaussian_dist(0, sigma); Vector y(y0.size()); for(sopt::t_int i = 0; i < y0.size(); i++) y(i) = y0(i) + gaussian_dist(mersenne); // Write dirty imagte to file if(output != "none") { Vector const dirty = sampling.adjoint() * y; sopt::utilities::write_tiff(Matrix::Map(dirty.data(), image.rows(), image.cols()), "dirty_" + output + ".tiff"); } SOPT_HIGH_LOG("Initializing convergence function"); auto relvar = sopt::RelativeVariation(5e-2); auto convergence = [&y, &sampling, &psi, &relvar](sopt::Vector const &x) -> bool { SOPT_MEDIUM_LOG("||x - y||_2: {}", (y - sampling * x).stableNorm()); SOPT_MEDIUM_LOG("||Psi^Tx||_1: {}", sopt::l1_norm(psi.adjoint() * x)); SOPT_MEDIUM_LOG("||abs(x) - x||_2: {}", (x.array().abs().matrix() - x).stableNorm()); return relvar(x); }; SOPT_HIGH_LOG("Creating SDMM Functor"); auto const sdmm = sopt::algorithm::SDMM() .itermax(3000) .gamma(0.1) .conjugate_gradient(200, 1e-8) .is_converged(convergence) // Any number of (proximal g_i, L_i) pairs can be added // ||Psi^dagger x||_1 .append(sopt::proximal::l1_norm, psi.adjoint(), psi) // ||y - A x|| < epsilon .append(sopt::proximal::translate(sopt::proximal::L2Ball(epsilon), -y), sampling) // x in positive quadrant .append(sopt::proximal::positive_quadrant); SOPT_HIGH_LOG("Allocating result vector"); Vector result(image.size()); SOPT_HIGH_LOG("Starting SDMM"); auto const diagnostic = sdmm(result, Vector::Zero(image.size())); SOPT_HIGH_LOG("SDMM returned {}", diagnostic.good); // diagnostic should tell us the function converged // it also contains diagnostic.niters - the number of iterations, and cg_diagnostic - the // diagnostic from the last call to the conjugate gradient. if(not diagnostic.good) throw std::runtime_error("Did not converge!"); SOPT_HIGH_LOG("SOPT-SDMM converged in {} iterations", diagnostic.niters); if(output != "none") sopt::utilities::write_tiff(Matrix::Map(result.data(), image.rows(), image.cols()), output + ".tiff"); return 0; } sopt-2.0.0/cpp/examples/sdmm/reweighted.cc000066400000000000000000000144341277570055300205150ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // This header is not part of the installed sopt interface // It is only present in tests #include #include // \min_{x} ||W_j\Psi^Tx||_1 \quad \mbox{s.t.} \quad ||y - Ax||_2 < \epsilon and x \geq 0 // with W_j = ||\Psi^Tx_{j-1}||_1 // By iterating this algorithm, we can approximate L0 from L1. int main(int argc, char const **argv) { // Some typedefs for simplicity typedef double Scalar; // Column vector - linear algebra - A * x is a matrix-vector multiplication // type expected by SDMM typedef sopt::Vector Vector; // Matrix - linear algebra - A * x is a matrix-vector multiplication // type expected by SDMM typedef sopt::Matrix Matrix; // Image - 2D array - A * x is a coefficient-wise multiplication // Type expected by wavelets and image write/read functions typedef sopt::Image Image; std::string const input = argc >= 2 ? argv[1] : "cameraman256"; std::string const output = argc == 3 ? argv[2] : "none"; if(argc > 3) { std::cout << "Usage:\n" "$ " << argv[0] << " [input [output]]\n\n" "- input: path to the image to clean (or name of standard SOPT image)\n" "- output: filename pattern for output image\n"; exit(0); } // Set up random numbers for C and C++ auto const seed = std::time(0); std::srand((unsigned int)seed); std::mt19937 mersenne(std::time(0)); // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); SOPT_HIGH_LOG("Read input file {}", input); Image const image = sopt::notinstalled::read_standard_tiff(input); SOPT_HIGH_LOG("Initializing sensing operator"); sopt::t_uint nmeasure = 0.33 * image.size(); auto const sampling = sopt::linear_transform(sopt::Sampling(image.size(), nmeasure, mersenne)); SOPT_HIGH_LOG("Initializing wavelets"); auto const wavelet = sopt::wavelets::factory("DB4", 4); auto const psi = sopt::linear_transform(wavelet, image.rows(), image.cols()); SOPT_HIGH_LOG("Computing sdmm parameters"); Vector const y0 = sampling * Vector::Map(image.data(), image.size()); auto const snr = 30.0; auto const sigma = y0.stableNorm() / std::sqrt(y0.size()) * std::pow(10.0, -(snr / 20.0)); auto const epsilon = std::sqrt(nmeasure + 2 * std::sqrt(y0.size())) * sigma; SOPT_HIGH_LOG("Create dirty vector"); std::normal_distribution<> gaussian_dist(0, sigma); Vector y(y0.size()); for(sopt::t_int i = 0; i < y0.size(); i++) y(i) = y0(i) + gaussian_dist(mersenne); // Write dirty imagte to file if(output != "none") { Vector const dirty = sampling.adjoint() * y; sopt::utilities::write_tiff(Matrix::Map(dirty.data(), image.rows(), image.cols()), "dirty_" + output + ".tiff"); } SOPT_HIGH_LOG("Initializing convergence function"); auto relvar = sopt::RelativeVariation(5e-2); auto convergence = [&y, &sampling, &psi, &relvar](sopt::Vector const &x) -> bool { SOPT_MEDIUM_LOG("||x - y||_2: {}", (y - sampling * x).stableNorm()); SOPT_MEDIUM_LOG("||Psi^Tx||_1: {}", sopt::l1_norm(psi.adjoint() * x)); SOPT_MEDIUM_LOG("||abs(x) - x||_2: {}", (x.array().abs().matrix() - x).stableNorm()); return relvar(x); }; SOPT_HIGH_LOG("Creating SDMM Functor"); auto const sdmm = sopt::algorithm::SDMM() .itermax(3000) .gamma(0.1) .conjugate_gradient(200, 1e-8) .is_converged(convergence) // Any number of (proximal g_i, L_i) pairs can be added // ||Psi^dagger x||_1 .append(sopt::proximal::l1_norm, psi.adjoint(), psi) // ||y - A x|| < epsilon .append(sopt::proximal::translate(sopt::proximal::L2Ball(epsilon), -y), sampling) // x in positive quadrant .append(sopt::proximal::positive_quadrant); SOPT_HIGH_LOG("Creating the reweighted algorithm"); // positive_quadrant projects the result of SDMM on the positive quadrant. // This follows the reweighted algorithm in the original C implementation. auto const posq = positive_quadrant(sdmm); typedef std::remove_const::type t_PosQuadSDMM; auto const min_delta = sigma * std::sqrt(y.size()) / std::sqrt(8 * image.size()); // Sets weight after each sdmm iteration. // In practice, this means replacing the proximal of the l1 objective function. auto set_weights = [](t_PosQuadSDMM &sdmm, Vector const &weights) { sdmm.algorithm().proximals(0) = [weights](Vector &out, Scalar gamma, Vector const &x) { out = sopt::soft_threshhold(x, gamma * weights); }; }; auto call_PsiT = [&psi](t_PosQuadSDMM const &, Vector const &x) -> Vector { return psi.adjoint() * x; }; auto const reweighted = sopt::algorithm::reweighted(posq, set_weights, call_PsiT) .itermax(5) .min_delta(min_delta) .is_converged(sopt::RelativeVariation(1e-3)); SOPT_HIGH_LOG("Computing warm-start SDMM"); auto warm_start = sdmm(Vector::Zero(image.size())); warm_start.x = sopt::positive_quadrant(warm_start.x); SOPT_HIGH_LOG("SDMM returned {}", warm_start.good); SOPT_HIGH_LOG("Computing warm-start SDMM"); auto const result = reweighted(warm_start); // result should tell us the function converged // it also contains result.niters - the number of iterations, and cg_diagnostic - the // result from the last call to the conjugate gradient. if(not result.good) throw std::runtime_error("Did not converge!"); SOPT_HIGH_LOG("SOPT-SDMM converged in {} iterations", result.niters); if(output != "none") sopt::utilities::write_tiff(Matrix::Map(result.algo.x.data(), image.rows(), image.cols()), output + ".tiff"); return 0; } sopt-2.0.0/cpp/examples/soft_threshhold.cc000066400000000000000000000005641277570055300206240ustar00rootroot00000000000000#include #include int main(int, char const **) { sopt::Array<> input(6); input << 1e1, 2e1, 3e1, 4e1, 1e4, 2e4; if(not(sopt::soft_threshhold(input, 2.5e1).head(2).array() < 1e-8).all()) throw std::exception(); if(not(sopt::soft_threshhold(input, 2.5e1).tail(4).array() > 1e-8).all()) throw std::exception(); return 0; } sopt-2.0.0/cpp/examples/wavelets.cc000066400000000000000000000022411277570055300172510ustar00rootroot00000000000000#include int main(int, char const **) { // Creates Daubechies 4 wavelet, with 5 levels auto const wavelets = sopt::wavelets::factory("DB4", 5); // Creates a random signal sopt::Image input = sopt::Image::Random(128, 128); // Now gets its coefficients auto coefficients = wavelets.direct(input); // And transform back auto recover = wavelets.indirect(coefficients); // Check the reconstruction is corrrect if(not input.isApprox(recover)) throw std::exception(); // To save on memory allocation we could also use a pre-allocated matrix; coefficients.fill(0); recover.fill(0); wavelets.direct(coefficients, input); wavelets.indirect(coefficients, recover); if(not input.isApprox(recover)) throw std::exception(); // Finally, it is possible to use expressions // For instance, we can do a 1d transform on a single row wavelets.direct(coefficients.row(2).transpose(), input.row(2).transpose() * 2); wavelets.indirect(coefficients.row(2).transpose(), recover.row(2).transpose()); if(not input.row(2).isApprox(recover.row(2) * 0.5)) throw std::exception(); return 0; } sopt-2.0.0/cpp/regressions/000077500000000000000000000000001277570055300156365ustar00rootroot00000000000000sopt-2.0.0/cpp/regressions/CMakeLists.txt000066400000000000000000000004561277570055300204030ustar00rootroot00000000000000add_regression(sdmm_inpainting LABELS sdmm LIBRARIES tools_for_tests sopt) add_regression(l1_proximal LABELS sdmm LIBRARIES sopt tools_for_tests sopt) add_regression(padmm_inpainting LABELS sdmm LIBRARIES tools_for_tests sopt) add_regression(reweighted_sdmm LABELS sdmm LIBRARIES tools_for_tests sopt) sopt-2.0.0/cpp/regressions/l1_proximal.cc000066400000000000000000000102611277570055300203740ustar00rootroot00000000000000#include #include #include #include #include #include #include "sopt/l1_proximal.h" #include "sopt_prox.h" #include "tools_for_tests/cdata.h" std::random_device rd; std::default_random_engine rengine(rd()); template sopt::Matrix concatenated_permutations(sopt::t_uint i, sopt::t_uint j) { std::vector cols(j); std::iota(cols.begin(), cols.end(), 0); std::shuffle(cols.begin(), cols.end(), rengine); assert(j % i == 0); auto const N = j / i; auto const elem = 1e0 / std::sqrt(static_cast::type>(N)); sopt::Matrix result = sopt::Matrix::Zero(i, cols.size()); for(typename sopt::Matrix::Index k(0); k < result.cols(); ++k) result(cols[k] / N, k) = elem; return result; } template sopt::Vector c_proximal(sopt::proximal::L1 const &l1, typename sopt::real_type::type gamma, sopt::Vector const &x, bool pos = false, bool tf = false) { using namespace sopt; typedef typename sopt::real_type::type Real; int const nr = (l1.Psi().adjoint() * x).size(); Vector weights = l1.weights(); if(l1.weights().size() == 1) weights = l1.weights()(1) * Vector::Ones(nr); CData const psi_data{nr, x.size(), l1.Psi(), 0, 0}; sopt_prox_l1param params = { 0, // verbosity static_cast(l1.itermax()), // max iter l1.tolerance(), // relative change l1.nu(), // nu tf ? 1 : 0, // tight frame pos ? 1 : 0 // Positivity constraints }; Vector xin = x; Vector result = Vector::Zero(x.size()); Vector dummy = Vector::Zero(nr); Vector sol = Vector::Zero(x.size()); Vector u = Vector::Zero(nr); Vector v = Vector::Zero(nr); sopt_prox_l1(static_cast(result.data()), static_cast(xin.data()), x.size(), nr, &direct_transform, (void **)&psi_data, &adjoint_transform, (void **)&psi_data, weights.data(), gamma, std::is_same::value ? 1 : 0, params, static_cast(dummy.data()), static_cast(sol.data()), static_cast(u.data()), static_cast(v.data())); return result; } TEST_CASE("Compare L1 proximals", "") { using namespace sopt; typedef std::complex Scalar; auto l1 = proximal::L1(); Vector const input = Vector::Random(15); SECTION("Check tight frame") { auto const Psi = concatenated_permutations(input.size(), input.size() * 10); auto const weights = Vector::Random(Psi.cols()).array().abs().matrix().eval(); auto const gamma = 1e0 / static_cast(weights.size()); l1.Psi(Psi).weights(weights).tolerance(1e-12).itermax(10000); auto const cpp = l1.tight_frame(gamma, input); auto const c = c_proximal(l1, gamma, input, false, true); CHECK(cpp.isApprox(c)); } SECTION("Check general case") { auto const Psi = Matrix::Random(input.size(), input.size() * 10).eval(); auto const weights = Vector::Random(Psi.cols()).array().abs().matrix().eval(); auto const gamma = 1e0 / static_cast(weights.size()); SECTION("No constraints") { for(auto i : {2, 10, 25, 500, 1000}) { l1.Psi(Psi).weights(weights).tolerance(1e-12).itermax(i - 1); auto const c = c_proximal(l1, gamma, input, false, false); auto const cpp = l1.itermax(i)(gamma, input); CHECK(cpp.proximal.isApprox(c, 1e-8 * c.array().abs().maxCoeff())); } } SECTION("Positivity constraints") { for(auto i : {2, 10, 25, 500, 1000}) { l1.Psi(Psi).weights(weights).tolerance(1e-12).itermax(i - 1).positivity_constraint(true); auto const c = c_proximal(l1, gamma, input, true, false); auto const cpp = l1.itermax(i)(gamma, input); CAPTURE(c.transpose()); CAPTURE(cpp.proximal.transpose()); CHECK(cpp.proximal.isApprox(c, 1e-8 * c.array().abs().maxCoeff())); } } } } sopt-2.0.0/cpp/regressions/padmm_inpainting.cc000066400000000000000000000101051277570055300214600ustar00rootroot00000000000000#include #include #include #include #include "sopt/imaging_padmm.h" #include "sopt/logging.h" #include "sopt/proximal.h" #include "sopt/relative_variation.h" #include "sopt/sampling.h" #include "sopt/wavelets.h" #include "tools_for_tests/cdata.h" #include "tools_for_tests/directories.h" #include "tools_for_tests/inpainting.h" #include "tools_for_tests/tiffwrappers.h" #include "sopt_l1.h" typedef double Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; sopt::algorithm::ImagingProximalADMM create_admm(sopt::LinearTransform const &phi, sopt::LinearTransform const &psi, sopt_l1_param_padmm const ¶ms, t_Vector const &target) { using namespace sopt; return algorithm::ImagingProximalADMM(target) .itermax(params.max_iter + 1) .gamma(params.gamma) .relative_variation(params.rel_obj) .l2ball_proximal_epsilon(params.epsilon) .tight_frame(params.paraml1.tight == 1) .l1_proximal_tolerance(params.paraml1.rel_obj) .l1_proximal_nu(params.paraml1.nu) .l1_proximal_itermax(params.paraml1.max_iter) .l1_proximal_positivity_constraint(params.paraml1.pos == 1) .l1_proximal_real_constraint(params.real_out) .residual_convergence(params.epsilon * params.epsilon_tol_scale) .lagrange_update_scale(params.lagrange_update_scale) .nu(params.nu) .Psi(psi) .Phi(phi) // just for show, 1 is the default value, so these calls do not do anything .l2ball_proximal_weights(Vector::Ones(1)) .l1_proximal_weights(Vector::Ones(1)); } TEST_CASE("Compare ADMM C++ and C", "") { using namespace sopt; // Read image and create target vector y Image<> const image = notinstalled::read_standard_tiff("cameraman256"); t_uint const nmeasure = 0.5 * image.size(); extern std::unique_ptr mersenne; auto const sampling = linear_transform(Sampling(image.size(), nmeasure, *mersenne)); auto const y = dirty(sampling, image, *mersenne); sopt_l1_param_padmm params{ 0, // verbosity 200, // max iter 0.1, // gamma 0.0005, // relative change epsilon(sampling, image), // radius of the l2ball 1, // real out 1, // real meas { 0, // verbose = 1; 8, // max_iter = 50; 0.01, // rel_obj = 0.01; 1, // nu = 1; 0, // tight = 0; 1, // pos = 1; }, 1.001, // epsilon tol scale 0.9, // lagrange_update_scale 1.0, // nu }; // Create c++ SDMM auto const wavelet = wavelets::factory("DB2", 2); auto const psi = linear_transform(wavelet, image.rows(), image.cols()); // Create C bindings for C++ operators CData const sampling_data{image.size(), y.size(), sampling, 0, 0}; CData const psi_data{image.size(), image.size(), psi, 0, 0}; // Try increasing number of iterations and check output of c and c++ algorithms are the same for(t_uint i : {1, 5, 10}) { SECTION(fmt::format("With {} iterations", i)) { sopt_l1_param_padmm c_params = params; c_params.max_iter = i; auto admm = ::create_admm(sampling, psi, c_params, y); auto const cpp = admm(); t_Vector c = t_Vector::Zero(image.size()); t_Vector l1_weights = t_Vector::Ones(image.size()); t_Vector l2_weights = t_Vector::Ones((sampling * image).size()); sopt_l1_solver_padmm( (void *)c.data(), c.size(), &direct_transform, (void **)&sampling_data, &adjoint_transform, (void **)&sampling_data, &direct_transform, (void **)&psi_data, &adjoint_transform, (void **)&psi_data, // synthesis c.size(), (void *)y.data(), y.size(), l1_weights.data(), l2_weights.data(), c_params); CAPTURE(cpp.x.head(5).transpose()); CAPTURE(c.head(5).transpose()); CHECK(cpp.x.isApprox(c)); } }; } sopt-2.0.0/cpp/regressions/reweighted_sdmm.cc000066400000000000000000000117361277570055300213240ustar00rootroot00000000000000#include #include #include #include #include #include "sopt/logging.h" #include "sopt/positive_quadrant.h" #include "sopt/proximal.h" #include "sopt/relative_variation.h" #include "sopt/reweighted.h" #include "sopt/sampling.h" #include "sopt/sdmm.h" #include "sopt/wavelets.h" #include "tools_for_tests/cdata.h" #include "tools_for_tests/directories.h" #include "tools_for_tests/inpainting.h" #include "tools_for_tests/tiffwrappers.h" #include "sopt_l1.h" typedef double Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; sopt::algorithm::SDMM create_sdmm(sopt::LinearTransform const &sampling, sopt::LinearTransform const &psi, t_Vector const &y, sopt_l1_sdmmparam const ¶ms) { using namespace sopt; return algorithm::SDMM() .itermax(params.max_iter) .gamma(params.gamma) .conjugate_gradient(params.cg_max_iter, params.cg_tol) .is_converged(RelativeVariation(params.rel_obj)) .append(proximal::l1_norm, psi.adjoint(), psi) .append(proximal::translate(proximal::L2Ball(params.epsilon), -y), sampling) .append(proximal::positive_quadrant); } sopt::algorithm::Reweighted>> create_rwsdmm(sopt::algorithm::SDMM const &sdmm, sopt::LinearTransform const &psi, sopt_l1_rwparam const ¶ms) { using namespace sopt::algorithm; auto set_weights = [](PositiveQuadrant> &sdmm, t_Vector const &weights) { sdmm.algorithm().proximals(0) = [weights](t_Vector &out, Scalar gamma, t_Vector const &x) { out = sopt::soft_threshhold(x, gamma * weights); }; }; auto call_PsiT = [&psi](PositiveQuadrant> const &, t_Vector const &x) -> t_Vector { return psi.adjoint() * x; }; auto const pq = positive_quadrant(sdmm); return reweighted(pq, set_weights, call_PsiT) .itermax(params.max_iter) .min_delta(params.sigma) .is_converged(sopt::RelativeVariation(params.rel_var)); } TEST_CASE("Compare Reweighted SDMMS", "") { using namespace sopt; // Read image and create target vector y Image<> const image = notinstalled::read_standard_tiff("cameraman256"); t_uint const nmeasure = 0.5 * image.size(); extern std::unique_ptr mersenne; auto const sampling = linear_transform(Sampling(image.size(), nmeasure, *mersenne)); auto const y = dirty(sampling, image, *mersenne); sopt_l1_sdmmparam params = { 10, // verbosity 2, // max iter 0.1, // gamma 0.01, // relative change epsilon(sampling, image), // radius of the l2ball 1e-3, // Relative tolerance on epsilon std::is_same::type>::value ? 1 : 0, // real data 200, // cg max iter 1e-8, // cg tol }; sopt_l1_rwparam rwparam = { 0, 5, 0.001, sigma(sampling, image) * std::sqrt(y.size()) / std::sqrt(8 * image.size()), 0}; // Create c++ SDMM auto const wavelet = wavelets::factory("DB2", 2); auto const psi = linear_transform(wavelet, image.rows(), image.cols()); // Create C bindings for C++ operators CData const sampling_data{image.size(), y.size(), sampling, 0, 0}; CData const psi_data{image.size(), image.size(), psi, 0, 0}; auto sdmm = ::create_sdmm(sampling, psi, y, params); auto warm_start = sdmm(t_Vector::Zero(image.size())); warm_start.x = positive_quadrant(warm_start.x); // Try increasing number of iterations and check output of c and c++ algorithms are the same for(t_uint i : {0, 1, 2, 5}) { SECTION(fmt::format("With {} iterations", i)) { sopt_l1_rwparam c_params = rwparam; c_params.max_iter = i; auto rwsdmm = ::create_rwsdmm(sdmm, psi, c_params); auto const cpp = rwsdmm(warm_start); CHECK(image.size() == (psi.adjoint() * t_Vector::Zero(image.size())).size()); t_Vector c = t_Vector::Zero(image.size()); t_Vector weights = t_Vector::Ones((psi.adjoint() * c).size()); sopt_l1_rwsdmm((void *)c.data(), c.size(), &direct_transform, (void **)&sampling_data, &adjoint_transform, (void **)&sampling_data, &direct_transform, (void **)&psi_data, &adjoint_transform, (void **)&psi_data, // synthesis (psi.adjoint() * c).size(), (void *)y.data(), y.size(), params, c_params); CAPTURE(cpp.algo.x.head(25).tail(3).transpose()); CAPTURE(c.head(25).tail(3).transpose()); CAPTURE((cpp.algo.x - c).head(25).tail(3).transpose()); CHECK(cpp.algo.x.isApprox(c)); } }; } sopt-2.0.0/cpp/regressions/sdmm_inpainting.cc000066400000000000000000000076711277570055300213400ustar00rootroot00000000000000#include #include #include #include #include #include "sopt/logging.h" #include "sopt/proximal.h" #include "sopt/relative_variation.h" #include "sopt/sampling.h" #include "sopt/sdmm.h" #include "sopt/wavelets.h" #include "tools_for_tests/cdata.h" #include "tools_for_tests/directories.h" #include "tools_for_tests/inpainting.h" #include "tools_for_tests/tiffwrappers.h" #include "sopt_l1.h" typedef double Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; sopt::algorithm::SDMM create_sdmm(sopt::LinearTransform const &sampling, sopt::LinearTransform const &psi, t_Vector const &y, t_Vector const &weights, sopt_l1_sdmmparam const ¶ms) { using namespace sopt; auto weighted_l1_norm = [&weights](t_Vector &out, real_type::type gamma, t_Vector const &x) { assert(gamma > 1e-12); assert((weights.array() > 1e-12).all()); out = soft_threshhold(x, gamma * weights); }; return algorithm::SDMM() .itermax(params.max_iter) .gamma(params.gamma) .conjugate_gradient(params.cg_max_iter, params.cg_tol) .is_converged(RelativeVariation(params.rel_obj)) .append(weighted_l1_norm, psi.adjoint(), psi) .append(proximal::translate(proximal::L2Ball(params.epsilon), -y), sampling) .append(proximal::positive_quadrant); } TEST_CASE("Compare SDMMS", "") { using namespace sopt; // Read image and create target vector y Image<> const image = notinstalled::read_standard_tiff("cameraman256"); t_uint const nmeasure = 0.5 * image.size(); extern std::unique_ptr mersenne; auto const sampling = linear_transform(Sampling(image.size(), nmeasure, *mersenne)); auto const y = dirty(sampling, image, *mersenne); sopt_l1_sdmmparam params = { 0, // verbosity 50, // max iter 0.1, // gamma 0.01, // relative change epsilon(sampling, image), // radius of the l2ball 1e-3, // Relative tolerance on epsilon std::is_same::type>::value ? 1 : 0, // real data 200, // cg max iter 1e-8, // cg tol }; // Create c++ SDMM auto const wavelet = wavelets::factory("DB2", 2); auto const psi = linear_transform(wavelet, image.rows(), image.cols()); // Create C bindings for C++ operators CData const sampling_data{image.size(), y.size(), sampling, 0, 0}; CData const psi_data{image.size(), image.size(), psi, 0, 0}; t_Vector const weights = t_Vector::Random((psi * t_Vector::Zero(image.size())).size()).array().abs(); // Try increasing number of iterations and check output of c and c++ algorithms are the same for(t_uint i : {1, 2, 5, 10}) { SECTION(fmt::format("With {} iterations", i)) { t_Vector const input = t_Vector::Random(image.size()); sopt_l1_sdmmparam c_params = params; c_params.max_iter = i; auto sdmm = ::create_sdmm(sampling, psi, y, weights, c_params); t_Vector cpp(image.size()); sdmm(cpp, positive_quadrant(input)); t_Vector c = input; sopt_l1_sdmm((void *)c.data(), c.size(), &direct_transform, (void **)&sampling_data, &adjoint_transform, (void **)&sampling_data, &direct_transform, (void **)&psi_data, &adjoint_transform, (void **)&psi_data, // synthesis weights.size(), (void *)y.data(), y.size(), const_cast(weights.data()), c_params); CHECK(cpp.isApprox(c)); } }; } sopt-2.0.0/cpp/sopt/000077500000000000000000000000001277570055300142605ustar00rootroot00000000000000sopt-2.0.0/cpp/sopt/CMakeLists.txt000066400000000000000000000043611277570055300170240ustar00rootroot00000000000000# list of headers set(headers imaging_padmm.h logging.disabled.h maths.h proximal.h relative_variation.h sdmm.h wavelets.h conjugate_gradient.h l1_proximal.h logging.enabled.h padmm.h proximal_expression.h reweighted.h types.h wrapper.h exception.h linear_transform.h logging.h positive_quadrant.h real_type.h sampling.h ${PROJECT_BINARY_DIR}/include/sopt/config.h ) set(wavelet_headers wavelets/direct.h wavelets/indirect.h wavelets/innards.impl.h wavelets/sara.h wavelets/wavelet_data.h wavelets/wavelets.h ) set(sources wavelets/wavelets.cc wavelets/wavelet_data.cc) if(TIFF_FOUND) list(APPEND sources utilities.cc) list(APPEND headers utilities.h) endif() add_library(sopt SHARED ${sources}) add_dependencies(sopt lookup_dependencies) set(version "${Sopt_VERSION_MAJOR}.${Sopt_VERSION_MINOR}.${Sopt_VERSION_PATCH}") set_target_properties(sopt PROPERTIES VERSION ${version} SOVERSION ${version}) target_include_directories(sopt PUBLIC $ $ $) if(TIFF_FOUND) target_link_libraries(sopt ${TIFF_LIBRARY}) target_include_directories(sopt SYSTEM PUBLIC ${TIFF_INCLUDE_DIR}) endif() # Add spdlog as direct dependency if not downloaded if(SPDLOG_INCLUDE_DIR AND NOT spdlog_BUILT_AS_EXTERNAL_PROJECT) target_include_directories(sopt SYSTEM PUBLIC ${SPDLOG_INCLUDE_DIR}) elseif(SPDLOG_INCLUDE_DIR AND spdlog_BUILT_AS_EXTERNAL_PROJECT) target_include_directories(sopt SYSTEM PUBLIC $) endif() # Add eigen as direct dependency if not downloaded if(EIGEN3_INCLUDE_DIR AND NOT Eigen3_BUILT_AS_EXTERNAL_PROJECT) target_include_directories(sopt SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) elseif(EIGEN3_INCLUDE_DIR AND Eigen3_BUILT_AS_EXTERNAL_PROJECT) target_include_directories(sopt SYSTEM PUBLIC $) endif() if(TARGET openmp::openmp) target_link_libraries(sopt openmp::openmp) endif() install(FILES ${headers} DESTINATION include/sopt) install(FILES ${wavelet_headers} DESTINATION include/sopt/wavelets) install(TARGETS sopt EXPORT SoptCPPTargets DESTINATION share/cmake/sopt LIBRARY DESTINATION lib ARCHIVE DESTINATION lib INCLUDES DESTINATION include ) sopt-2.0.0/cpp/sopt/config.in.h000066400000000000000000000023271277570055300163070ustar00rootroot00000000000000#ifndef SOPT_CPP_CONFIG_H #define SOPT_CPP_CONFIG_H //! Problems with using and constructors #cmakedefine SOPT_HAS_USING #ifndef SOPT_HAS_USING #define SOPT_HAS_NOT_USING #endif //! True if using OPENMP #cmakedefine SOPT_OPENMP //! Macro to start logging or not #cmakedefine SOPT_DO_LOGGING #include #include namespace sopt { //! Returns library version inline std::string version() { return "@Sopt_VERSION@"; } //! Returns library version inline std::tuple version_tuple() { return std::tuple( @Sopt_VERSION_MAJOR@, @Sopt_VERSION_MINOR@, @Sopt_VERSION_PATCH@); } //! Returns library git reference, if known inline std::string gitref() { return "@Sopt_GITREF@"; } //! Default logging level inline std::string default_logging_level() { return "@SOPT_TEST_LOG_LEVEL@"; } //! Default logger name inline std::string default_logger_name() { return "@SOPT_LOGGER_NAME@"; } //! Wether to add color to the logger inline constexpr bool color_logger() { return @SOPT_COLOR_LOGGING@; } # ifdef SOPT_OPENMP //! Number of threads used during testing inline constexpr std::size_t number_of_threads_in_tests() { return @SOPT_DEFAULT_OPENMP_THREADS@; } # endif } #endif sopt-2.0.0/cpp/sopt/conjugate_gradient.h000066400000000000000000000121101277570055300202600ustar00rootroot00000000000000#ifndef SOPT_CONJUGATE_GRADIENT #define SOPT_CONJUGATE_GRADIENT #include "sopt/config.h" #include #include #include "sopt/logging.h" #include "sopt/types.h" #include "sopt/maths.h" #include "sopt/wrapper.h" namespace sopt { //! Solves $Ax = b$ for $x$, given $A$ and $b$. class ConjugateGradient { //! \brief Wraps around a matrix to fake a functor //! \details xout = A * xin becomes apply_matrix_instance(xout, xin); template class ApplyMatrix; public: //! Values indicating how the algorithm ran struct Diagnostic { //! Number of iterations t_uint niters; //! Residual t_real residual; //! Wether convergence was achieved bool good; }; //! Values indicating how the algorithm ran and its result; template struct DiagnosticAndResult : public Diagnostic { Vector result; }; //! \brief Creates conjugate gradient operator //! \param[in] itermax: Maximum number of iterations. 0 means algorithm breaks only if //! convergence is reached. //! \param[in] tolerance: Convergence criteria ConjugateGradient(t_uint itermax = std::numeric_limits::max(), t_real tolerance = 1e-8) : tolerance_(tolerance), itermax_(itermax) {} virtual ~ConjugateGradient() {} //! \brief Computes $x$ for $Ax=b$ //! \details Specialization that converts A from a matrix to a functor. //! This convertion is only so we write the conjugate-gradient algorithm only once for //! A as a matrix and A as a functor. A as a functor means A can be a complex operation, e.g. an //! FFT or two. template Diagnostic operator()(VECTOR &x, Eigen::MatrixBase const &A, Eigen::MatrixBase const &b) const { return implementation(x, A, b); } //! \brief Computes $x$ for $Ax=b$ //! \details Specialisation where A is a functor and b and x are matrix-like objects. This is //! the innermost specialization. template typename std::enable_if, T1>::value, Diagnostic>::type operator()(VECTOR &x, T1 const &A, Eigen::MatrixBase const &b) const { return implementation(x, details::wrap(A), b); } //! \brief Computes $x$ for $Ax=b$ //! \details Specialisation where x is constructed during call and returned. And x is a matrix //! rather than an array. template DiagnosticAndResult operator()(A_TYPE const &A, Eigen::MatrixBase const &b) const { DiagnosticAndResult result; result.result = Vector::Zero(b.size()); *static_cast(&result) = operator()(result.result, A, b); return result; } //! \brief Maximum number of iterations //! \details 0 means algorithm breaks only if convergence is reached. t_uint itermax() const { return itermax_; } //! \brief Sets maximum number of iterations //! \details 0 means algorithm breaks only if convergence is reached. void itermax(t_uint const &itermax) { itermax_ = itermax; } //! Tolerance criteria t_real tolerance() const { return tolerance_; } //! Sets tolerance criteria void tolerance(t_real const &tolerance) { if(tolerance <= 0e0) throw std::domain_error("Incorrect tolerance input"); tolerance_ = tolerance; } protected: //! Tolerance criteria t_real tolerance_; //! Maximum number of iteration t_uint itermax_; //! \details Work array to hold v Image<> work_v; //! Work array to hold r Image<> work_r; //! Work array to hold p Image<> work_p; private: //! \brief Just one implementation for all types //! \note This is a template function, to avoid repetition, but it is not declared in the //! header. template Diagnostic implementation(VECTOR &x, MATRIXLIKE const &A, Eigen::MatrixBase const &b) const; }; template ConjugateGradient::Diagnostic ConjugateGradient::implementation(VECTOR &x, MATRIXLIKE const &A, Eigen::MatrixBase const &b) const { typedef typename T1::Scalar Scalar; typedef typename real_type::type Real; x.resize(b.size()); if(std::abs((b.transpose().conjugate() * b)(0)) < tolerance()) { x.fill(0); return {0, 0, 1}; } Vector Ap(b.size()); x = b; Vector residuals = b - A * x; Vector p = residuals; Real residual = std::abs((residuals.transpose().conjugate() * residuals)(0)); t_uint i(0); for(; i < itermax(); ++i) { Ap = A * p; Scalar const alpha = residual / (p.transpose().conjugate() * Ap)(0); x += alpha * p; residuals -= alpha * Ap; Real new_residual = std::abs((residuals.transpose().conjugate() * residuals)(0)); SOPT_LOW_LOG("CG iteration {} - residuals: {}", i, new_residual); if(std::abs(new_residual) < tolerance()) { residual = new_residual; break; } p = residuals + new_residual / residual * p; residual = new_residual; } return {i, residual, residual < tolerance()}; } } /* sopt */ #endif sopt-2.0.0/cpp/sopt/exception.h000066400000000000000000000023671277570055300164370ustar00rootroot00000000000000#ifndef SOPT_EXCEPTION #define SOPT_EXCEPTION #include "sopt/config.h" #include #include #include namespace sopt { //! Root exception for sopt class Exception : public std::exception { protected: //! Constructor for derived classes Exception(std::string const &name, std::string const &filename, size_t lineno) : std::exception(), message(header(name, filename, lineno)) {} public: //! Creates exception Exception(std::string const &filename, size_t lineno) : Exception("sopt::Exception", filename, lineno) {} //! Creates message const char *what() const noexcept override { return message.c_str(); } //! Header of the message static std::string header(std::string const &name, std::string const &filename, size_t lineno) { std::ostringstream header; header << name << " at " << filename << ":" << lineno; return header.str(); } //! Adds to message template Exception &operator<<(OBJECT const &object) { std::ostringstream msg; msg << message << object; message = msg.str(); return *this; } private: //! Message to issue std::string message; }; #define SOPT_THROW(MSG) throw(sopt::Exception(__FILE__, __LINE__) << "\n" << MSG) } /* sopt */ #endif sopt-2.0.0/cpp/sopt/imaging_padmm.h000066400000000000000000000365061277570055300172340ustar00rootroot00000000000000#ifndef SOPT_L1_PROXIMAL_ADMM_H #define SOPT_L1_PROXIMAL_ADMM_H #include "sopt/config.h" #include #include #include #include "sopt/exception.h" #include "sopt/l1_proximal.h" #include "sopt/linear_transform.h" #include "sopt/logging.h" #include "sopt/padmm.h" #include "sopt/proximal.h" #include "sopt/types.h" namespace sopt { namespace algorithm { //! \brief Specialization of Proximal ADMM for Purify //! \details \f$\min_{x, z} f(x) + h(z)\f$ subject to \f$Φx + z = y\f$, where \f$f(x) = //! ||Ψ^Hx||_1 + i_C(x)\f$ and \f$h(x) = i_B(z)\f$ with \f$C = R^N_{+}\f$ and \f$B = {z \in R^M: //! ||z||_2 \leq \epsilon}\f$ template class ImagingProximalADMM : private ProximalADMM { //! Defines convergence behaviour struct Breaker; public: //! Scalar type typedef typename ProximalADMM::value_type value_type; typedef typename ProximalADMM::Scalar Scalar; typedef typename ProximalADMM::Real Real; typedef typename ProximalADMM::t_Vector t_Vector; typedef typename ProximalADMM::t_LinearTransform t_LinearTransform; typedef typename ProximalADMM::t_Proximal t_Proximal; typedef typename ProximalADMM::t_IsConverged t_IsConverged; using ProximalADMM::initial_guess; //! Values indicating how the algorithm ran struct Diagnostic : public ProximalADMM::Diagnostic { //! Diagnostic from calling L1 proximal typename proximal::L1::Diagnostic l1_diag; Diagnostic(t_uint niters = 0u, bool good = false, typename proximal::L1::Diagnostic const &l1diag = typename proximal::L1::Diagnostic()) : ProximalADMM::Diagnostic(niters, good), l1_diag(l1diag) {} Diagnostic(t_uint niters, bool good, typename proximal::L1::Diagnostic const &l1diag, t_Vector &&residual) : ProximalADMM::Diagnostic(niters, good, std::move(residual)), l1_diag(l1diag) {} }; //! Holds result vector as well struct DiagnosticAndResult : public Diagnostic { //! Output x t_Vector x; }; template ImagingProximalADMM(Eigen::MatrixBase const &target) : ProximalADMM(nullptr, nullptr, target), l1_proximal_(), l2ball_proximal_(1e0), tight_frame_(false), relative_variation_(1e-4), residual_convergence_(1e-4) { set_f_and_g_proximal_to_members_of_this(); } ImagingProximalADMM(ImagingProximalADMM const &c) : ProximalADMM(c), l1_proximal_(c.l1_proximal_), l2ball_proximal_(c.l2ball_proximal_), tight_frame_(c.tight_frame_), relative_variation_(c.relative_variation_), residual_convergence_(c.residual_convergence_) { set_f_and_g_proximal_to_members_of_this(); } ImagingProximalADMM(ImagingProximalADMM &&c) : ProximalADMM(std::move(c)), l1_proximal_(std::move(c.l1_proximal_)), l2ball_proximal_(std::move(c.l2ball_proximal_)), tight_frame_(c.tight_frame_), relative_variation_(c.relative_variation_), residual_convergence_(c.residual_convergence_) { set_f_and_g_proximal_to_members_of_this(); } void operator=(ImagingProximalADMM const &c) { ProximalADMM::operator=(c); l1_proximal_ = c.l1_proximal_; l2ball_proximal_ = c.l2ball_proximal_; tight_frame_ = c.tight_frame_; set_f_and_g_proximal_to_members_of_this(); } void operator=(ImagingProximalADMM &&c) { ProximalADMM::operator=(std::move(c)); l1_proximal_ = std::move(c.l1_proximal_); l2ball_proximal_ = std::move(c.l2ball_proximal_); tight_frame_ = std::move(c.tight_frame_); set_f_and_g_proximal_to_members_of_this(); } virtual ~ImagingProximalADMM() {} // Macro helps define properties that can be initialized as in // auto sdmm = ProximalADMM().prop0(value).prop1(value); #define SOPT_MACRO(NAME, TYPE, CODE) \ TYPE const &NAME() const { return NAME##_; } \ ImagingProximalADMM &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ CODE; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! The L1 proximal functioning as f SOPT_MACRO(l1_proximal, proximal::L1, set_f_and_g_proximal_to_members_of_this()); //! The weighted L2 proximal functioning as g SOPT_MACRO(l2ball_proximal, proximal::WeightedL2Ball, set_f_and_g_proximal_to_members_of_this()); //! Whether Ψ is a tight-frame or not SOPT_MACRO(tight_frame, bool, ); //! \brief Convergence of the relative variation of the objective functions //! \details If negative, this convergence criteria is disabled. SOPT_MACRO(relative_variation, Real, ); //! \brief Convergence of the residuals //! \details If negative, this convergence criteria is disabled. SOPT_MACRO(residual_convergence, Real, ); #undef SOPT_MACRO //! \brief Analysis operator Ψ //! \details Under-the-hood, the object is actually owned by the L1 proximal. t_LinearTransform const &Psi() const { return l1_proximal().Psi(); } //! Analysis operator Ψ template typename std::enable_if= 1, ImagingProximalADMM &>::type Psi(ARGS &&... args) { l1_proximal().Psi(std::forward(args)...); return *this; } //! \brief Analysis operator Φ t_LinearTransform const &Phi() const { return ProximalADMM::Phi(); } //! Φ initialized via some call to \ref linear_transform template typename std::enable_if= 1, ImagingProximalADMM &>::type Phi(ARGS &&... args) { ProximalADMM::Phi(std::forward(args)...); return *this; } //! target measurements t_Vector const &target() const { return ProximalADMM::target(); } //! target measurements template ImagingProximalADMM &target(Eigen::MatrixBase const &target) const { ProximalADMM::target(target); return *this; } //! \brief L1 proximal used during calculation //! \details Non-const version to setup the object. proximal::L1 &l1_proximal() { return l1_proximal_; } //! \brief Proximal of the L2 ball //! \details Non-const version to setup the object. proximal::WeightedL2Ball &l2ball_proximal() { return l2ball_proximal_; } //! Type-erased version of the l1 proximal t_Proximal const &f_proximal() { return ProximalADMM::f_proximal(); } //! Type-erased version of the l2 proximal t_Proximal const &g_proximal() { return ProximalADMM::g_proximal(); } // Forwards get/setters to L1 and L2Ball proximals // In practice, we end up with a bunch of functions that make it simpler to set or get values // associated with the two proximal operators. // E.g.: `paddm.l1_proximal_itermax(100).l2ball_epsilon(1e-2).l1_proximal_tolerance(1e-4)`. // ~~~ #define SOPT_MACRO(VAR, NAME, PROXIMAL) \ /** \brief Forwards to l1_proximal **/ \ decltype(std::declval const>().VAR()) NAME##_proximal_##VAR() const { \ return NAME##_proximal().VAR(); \ } \ /** \brief Forwards to l1_proximal **/ \ ImagingProximalADMM &NAME##_proximal_##VAR( \ decltype(std::declval const>().VAR()) VAR) { \ NAME##_proximal().VAR(VAR); \ return *this; \ } SOPT_MACRO(itermax, l1, L1); SOPT_MACRO(tolerance, l1, L1); SOPT_MACRO(positivity_constraint, l1, L1); SOPT_MACRO(real_constraint, l1, L1); SOPT_MACRO(fista_mixing, l1, L1); SOPT_MACRO(nu, l1, L1); SOPT_MACRO(weights, l1, L1); SOPT_MACRO(epsilon, l2ball, WeightedL2Ball); SOPT_MACRO(weights, l2ball, WeightedL2Ball); #undef SOPT_MACRO // Includes getters and redefines setters to return this object #define SOPT_MACRO(NAME) \ using ProximalADMM::NAME; \ /** \brief Forwards to ProximalADMM base class **/ \ ImagingProximalADMM &NAME(decltype(std::declval>().NAME()) NAME) { \ ProximalADMM::NAME(NAME); \ return *this; \ } SOPT_MACRO(itermax); SOPT_MACRO(gamma); SOPT_MACRO(nu); SOPT_MACRO(lagrange_update_scale); SOPT_MACRO(is_converged); #undef SOPT_MACRO //! Calls l1 proximal operator, checking for real constraints and tight frame template typename proximal::L1::Diagnostic l1_proximal(Eigen::MatrixBase &out, Real gamma, Eigen::MatrixBase const &x) const { return l1_proximal_real_constraint() ? call_l1_proximal(out, gamma, x.real().template cast()) : call_l1_proximal(out, gamma, x); } //! Forwards call to weighted L2 ball proximal template auto l2ball_proximal(Eigen::MatrixBase const &x) const -> decltype(std::declval const>()(Real(0), x)) { return l2ball_proximal()(Real(0), x); } //! \brief Call Proximal ADMM for L1 and L2 ball //! \param[out] out: Output x vector //! \param[in] guess: for both x and the residuals Diagnostic operator()(t_Vector &out, std::tuple const &guess) const { return operator()(out, std::get<0>(guess), std::get<1>(guess)); } //! \brief Call Proximal ADMM for L1 and L2 ball //! \param[out] out: Output x vector Diagnostic operator()(t_Vector &out) const { return operator()(out, initial_guess()); } //! \brief Calls Proximal ADMM for L1 and L2 ball //! \param[in] guess: for both x and the residuals DiagnosticAndResult operator()(std::tuple const &guess) const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, guess); return result; } //! \brief Calls Proximal ADMM for L1 and L2 ball //! \param[in] warm_start: uses result from previous run to restart the calculations DiagnosticAndResult operator()(DiagnosticAndResult const &warm_start) const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, warm_start.x, warm_start.residual); return result; } //! \brief Calls Proximal ADMM for L1 and L2 ball //! \param[in] warm_start: uses result from previous run to restart the calculations DiagnosticAndResult operator()() const { DiagnosticAndResult result; static_cast(result) = operator()(result.x); return result; } protected: //! Keeps track of the last call to the L1 proximal mutable typename proximal::L1::Diagnostic l1_diagnostic; //! Calls l1 proximal operator, checking for thight frame template typename proximal::L1::Diagnostic call_l1_proximal(Eigen::MatrixBase &out, Real gamma, Eigen::MatrixBase const &x) const { if(tight_frame()) { l1_proximal().tight_frame(out, gamma, x); return {0, 0, l1_proximal().objective(x, out, gamma), true}; } return l1_proximal()(out, gamma, x); } //! Sets the result from this call to L1 proximal so it can be used later void erased_f_proximal(t_Vector &out, Real gamma, t_Vector const &x) const { l1_diagnostic = l1_proximal(out, gamma, x); } //! References void set_f_and_g_proximal_to_members_of_this() { using namespace std::placeholders; ProximalADMM::f_proximal( std::bind(&ImagingProximalADMM::erased_f_proximal, this, _1, _2, _3)); ProximalADMM::g_proximal(std::cref(l2ball_proximal())); } //! \brief Call Proximal ADMM for L1 and L2 ball //! \param[out] out: Output x vector //! \param[in] guess: initial guess for the image //! \param[in] res: initial guess for the residual Diagnostic operator()(t_Vector &out, t_Vector const &guess, t_Vector const &res) const; }; template typename ImagingProximalADMM::Diagnostic ImagingProximalADMM:: operator()(t_Vector &out, t_Vector const &x_guess, t_Vector const &res_guess) const { SOPT_HIGH_LOG("Performing Proximal ADMM with L1 and L2 operators"); ProximalADMM::sanity_check(x_guess, res_guess); t_Vector lambda = t_Vector::Zero(target().size()); t_Vector z = t_Vector::Zero(target().size()); t_Vector residual = res_guess; out = x_guess; bool const has_user_convergence = static_cast(is_converged()); l1_diagnostic = {0, 0, 0, false}; SOPT_TRACE(" - Initialization"); std::pair objectives{sopt::l1_norm(Psi().adjoint() * out, l1_proximal_weights()), 0}; bool converged = false; for(t_uint niters(0); niters < itermax(); ++niters) { SOPT_LOW_LOG(" - Iteration {}/{}. ", niters, itermax()); ProximalADMM::iteration_step(out, residual, lambda, z); // print-out stuff objectives.second = objectives.first; objectives.first = sopt::l1_norm(Psi().adjoint() * out, l1_proximal_weights()); t_real const relative_objective = std::abs(objectives.first - objectives.second) / objectives.first; auto const residual_norm = sopt::l2_norm(residual, l2ball_proximal_weights()); SOPT_LOW_LOG(" - objective: obj value = {}, rel obj = {}", objectives.first, relative_objective); SOPT_LOW_LOG(" - Residuals: epsilon = {}, residual norm = {}", l2ball_proximal_epsilon(), residual_norm); // convergence stuff auto const user = (not has_user_convergence) or is_converged(out); auto const res = residual_convergence() <= 0e0 or residual_norm < residual_convergence(); auto const rel = relative_variation() <= 0e0 or relative_objective < relative_variation(); converged = user and rel and res; if(converged) { SOPT_MEDIUM_LOG(" - converged in {} of {} iterations", niters, itermax()); break; } } if(not converged) SOPT_ERROR(" - did not converge within {} iterations", itermax()); return {itermax(), converged, l1_diagnostic, std::move(residual)}; } } } /* sopt::algorithm */ #endif sopt-2.0.0/cpp/sopt/l1_proximal.h000066400000000000000000000400701277570055300166610ustar00rootroot00000000000000#ifndef SOPT_L1_PROXIMAL_H #define SOPT_L1_PROXIMAL_H #include "sopt/config.h" #include #include #include #include "sopt/linear_transform.h" #include "sopt/maths.h" #include "sopt/proximal_expression.h" namespace sopt { namespace proximal { //! \brief L1 proximal, including linear transform //! \details This function computes the prox operator of the l1 //! norm for the input vector \f$x\f$. It solves the problem: //! \f[ min_{z} 0.5||x - z||_2^2 + γ ||Ψ^† z||_w1 \f] //! where \f$Ψ \in C^{N_x \times N_r} \f$ is the sparsifying operator, and \f[|| ||_w1\f] is the //! weighted L1 norm. template class L1TightFrame { public: //! Underlying scalar type typedef SCALAR Scalar; //! Underlying real scalar type typedef typename real_type::type Real; L1TightFrame() : Psi_(linear_transform_identity()), nu_(1e0), weights_(Vector::Ones(1)) {} #define SOPT_MACRO(NAME, TYPE) \ TYPE const &NAME() const { return NAME##_; } \ L1TightFrame &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! Linear transform applied to input prior to L1 norm SOPT_MACRO(Psi, LinearTransform>); //! Bound on the squared norm of the operator Ψ SOPT_MACRO(nu, Real); #undef SOPT_MACRO //! Weights of the l1 norm Vector const &weights() const { return weights_; } //! Weights of the l1 norm template L1TightFrame &weights(Eigen::MatrixBase const &w) { if((w.array() < 0e0).any()) SOPT_THROW("Weights cannot be negative"); if(w.stableNorm() < 1e-12) SOPT_THROW("Weights cannot be null"); weights_ = w; return *this; } //! Set weights to a single value L1TightFrame &weights(Real const &value) { if(value <= 0e0) SOPT_THROW("Weight cannot be negative or null"); weights_ = Vector::Ones(1) * value; return *this; } //! Set Ψ and Ψ^† using arguments that sopt::linear_transform understands template typename std::enable_if= 1, L1TightFrame &>::type Psi(ARGS &&... args) { Psi_ = linear_transform(std::forward(args)...); return *this; } //! Computes proximal for given γ template typename std::enable_if::value == is_complex::value and is_complex::value == is_complex::value>::type operator()(Eigen::MatrixBase &out, Real gamma, Eigen::MatrixBase const &x) const; //! Lazy version template ProximalExpression const &, T0> operator()(Real const &gamma, Eigen::MatrixBase const &x) const { return {*this, gamma, x}; } //! \f[ 0.5||x - z||_2^2 + γ||Ψ^† z||_w1 \f] template typename std::enable_if::value == is_complex::value and is_complex::value == is_complex::value, Real>::type objective(Eigen::MatrixBase const &x, Eigen::MatrixBase const &z, Real const &gamma) const; protected: //! Weights associated with the l1-norm Vector weights_; }; template template typename std::enable_if::value == is_complex::value and is_complex::value == is_complex::value>::type L1TightFrame:: operator()(Eigen::MatrixBase &out, Real gamma, Eigen::MatrixBase const &x) const { Vector const psit_x = Psi().adjoint() * x; if(weights().size() == 1) out = Psi() * (soft_threshhold(psit_x, nu() * gamma * weights()(0)) - psit_x) / nu() + x; else out = Psi() * (soft_threshhold(psit_x, nu() * gamma * weights()) - psit_x) / nu() + x; SOPT_LOW_LOG("Prox L1: objective = {}", objective(x, out, gamma)); } template template typename std::enable_if::value == is_complex::value and is_complex::value == is_complex::value, typename real_type::type>::type L1TightFrame::objective(Eigen::MatrixBase const &x, Eigen::MatrixBase const &z, Real const &gamma) const { return 0.5 * (x - z).squaredNorm() + gamma * sopt::l1_norm(Psi().adjoint() * z, weights()); } //! \brief L1 proximal, including linear transform //! \details This function computes the prox operator of the l1 //! norm for the input vector \f$x\f$. It solves the problem: //! \f[ min_{z} 0.5||x - z||_2^2 + γ ||Ψ^† z||_w1 \f] //! where \f$Ψ \in C^{N_x \times N_r} \f$ is the sparsifying operator, and \f[|| ||_w1\f] is the //! weighted L1 norm. template class L1 : protected L1TightFrame { public: //! Functor to do fista mixing class FistaMixing; //! Functor to do no mixing class NoMixing; //! Functor to check convergence and cycling class Breaker; using L1TightFrame::objective; //! Underlying scalar type typedef typename L1TightFrame::Scalar Scalar; //! Underlying real scalar type typedef typename L1TightFrame::Real Real; //! How did calling L1 go? struct Diagnostic { //! Number of iterations t_uint niters; //! Relative variation of the objective function Real relative_variation; //! Value of the objective function Real objective; //! Wether convergence was achieved bool good; Diagnostic(t_uint niters = 0, Real relative_variation = 0, Real objective = 0, bool good = false) : niters(niters), relative_variation(relative_variation), objective(objective), good(good) { } }; //! Result from calling L1 struct DiagnosticAndResult : public Diagnostic { //! The proximal value Vector proximal; }; //! Computes proximal for given γ template Diagnostic operator()(Eigen::MatrixBase &out, Real gamma, Vector const &x) const { // Note that we *must* call eval on x, in case it is an expression involving out if(fista_mixing()) return operator()(out, gamma, x, FistaMixing()); else return operator()(out, gamma, x, NoMixing()); } //! Lazy version template DiagnosticAndResult operator()(Real const &gamma, Eigen::MatrixBase const &x) const { DiagnosticAndResult result; static_cast(result) = operator()(result.proximal, gamma, x); return result; } L1() : L1TightFrame(), itermax_(0), tolerance_(1e-8), positivity_constraint_(false), real_constraint_(false), fista_mixing_(true) {} #define SOPT_MACRO(NAME, TYPE) \ TYPE const &NAME() const { return NAME##_; } \ L1 &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! \brief Maximum number of iterations before bailing out //! \details 0 means algorithm breaks only if convergence is reached. SOPT_MACRO(itermax, t_uint); //! Tolerance criteria SOPT_MACRO(tolerance, Real); //! Whether to apply positivity constraints SOPT_MACRO(positivity_constraint, bool); //! Whether the output should be constrained to be real SOPT_MACRO(real_constraint, bool); //! Whether to do fista mixing or not SOPT_MACRO(fista_mixing, bool); #undef SOPT_MACRO //! Weights of the l1 norm Vector const &weights() const { return L1TightFrame::weights(); } //! Set weights to an array of values template L1 &weights(Eigen::MatrixBase const &w) { L1TightFrame::weights(w); return *this; } //! Set weights to a single value L1 &weights(Real const &w) { L1TightFrame::weights(w); return this; } //! Bounds on the squared norm of the operator Ψ Real nu() const { return L1TightFrame::nu(); } //! Sets the bound on the squared norm of the operator Ψ L1 &nu(Real const &nu) { L1TightFrame::nu(nu); return *this; } //! Linear transform applied to input prior to L1 norm LinearTransform> const &Psi() const { return L1TightFrame::Psi(); } //! Set Ψ and Ψ^† using a matrix template typename std::enable_if= 1, L1 &>::type Psi(ARGS &&... args) { L1TightFrame::Psi(std::forward(args)...); return *this; } //! \brief Special case if Ψ ia a tight frame. //! \see L1TightFrame template auto tight_frame(T &&... args) const -> decltype(this->L1TightFrame::operator()(std::forward(args)...)) { return this->L1TightFrame::operator()(std::forward(args)...); } protected: //! Applies one or another soft-threshhold, depending on weight template Vector apply_soft_threshhold(Real gamma, Eigen::MatrixBase const &x) const; //! Applies constraints to input expression template void apply_constraints(Eigen::MatrixBase &out, Eigen::MatrixBase const &x) const; //! Operation with explicit mixing step template Diagnostic operator()(Eigen::MatrixBase &out, Real gamma, Vector const &x, MIXING mixing) const; }; //! Computes proximal for given γ template template typename L1::Diagnostic L1:: operator()(Eigen::MatrixBase &out, Real gamma, Vector const &x, MIXING mixing) const { SOPT_MEDIUM_LOG(" Starting Proximal L1 operator:"); t_uint niters = 0; out = x; Breaker breaker(objective(out, x, gamma), tolerance(), false); // not fista_mixing()); SOPT_LOW_LOG(" - iter {}, prox_fval = {}", niters, breaker.current()); Vector const res = Psi().adjoint() * out; Vector u_l1 = 1e0 / nu() * (res - apply_soft_threshhold(gamma, res)); apply_constraints(out, x - Psi() * u_l1); // Move on to other iterations for(++niters; niters < itermax() or itermax() == 0; ++niters) { auto const do_break = breaker(objective(x, out, gamma)); SOPT_LOW_LOG(" - iter {}, prox_fval = {}, rel_fval = {}", niters, breaker.current(), breaker.relative_variation()); if(do_break) break; Vector const res = u_l1 * nu() + Psi().adjoint() * out; mixing(u_l1, 1e0 / nu() * (res - apply_soft_threshhold(gamma, res)), niters); apply_constraints(out, x - Psi() * u_l1); } if(breaker.two_cycle()) SOPT_WARN("Two-cycle detected when computing L1"); if(breaker.converged()) { SOPT_LOW_LOG(" Proximal L1 operator converged at {} in {} iterations", breaker.current(), niters); } else SOPT_ERROR(" Proximal L1 operator did not converge after {} iterations", niters); return {niters, breaker.relative_variation(), breaker.current(), breaker.converged()}; } template template Vector L1::apply_soft_threshhold(Real gamma, Eigen::MatrixBase const &x) const { if(weights().size() == 1) return soft_threshhold(x, gamma * weights()(0)); else return soft_threshhold(x, gamma * weights()); } template template void L1::apply_constraints(Eigen::MatrixBase &out, Eigen::MatrixBase const &x) const { if(positivity_constraint()) out = sopt::positive_quadrant(x); else if(real_constraint()) out = x.real().template cast(); else out = x; } template class L1::FistaMixing { public: typedef typename real_type::type Real; FistaMixing() : t(1){}; template void operator()(Vector &previous, Eigen::MatrixBase const &unmixed, t_uint iter) { // reset if(iter == 0) { previous = unmixed; return; } if(iter <= 1) t = next(1); auto const prior_t = t; t = next(t); auto const alpha = (prior_t - 1) / t; previous = (1e0 + alpha) * unmixed.derived() - alpha * previous; } static Real next(Real t) { return 0.5 + 0.5 * std::sqrt(1e0 + 4e0 * t * t); } private: Real t; }; template class L1::NoMixing { public: template void operator()(Vector &previous, Eigen::MatrixBase const &unmixed, t_uint) { previous = unmixed; } }; template class L1::Breaker { public: typedef typename real_type::type Real; //! Constructs a breaker object //! \param[in] objective: the first objective function //! \param[in] tolerance: Convergence criteria for convergence //! \param[in] do_two_cycle: Whether to enable two cycle detections. Only necessary when mixing //! is not enabled. Breaker(Real objective, Real tolerance = 1e-8, bool do_two_cycle = true) : tolerance_(tolerance), iter(0), objectives({{objective, 0, 0, 0}}), do_two_cycle(do_two_cycle) {} //! True if we should break out of loop bool operator()(Real objective) { ++iter; objectives = {{objective, objectives[0], objectives[1], objectives[2]}}; return converged() or two_cycle(); } //! Current objective Real current() const { return objectives[0]; } //! Current objective Real previous() const { return objectives[1]; } //! Variation in the objective function Real relative_variation() const { return std::abs((current() - previous()) / current()); } //! \brief Whether we have a cycle of period two //! \details Cycling is prone to happen without mixing, it seems. bool two_cycle() const { return do_two_cycle and iter > 3 and std::abs(objectives[0] - objectives[2]) < tolerance() and std::abs(objectives[1] - objectives[3]) < tolerance(); } //! True if relative variation smaller than tolerance bool converged() const { // If current ~ 0, then defaults to absolute convergence // This is mainly to avoid a division by zero if(std::abs(current() * 1000) < tolerance()) return std::abs(previous() * 1000) < tolerance(); return relative_variation() < tolerance(); } //! Tolerance criteria Real tolerance() const { return tolerance_; } //! Tolerance criteria L1::Breaker &tolerance(Real tol) const { tolerance_ = tol; return *this; } protected: Real tolerance_; t_uint iter; std::array objectives; bool do_two_cycle; }; } } /* sopt::proximal */ #endif sopt-2.0.0/cpp/sopt/linear_transform.h000066400000000000000000000230111277570055300177730ustar00rootroot00000000000000#ifndef SOPT_OPERATORS_H #define SOPT_OPERATORS_H #include "sopt/config.h" #include #include #include #include #include "sopt/logging.h" #include "sopt/types.h" #include "sopt/maths.h" #include "sopt/wrapper.h" namespace sopt { namespace details { //! \brief Wraps a matrix into a function and its conjugate transpose //! \details This class helps to wrap matrices into functions, such that we can use and store them //! such that SDMM algorithms can refer to them. template class MatrixToLinearTransform; //! Wraps a tranposed matrix into a function and its conjugate transpose template class MatrixAdjointToLinearTransform; } //! Joins together direct and indirect operators template class LinearTransform : public details::WrapFunction { public: //! Type of the wrapped functions typedef OperatorFunction t_Function; //! Constructor //! \param[in] direct: function with signature void(VECTOR&, VECTOR const&) which applies a //! linear operator to a vector. //! \param[in] indirect: function with signature void(VECTOR&, VECTOR const&) which applies a //! the conjugate transpose linear operator to a vector. //! \param[in] sizes: 3 integer elements (a, b, c) such that if the input to linear operator is //! of size N, then the output is of size (a * N) / b + c. A similar quantity is deduced for //! the indirect operator. LinearTransform(t_Function const &direct, t_Function const &indirect, std::array sizes = {{1, 1, 0}}) : LinearTransform( direct, sizes, indirect, {{sizes[1], sizes[0], sizes[0] == 0 ? 0 : -(sizes[2] * sizes[1]) / sizes[0]}}) { assert(sizes[0] != 0); } //! Constructor //! \param[in] direct: function with signature void(VECTOR&, VECTOR const&) which applies a //! linear operator to a vector. //! \param[in] dsizes: 3 integer elements (a, b, c) such that if the input to the linear //! operator is of size N, then the output is of size (a * N) / b + c. //! \param[in] indirect: function with signature void(VECTOR&, VECTOR const&) which applies a //! the conjugate transpose linear operator to a vector. //! \param[in] dsizes: 3 integer elements (a, b, c) such that if the input to the indirect //! linear operator is of size N, then the output is of size (a * N) / b + c. LinearTransform(t_Function const &direct, std::array dsizes, t_Function const &indirect, std::array isizes) : LinearTransform(details::wrap(direct, dsizes), details::wrap(indirect, isizes)) {} LinearTransform(details::WrapFunction const &direct, details::WrapFunction const &indirect) : details::WrapFunction(direct), indirect_(indirect) {} LinearTransform(LinearTransform const &c) : details::WrapFunction(c), indirect_(c.indirect_) {} LinearTransform(LinearTransform &&c) : details::WrapFunction(std::move(c)), indirect_(std::move(c.indirect_)) {} void operator=(LinearTransform const &c) { details::WrapFunction::operator=(c); indirect_ = c.indirect_; } void operator=(LinearTransform &&c) { details::WrapFunction::operator=(std::move(c)); indirect_ = std::move(c.indirect_); } //! Indirect transform LinearTransform adjoint() const { return {indirect_, static_cast const &>(*this)}; } using details::WrapFunction::operator*; using details::WrapFunction::sizes; using details::WrapFunction::rows; private: //! Function applying conjugate transpose operator details::WrapFunction indirect_; }; //! Helper function to creates a function operator //! \param[in] direct: function with signature void(VECTOR&, VECTOR const&) which applies a //! linear operator to a vector. //! \param[in] indirect: function with signature void(VECTOR&, VECTOR const&) which applies a //! the conjugate transpose linear operator to a vector. //! \param[in] sizes: 3 integer elements (a, b, c) such that if the input to linear operator is //! of size N, then the output is of size (a * N) / b + c. A similar quantity is deduced for //! the indirect operator. template LinearTransform linear_transform(OperatorFunction const &direct, OperatorFunction const &indirect, std::array const &sizes = {{1, 1, 0}}) { return {direct, indirect, sizes}; } //! Helper function to creates a function operator //! \param[in] direct: function with signature void(VECTOR&, VECTOR const&) which applies a //! linear operator to a vector. //! \param[in] dsizes: 3 integer elements (a, b, c) such that if the input to the linear //! operator is of size N, then the output is of size (a * N) / b + c. //! \param[in] indirect: function with signature void(VECTOR&, VECTOR const&) which applies a //! the conjugate transpose linear operator to a vector. //! \param[in] dsizes: 3 integer elements (a, b, c) such that if the input to the indirect //! linear operator is of size N, then the output is of size (a * N) / b + c. template LinearTransform linear_transform(OperatorFunction const &direct, std::array const &dsizes, OperatorFunction const &indirect, std::array const &isizes) { return {direct, dsizes, indirect, isizes}; } //! Convenience no-op function template LinearTransform &linear_transform(LinearTransform &passthrough) { return passthrough; } //! Creates a linear transform from a pair of wrappers template LinearTransform linear_transform(details::WrapFunction const &direct, details::WrapFunction const &adjoint) { return {direct, adjoint}; } namespace details { template class MatrixToLinearTransform { //! The underlying raw matrix type typedef typename std::remove_const::type>::type Raw; //! The matrix underlying the expression typedef typename Raw::PlainObject PlainMatrix; public: //! The output type typedef typename std::conditional, PlainMatrix>::value, Vector, Array>::type PlainObject; //! \brief Creates from an expression //! \details Expression is evaluated and the result stored internally. This object owns a //! copy of the matrix. It might share it with a few friendly neighbors. template MatrixToLinearTransform(Eigen::MatrixBase const &A) : matrix(std::make_shared(A)) {} //! Creates from a shared matrix. MatrixToLinearTransform(std::shared_ptr const &x) : matrix(x){}; //! Performs operation void operator()(PlainObject &out, PlainObject const &x) const { #ifndef NDEBUG if((*matrix).cols() != x.size()) SOPT_THROW("Input vector and matrix do not match: ") << out.cols() << " columns for " << x.size() << " elements."; #endif out = (*matrix) * x; } //! \brief Returns conjugate transpose operator //! \details The matrix is shared. MatrixAdjointToLinearTransform adjoint() const { return MatrixAdjointToLinearTransform(matrix); } private: //! Wrapped matrix std::shared_ptr matrix; }; template class MatrixAdjointToLinearTransform { public: typedef typename MatrixToLinearTransform::PlainObject PlainObject; //! \brief Creates from an expression //! \details Expression is evaluated and the result stored internally. This object owns a //! copy of the matrix. It might share it with a few friendly neighbors. template MatrixAdjointToLinearTransform(Eigen::MatrixBase const &A) : matrix(std::make_shared(A)) {} //! Creates from a shared matrix. MatrixAdjointToLinearTransform(std::shared_ptr const &x) : matrix(x){}; //! Performs operation void operator()(PlainObject &out, PlainObject const &x) const { #ifndef NDEBUG if((*matrix).rows() != x.size()) SOPT_THROW("Input vector and matrix adjoint do not match: ") << out.cols() << " rows for " << x.size() << " elements."; #endif out = matrix->adjoint() * x; } //! \brief Returns adjoint operator //! \details The matrix is shared. MatrixToLinearTransform adjoint() const { return MatrixToLinearTransform(matrix); } private: std::shared_ptr matrix; }; } //! Helper function to creates a function operator template LinearTransform> linear_transform(Eigen::MatrixBase const &A) { details::MatrixToLinearTransform> const matrix(A); if(A.rows() == A.cols()) return {matrix, matrix.adjoint()}; else { t_int const gcd = details::gcd(A.cols(), A.rows()); t_int const a = A.cols() / gcd; t_int const b = A.rows() / gcd; return {matrix, matrix.adjoint(), {{b, a, 0}}}; } } //! Helper function to create a linear transform that's just the identity template LinearTransform> linear_transform_identity() { return {[](Vector &out, Vector const &in) { out = in; }, [](Vector &out, Vector const &in) { out = in; }}; } } #endif sopt-2.0.0/cpp/sopt/logging.disabled.h000066400000000000000000000013771277570055300176350ustar00rootroot00000000000000#ifndef SOPT_LOGGING_DISABLED_H #define SOPT_LOGGING_DISABLED_H #include "sopt/config.h" #include #include namespace sopt { namespace logging { //! Name of the sopt logger const std::string name_prefix = "sopt::"; inline std::shared_ptr initialize(std::string const &) { return nullptr; } inline std::shared_ptr initialize() { return nullptr; } inline std::shared_ptr get(std::string const &) { return nullptr; } inline std::shared_ptr get() { return nullptr; } inline void set_level(std::string const &, std::string const &){}; inline void set_level(std::string const &){}; inline bool has_level(std::string const &, std::string const &) { return false; } } } //! \macro For internal use only #define SOPT_LOG_(...) #endif sopt-2.0.0/cpp/sopt/logging.enabled.h000066400000000000000000000051351277570055300174540ustar00rootroot00000000000000#ifndef SOPT_LOGGING_ENABLED_H #define SOPT_LOGGING_ENABLED_H #include "sopt/config.h" #include #include #include "sopt/exception.h" namespace sopt { namespace logging { void set_level(std::string const &level, std::string const &name = ""); //! \brief Initializes a logger. //! \details Logger only exists as long as return is kept alive. inline std::shared_ptr initialize(std::string const &name = "") { auto const result = spdlog::stdout_logger_mt(default_logger_name() + name, color_logger()); set_level(default_logging_level(), name); return result; } //! Returns shared pointer to logger or null if it does not exist inline std::shared_ptr get(std::string const &name = "") { return spdlog::get(default_logger_name() + name); } //! \brief Sets loggin level //! \details Levels can be one of //! - "trace" //! - "debug" //! - "info" //! - "warn" //! - "err" //! - "critical" //! - "off" inline void set_level(std::string const &level, std::string const &name) { auto const logger = get(name); if(not logger) SOPT_THROW("No logger by the name of ") << name << ".\n"; #define SOPT_MACRO(LEVEL) \ if(level == #LEVEL) \ logger->set_level(spdlog::level::LEVEL) SOPT_MACRO(trace); else SOPT_MACRO(debug); else SOPT_MACRO(info); else SOPT_MACRO(warn); else SOPT_MACRO(err); else SOPT_MACRO(critical); else SOPT_MACRO(off); #undef SOPT_MACRO else SOPT_THROW("Unknown logging level ") << level << "\n"; } inline bool has_level(std::string const &level, std::string const &name = "") { auto const logger = get(name); if(not logger) return false; #define SOPT_MACRO(LEVEL) \ if(level == #LEVEL) \ return logger->level() >= spdlog::level::LEVEL SOPT_MACRO(trace); else SOPT_MACRO(debug); else SOPT_MACRO(info); else SOPT_MACRO(warn); else SOPT_MACRO(err); else SOPT_MACRO(critical); else SOPT_MACRO(off); #undef SOPT_MACRO else SOPT_THROW("Unknown logging level ") << level << "\n"; } } } //! \macro For internal use only #define SOPT_LOG_(NAME, TYPE, ...) \ if(auto sopt_logging_##__func__##_##__LINE__ = sopt::logging::get(NAME)) \ sopt_logging_##__func__##_##__LINE__->TYPE(__VA_ARGS__) #endif sopt-2.0.0/cpp/sopt/logging.h000066400000000000000000000021661277570055300160640ustar00rootroot00000000000000#ifndef SOPT_LOGGING_H #define SOPT_LOGGING_H #include "sopt/config.h" #ifdef SOPT_DO_LOGGING #include "sopt/logging.enabled.h" #else #include "sopt/logging.disabled.h" #endif //! \macro Normal but significant condition or critical error #define SOPT_NOTICE(...) SOPT_LOG_(, critical, __VA_ARGS__) //! \macro Something is definitely wrong, algorithm exits #define SOPT_ERROR(...) SOPT_LOG_(, error, __VA_ARGS__) //! \macro Something might be going wrong #define SOPT_WARN(...) SOPT_LOG_(, warn, __VA_ARGS__) //! \macro Verbose informational message about normal condition #define SOPT_INFO(...) SOPT_LOG_(, info, __VA_ARGS__) //! \macro Output some debugging #define SOPT_DEBUG(...) SOPT_LOG_(, debug, __VA_ARGS__) //! \macro Output internal values of no interest to anyone //! \details Except maybe when debugging. #define SOPT_TRACE(...) SOPT_LOG_(, trace, __VA_ARGS__) //! High priority message #define SOPT_HIGH_LOG(...) SOPT_LOG_(, critical, __VA_ARGS__) //! Medium priority message #define SOPT_MEDIUM_LOG(...) SOPT_LOG_(, info, __VA_ARGS__) //! Low priority message #define SOPT_LOW_LOG(...) SOPT_LOG_(, debug, __VA_ARGS__) #endif sopt-2.0.0/cpp/sopt/maths.h000066400000000000000000000153721277570055300155550ustar00rootroot00000000000000#ifndef SOPT_MATHS_H #define SOPT_MATHS_H #include "sopt/config.h" #include #include #include #include #include "sopt/exception.h" #include "sopt/types.h" namespace sopt { //! Computes the standard deviation of a vector template typename real_type::type standard_deviation(Eigen::ArrayBase const &x) { return (x - x.mean()).matrix().stableNorm() / std::sqrt(x.size()); } //! Computes the standard deviation of a vector template typename real_type::type standard_deviation(Eigen::MatrixBase const &x) { return standard_deviation(x.array()); } //! abs(x) < threshhold ? 0: x - sgn(x) * threshhold template typename std::enable_if::value or is_complex::value, SCALAR>::type soft_threshhold(SCALAR const &x, typename real_type::type const &threshhold) { auto const normalized = std::abs(x); return normalized < threshhold ? SCALAR(0) : (x * (SCALAR(1) - threshhold / normalized)); } namespace details { //! Expression to create projection onto positive orthant template class ProjectPositiveQuadrant { public: SCALAR operator()(const SCALAR &value) const { return std::max(value, SCALAR(0)); } }; //! Specialization for complex numbers template class ProjectPositiveQuadrant> { public: SCALAR operator()(SCALAR const &value) const { return std::max(value, SCALAR(0)); } std::complex operator()(std::complex const &value) const { return {operator()(value.real()), SCALAR(0)}; } }; //! Helper template typedef to instantiate soft_threshhold that takes an Eigen object template using SoftThreshhold = decltype( std::bind(soft_threshhold, std::placeholders::_1, typename real_type::type(1))); } //! Expression to create projection onto positive quadrant template Eigen::CwiseUnaryOp, const T> positive_quadrant(Eigen::DenseBase const &input) { typedef details::ProjectPositiveQuadrant Projector; typedef Eigen::CwiseUnaryOp UnaryOp; return UnaryOp(input.derived(), Projector()); } //! Expression to create soft-threshhold template Eigen::CwiseUnaryOp, const T> soft_threshhold(Eigen::DenseBase const &input, typename real_type::type const &threshhold) { typedef typename T::Scalar Scalar; typedef typename real_type::type Real; return Eigen::CwiseUnaryOp, const T> {input.derived(), std::bind(soft_threshhold, std::placeholders::_1, Real(threshhold))}; } //! \brief Expression to create soft-threshhold with multiple parameters //! \details Operates over a vector of threshholds: ``out(i) = soft_threshhold(x(i), h(i))`` //! Threshhold and input vectors must have the same size and type. The latter condition is enforced //! by CwiseBinaryOp, unfortunately. template typename std::enable_if::value and std::is_arithmetic::value, Eigen::CwiseBinaryOp>::type soft_threshhold(Eigen::DenseBase const &input, Eigen::DenseBase const &threshhold) { if(input.size() != threshhold.size()) SOPT_THROW("Threshhold and input should have the same size"); return {input.derived(), threshhold.derived(), soft_threshhold}; } //! \brief Expression to create soft-threshhold with multiple parameters //! \details Operates over a vector of threshholds: ``out(i) = soft_threshhold(x(i), h(i))`` //! Threshhold and input vectors must have the same size and type. The latter condition is enforced //! by CwiseBinaryOp, unfortunately. So we cast threshhold from real to complex and back. template typename std:: enable_if::value and std::is_arithmetic::value, Eigen::CwiseBinaryOp< typename T0::Scalar (*)(typename T0::Scalar const &, typename T0::Scalar const &), const T0, decltype(std::declval().template cast())>>::type soft_threshhold(Eigen::DenseBase const &input, Eigen::DenseBase const &threshhold) { if(input.size() != threshhold.size()) SOPT_THROW("Threshhold and input should have the same size: ") << threshhold.size() << " vs " << input.size(); typedef typename T0::Scalar Complex; auto const func = [](Complex const &x, Complex const &t) -> Complex { return soft_threshhold(x, t.real()); }; return {input.derived(), threshhold.derived().template cast(), func}; } //! Computes weighted L1 norm template typename real_type::type l1_norm(Eigen::ArrayBase const &input, Eigen::ArrayBase const &weights) { if(weights.size() == 1) return input.cwiseAbs().sum() * std::abs(weights(0)); return (input.cwiseAbs() * weights).real().sum(); } //! Computes weighted L1 norm template typename real_type::type l1_norm(Eigen::MatrixBase const &input, Eigen::MatrixBase const &weight) { return l1_norm(input.array(), weight.array()); } //! Computes L1 norm template typename real_type::type l1_norm(Eigen::ArrayBase const &input) { return input.cwiseAbs().sum(); } //! Computes L1 norm template typename real_type::type l1_norm(Eigen::MatrixBase const &input) { return l1_norm(input.array()); } //! Computes weighted L2 norm template typename real_type::type l2_norm(Eigen::ArrayBase const &input, Eigen::ArrayBase const &weights) { if(weights.size() == 1) return input.matrix().stableNorm() * std::abs(weights(0)); return (input * weights).matrix().stableNorm(); } //! Computes weighted L2 norm template typename real_type::type l2_norm(Eigen::MatrixBase const &input, Eigen::MatrixBase const &weights) { return l2_norm(input.derived().array(), weights.derived().array()); } namespace details { //! Greatest common divisor inline t_int gcd(t_int a, t_int b) { return b == 0 ? a : gcd(b, a % b); } } } /* sopt */ #endif sopt-2.0.0/cpp/sopt/padmm.h000066400000000000000000000220501277570055300155260ustar00rootroot00000000000000#ifndef SOPT_PROXIMAL_ADMM_H #define SOPT_PROXIMAL_ADMM_H #include "sopt/config.h" #include #include #include "sopt/exception.h" #include "sopt/linear_transform.h" #include "sopt/logging.h" #include "sopt/types.h" namespace sopt { namespace algorithm { //! \brief Proximal Alternate Direction method of mutltipliers //! \details \f$\min_{x, z} f(x) + h(z)\f$ subject to \f$Φx + z = y\f$. \f$y\f$ is a target vector. template class ProximalADMM { public: //! Scalar type typedef SCALAR value_type; //! Scalar type typedef value_type Scalar; //! Real type typedef typename real_type::type Real; //! Type of then underlying vectors typedef Vector t_Vector; //! Type of the Ψ and Ψ^H operations, as well as Φ and Φ^H typedef LinearTransform t_LinearTransform; //! Type of the convergence function typedef ConvergenceFunction t_IsConverged; //! Type of the convergence function typedef ProximalFunction t_Proximal; //! Values indicating how the algorithm ran struct Diagnostic { //! Number of iterations t_uint niters; //! Wether convergence was achieved bool good; //! the residual from the last iteration t_Vector residual; Diagnostic(t_uint niters = 0u, bool good = false) : niters(niters), good(good), residual(t_Vector::Zero(0)) {} Diagnostic(t_uint niters, bool good, t_Vector &&residual) : niters(niters), good(good), residual(std::move(residual)) {} }; //! Holds result vector as well struct DiagnosticAndResult : public Diagnostic { //! Output x t_Vector x; }; //! Setups ProximalADMM //! \param[in] f_proximal: proximal operator of the \f$f\f$ function. //! \param[in] g_proximal: proximal operator of the \f$g\f$ function template ProximalADMM(t_Proximal const &f_proximal, t_Proximal const &g_proximal, Eigen::MatrixBase const &target) : itermax_(std::numeric_limits::max()), gamma_(1e-8), nu_(1), lagrange_update_scale_(0.9), is_converged_(), Phi_(linear_transform_identity()), f_proximal_(f_proximal), g_proximal_(g_proximal), target_(target) {} virtual ~ProximalADMM() {} // Macro helps define properties that can be initialized as in // auto sdmm = ProximalADMM().prop0(value).prop1(value); #define SOPT_MACRO(NAME, TYPE) \ TYPE const &NAME() const { return NAME##_; } \ ProximalADMM &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! Maximum number of iterations SOPT_MACRO(itermax, t_uint); //! γ parameter SOPT_MACRO(gamma, Real); //! ν parameter SOPT_MACRO(nu, Real); //! Lagrange update scale β SOPT_MACRO(lagrange_update_scale, Real); //! A function verifying convergence SOPT_MACRO(is_converged, t_IsConverged); //! Measurement operator SOPT_MACRO(Phi, t_LinearTransform); //! First proximal SOPT_MACRO(f_proximal, t_Proximal); //! Second proximal SOPT_MACRO(g_proximal, t_Proximal); #undef SOPT_MACRO //! \brief Simplifies calling the proximal of f. void f_proximal(t_Vector &out, Real gamma, t_Vector const &x) const { f_proximal()(out, gamma, x); } //! \brief Simplifies calling the proximal of f. void g_proximal(t_Vector &out, Real gamma, t_Vector const &x) const { g_proximal()(out, gamma, x); } //! Vector of target measurements t_Vector const &target() const { return target_; } //! Sets the vector of target measurements template ProximalADMM &target(Eigen::MatrixBase const &target) { target_ = target; return *this; } //! Facilitates call to user-provided convergence function bool is_converged(t_Vector const &x) const { return static_cast(is_converged()) and is_converged()(x); } //! \brief Calls Proximal ADMM //! \param[out] out: Output vector x Diagnostic operator()(t_Vector &out) const { return operator()(out, initial_guess()); } //! \brief Calls Proximal ADMM //! \param[out] out: Output vector x //! \param[in] guess: initial guess Diagnostic operator()(t_Vector &out, std::tuple const &guess) const { return operator()(out, std::get<0>(guess), std::get<1>(guess)); } //! \brief Calls Proximal ADMM //! \param[in] guess: initial guess DiagnosticAndResult operator()(std::tuple const &guess) const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, guess); return result; } //! \brief Calls Proximal ADMM //! \param[in] guess: initial guess DiagnosticAndResult operator()() const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, initial_guess()); return result; } //! Makes it simple to chain different calls to PADMM DiagnosticAndResult operator()(DiagnosticAndResult const &warmstart) const { DiagnosticAndResult result = warmstart; static_cast(result) = operator()(result.x, warmstart.x, warmstart.residual); return result; } //! Set Φ and Φ^† using arguments that sopt::linear_transform understands template typename std::enable_if= 1, ProximalADMM &>::type Phi(ARGS &&... args) { Phi_ = linear_transform(std::forward(args)...); return *this; } //! \brief Computes initial guess for x and the residual using the targets //! \details with y the vector of measurements //! - x = Φ^T y / ν //! - residuals = Φ x - y std::tuple initial_guess() const { std::tuple guess; std::get<0>(guess) = Phi().adjoint() * target() / nu(); std::get<1>(guess) = Phi() * std::get<0>(guess) - target(); return guess; } protected: void iteration_step(t_Vector &out, t_Vector &residual, t_Vector &lambda, t_Vector &z) const; //! Checks input makes sense void sanity_check(t_Vector const &x_guess, t_Vector const &res_guess) const { if((Phi().adjoint() * target()).size() != x_guess.size()) SOPT_THROW("target, adjoint measurement operator and input vector have inconsistent sizes"); if(target().size() != res_guess.size()) SOPT_THROW("target and residual vector have inconsistent sizes"); if((Phi() * x_guess).size() != target().size()) SOPT_THROW("target, measurement operator and input vector have inconsistent sizes"); if(not static_cast(is_converged())) SOPT_WARN("No convergence function was provided: algorithm will run for {} steps", itermax()); } //! \brief Calls Proximal ADMM //! \param[out] out: Output vector x //! \param[in] guess: initial guess //! \param[in] residuals: initial residuals Diagnostic operator()(t_Vector &out, t_Vector const &guess, t_Vector const &res) const; //! Vector of measurements t_Vector target_; }; template void ProximalADMM::iteration_step(t_Vector &out, t_Vector &residual, t_Vector &lambda, t_Vector &z) const { g_proximal(z, gamma(), -lambda - residual); f_proximal(out, gamma() / nu(), out - Phi().adjoint() * (residual + lambda + z) / nu()); residual = Phi() * out - target(); lambda += lagrange_update_scale() * (residual + z); } template typename ProximalADMM::Diagnostic ProximalADMM:: operator()(t_Vector &out, t_Vector const &x_guess, t_Vector const &res_guess) const { SOPT_HIGH_LOG("Performing Proximal ADMM"); sanity_check(x_guess, res_guess); t_Vector lambda = t_Vector::Zero(target().size()); t_Vector z = t_Vector::Zero(target().size()); t_Vector residual = res_guess; out = x_guess; for(t_uint niters(0); niters < itermax(); ++niters) { SOPT_LOW_LOG(" - Iteration {}/{}", niters, itermax()); iteration_step(out, residual, lambda, z); SOPT_LOW_LOG(" - Sum of residuals: {}", residual.array().abs().sum()); if(is_converged(out)) { SOPT_MEDIUM_LOG(" - converged in {} of {} iterations", niters, itermax()); return {niters, true}; } } // check function exists, otherwise, don't know if convergence is meaningful if(static_cast(is_converged())) SOPT_ERROR(" - did not converge within {} iterations", itermax()); return {itermax(), false, std::move(residual)}; } } } /* sopt::algorithm */ #endif sopt-2.0.0/cpp/sopt/positive_quadrant.h000066400000000000000000000040121277570055300201670ustar00rootroot00000000000000#ifndef SOPT_PROJECTED_ALGORITHM_H #define SOPT_PROJECTED_ALGORITHM_H #include "sopt/linear_transform.h" #include "sopt/types.h" namespace sopt { namespace algorithm { //! \brief Computes according to given algorithm and then projects it to the positive quadrant //! \details C implementation of the reweighted algorithms uses this, even-though the solutions are //! already constrained to the positive quadrant. template class PositiveQuadrant { public: //! Underlying algorithm typedef ALGORITHM Algorithm; //! Underlying scalar typedef typename Algorithm::Scalar Scalar; //! Underlying vector typedef typename Algorithm::t_Vector t_Vector; //! Underlying convergence functions typedef typename Algorithm::t_IsConverged t_IsConverged; //! Underlying result type typedef typename ALGORITHM::Diagnostic Diagnostic; //! Underlying result type typedef typename ALGORITHM::DiagnosticAndResult DiagnosticAndResult; PositiveQuadrant(Algorithm const &algo) : algorithm_(algo) {} PositiveQuadrant(Algorithm &&algo) : algorithm_(std::move(algo)) {} Algorithm &algorithm() { return algorithm_; } Algorithm const &algorithm() const { return algorithm_; } //! Performs algorithm and project results onto positive quadrant template Diagnostic operator()(t_Vector &out, T const &... args) const { auto const diagnostic = algorithm()(out, std::forward(args)...); out = positive_quadrant(out); return diagnostic; }; //! Performs algorithm and project results onto positive quadrant template DiagnosticAndResult operator()(T const &... args) const { auto result = algorithm()(std::forward(args)...); result.x = positive_quadrant(result.x); return result; }; protected: //! Underlying algorithm Algorithm algorithm_; }; //! Extended algorithm where the solution is projected on the positive quadrant template PositiveQuadrant positive_quadrant(ALGORITHM const &algo) { return {algo}; } } } #endif sopt-2.0.0/cpp/sopt/power_method.h000066400000000000000000000117701277570055300171330ustar00rootroot00000000000000#ifndef SOPT_POWER_METHO_H #define SOPT_POWER_METHO_H #include "sopt/config.h" #include #include #include "sopt/exception.h" #include "sopt/linear_transform.h" #include "sopt/logging.h" #include "sopt/types.h" namespace sopt { namespace algorithm { //! \brief Eigenvalue and eigenvector for eigenvalue with largest magnitude template class PowerMethod { public: //! Scalar type typedef SCALAR value_type; //! Scalar type typedef value_type Scalar; //! Real type typedef typename real_type::type Real; //! Type of then underlying vectors typedef Vector t_Vector; //! Type of the Ψ and Ψ^H operations, as well as Φ and Φ^H typedef LinearTransform t_LinearTransform; //! Holds result vector as well struct DiagnosticAndResult { //! Number of iterations t_uint niters; //! Wether convergence was achieved bool good; //! Magnitude of the eigenvalue Scalar magnitude; //! Corresponding eigenvector if converged Vector eigenvector; }; //! Setups ProximalADMM PowerMethod() : itermax_(std::numeric_limits::max()), tolerance_(1e-8) {} virtual ~PowerMethod() {} // Macro helps define properties that can be initialized as in // auto sdmm = ProximalADMM().prop0(value).prop1(value); #define SOPT_MACRO(NAME, TYPE) \ TYPE const &NAME() const { return NAME##_; } \ PowerMethod &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! Maximum number of iterations SOPT_MACRO(itermax, t_uint); //! Convergence criteria SOPT_MACRO(tolerance, Real); #undef SOPT_MACRO //! \brief Calls the power method for A.adjoint() * A DiagnosticAndResult AtA(t_LinearTransform const &A, t_Vector const &input) const; //! \brief Calls the power method for A, with A a matrix template DiagnosticAndResult operator()(Eigen::DenseBase const &A, t_Vector const &input) const; //! \brief Calls the power method for a given matrix-vector multiplication function DiagnosticAndResult operator()(OperatorFunction const &op, t_Vector const &input) const; protected: }; template typename PowerMethod::DiagnosticAndResult PowerMethod::AtA(t_LinearTransform const &A, t_Vector const &input) const { auto const op = [&A](t_Vector &out, t_Vector const &input) -> void { out = A.adjoint() * (A * input).eval(); }; return operator()(op, input); } template template typename PowerMethod::DiagnosticAndResult PowerMethod:: operator()(Eigen::DenseBase const &A, t_Vector const &input) const { Matrix const Ad = A.derived(); auto const op = [&Ad](t_Vector &out, t_Vector const &input) -> void { out = Ad * input; }; return operator()(op, input); } template typename PowerMethod::DiagnosticAndResult PowerMethod:: operator()(OperatorFunction const &op, t_Vector const &input) const { SOPT_INFO("Computing the upper bound of a given operator"); SOPT_INFO(" - input vector {}", input.transpose()); t_Vector eigenvector = input.normalized(); SOPT_INFO(" - eigenvector norm {}", eigenvector.stableNorm()); typename t_Vector::Scalar previous_magnitude = 1; bool converged = false; t_uint niters = 0; for(; niters < itermax() and converged == false; ++niters) { op(eigenvector, eigenvector); typename t_Vector::Scalar const magnitude = eigenvector.stableNorm() / static_cast(eigenvector.size()); auto const rel_val = std::abs((magnitude - previous_magnitude) / previous_magnitude); converged = rel_val < tolerance(); SOPT_INFO(" - Iteration {}/{} -- norm: {}", niters, itermax(), magnitude); eigenvector /= magnitude; previous_magnitude = magnitude; } // check function exists, otherwise, don't know if convergence is meaningful if(not converged) { SOPT_WARN(" - did not converge within {} iterations", itermax()); } else { SOPT_INFO(" - converged in {} of {} iterations", niters, itermax()); } return DiagnosticAndResult{itermax(), converged, previous_magnitude, eigenvector.normalized()}; } } } /* sopt::algorithm */ #endif sopt-2.0.0/cpp/sopt/proximal.h000066400000000000000000000154201277570055300162660ustar00rootroot00000000000000#ifndef SOPT_PROXIMAL_H #define SOPT_PROXIMAL_H #include "sopt/config.h" #include #include #include "sopt/proximal_expression.h" #include "sopt/maths.h" namespace sopt { //! Holds some standard proximals namespace proximal { //! Proximal of euclidian norm struct EuclidianNorm { template void operator()(Vector &out, typename real_type::type const &t, Eigen::MatrixBase const &x) const { typedef typename T0::Scalar Scalar; auto const norm = x.stableNorm(); if(norm > t) out = (Scalar(1) - t / norm) * x; else out.fill(0); } //! Lazy version template ProximalExpression operator()(typename T0::Scalar const &t, Eigen::MatrixBase const &x) const { return {*this, t, x}; } }; //! Proximal of the euclidian norm template auto euclidian_norm(typename real_type::type const &t, Eigen::MatrixBase const &x) -> decltype(EuclidianNorm(), t, x) { return EuclidianNorm()(t, x); } //! Proximal of the l1 norm template void l1_norm(Eigen::DenseBase &out, typename real_type::type gamma, Eigen::DenseBase const &x) { out = sopt::soft_threshhold(x, gamma); } //! \brief Proximal of the l1 norm //! \detail This specialization makes it easier to use in algorithms, e.g. within `SDMM::append`. template void l1_norm(Vector &out, typename real_type::type gamma, Vector const &x) { l1_norm, Vector>(out, gamma, x); } //! \brief Proximal of l1 norm //! \details For more complex version involving linear transforms and weights, see L1TightFrame and //! L1 classes. In practice, this is an alias for soft_threshhold. template auto l1_norm(typename real_type::type gamma, Eigen::DenseBase const &x) -> decltype(sopt::soft_threshhold(x, gamma)) { return sopt::soft_threshhold(x, gamma); } //! Proximal for projection on the positive quadrant template void positive_quadrant(Vector &out, typename real_type::type, Vector const &x) { out = sopt::positive_quadrant(x); }; //! Proximal for indicator function of L2 ball template class L2Ball { public: typedef typename real_type::type Real; //! Constructs an L2 ball proximal of size epsilon L2Ball(Real epsilon) : epsilon_(epsilon) {} //! Calls proximal function void operator()(Vector &out, typename real_type::type, Vector const &x) const { return operator()(out, x); } //! Calls proximal function void operator()(Vector &out, Vector const &x) const { auto const norm = x.stableNorm(); if(norm > epsilon()) out = x * (epsilon() / norm); else out = x; } //! Lazy version template EnveloppeExpression operator()(Real const &, Eigen::MatrixBase const &x) const { return {*this, x}; } //! Lazy version template EnveloppeExpression operator()(Eigen::MatrixBase const &x) const { return {*this, x}; } //! Size of the ball Real epsilon() const { return epsilon_; } //! Size of the ball L2Ball &epsilon(Real eps) { epsilon_ = eps; return *this; } protected: //! Size of the ball Real epsilon_; }; template class WeightedL2Ball : public L2Ball { public: typedef typename L2Ball::Real Real; typedef Vector t_Vector; //! Constructs an L2 ball proximal of size epsilon with given weights template WeightedL2Ball(Real epsilon, Eigen::DenseBase const &w) : L2Ball(epsilon), weights_(w) {} //! Constructs an L2 ball proximal of size epsilon WeightedL2Ball(Real epsilon) : WeightedL2Ball(epsilon, t_Vector::Ones(1)) {} //! Calls proximal function void operator()(Vector &out, typename real_type::type, Vector const &x) const { return operator()(out, x); } //! Calls proximal function void operator()(Vector &out, Vector const &x) const { auto const norm = weights().size() == 1 ? x.stableNorm() * std::abs(weights()(0)) : (x.array() * weights().array()).matrix().stableNorm(); if(norm > epsilon()) out = x * (epsilon() / norm); else out = x; } //! Lazy version template EnveloppeExpression operator()(Real const &, Eigen::MatrixBase const &x) const { return {*this, x}; } //! Lazy version template EnveloppeExpression operator()(Eigen::MatrixBase const &x) const { return {*this, x}; } //! Weights associated with each dimension t_Vector const &weights() const { return weights_; } //! Weights associated with each dimension template WeightedL2Ball &weights(Eigen::MatrixBase const &w) { if((w.array() < 0e0).any()) SOPT_THROW("Weights cannot be negative"); if(w.stableNorm() < 1e-12) SOPT_THROW("Weights cannot be null"); weights_ = w; return *this; } //! Size of the ball Real epsilon() const { return L2Ball::epsilon(); } //! Size of the ball WeightedL2Ball &epsilon(Real const &eps) { L2Ball::epsilon(eps); return *this; } protected: t_Vector weights_; }; //! Translation over proximal function template class Translation { public: //! Creates proximal of translated function template Translation(FUNCTION const &func, T_VECTOR const &trans) : func(func), trans(trans) {} //! Computes proximal of translated function template typename std::enable_if::value, void>::type operator()(OUTPUT out, typename real_type::type const &t, Eigen::MatrixBase const &x) const { func(out, t, x + trans); out -= trans; } //! Computes proximal of translated function template void operator()(Vector &out, typename real_type::type const &t, Eigen::MatrixBase const &x) const { func(out, t, x + trans); out -= trans; } //! Lazy version template ProximalExpression const &, T0> operator()(typename T0::Scalar const &t, Eigen::MatrixBase const &x) const { return {*this, t, x}; } private: //! Function to translate FUNCTION const func; //! Translation VECTOR const trans; }; //! Translates given proximal by given vector template Translation translate(FUNCTION const &func, VECTOR const &translation) { return Translation(func, translation); } } } /* sopt::proximal */ #endif sopt-2.0.0/cpp/sopt/proximal_expression.h000066400000000000000000000066531277570055300205550ustar00rootroot00000000000000#ifndef SOPT_PROXIMAL_EXPRESSION_H #define SOPT_PROXIMAL_EXPRESSION_H #include "sopt/config.h" #include #include #include "sopt/maths.h" namespace sopt { //! Holds some standard proximals namespace proximal { namespace details { //! \brief Expression referencing a lazy proximal function call //! \details It helps transform the call ``proximal(out, gamma, input)`` //! to ``out = proximal(gamma, input)`` without incurring copy or allocation overhead if ``out`` //! already exists. template class DelayedProximalFunction : public Eigen::ReturnByValue> { public: typedef typename DERIVED::PlainObject PlainObject; typedef typename DERIVED::Index Index; typedef typename real_type::type Real; DelayedProximalFunction(FUNCTION const &func, Real const &gamma, DERIVED const &x) : func(func), gamma(gamma), x(x) {} DelayedProximalFunction(DelayedProximalFunction const &c) : func(c.func), gamma(c.gamma), x(c.x) {} DelayedProximalFunction(DelayedProximalFunction &&c) : func(std::move(c.func)), gamma(c.gamma), x(c.x) {} template void evalTo(DESTINATION &destination) const { destination.resizeLike(x); func(destination, gamma, x); } Index rows() const { return x.rows(); } Index cols() const { return x.cols(); } private: FUNCTION const func; Real const gamma; DERIVED const &x; }; //! \brief Expression referencing a lazy function call to envelope proximal //! \details It helps transform the call ``proximal(out, input)`` //! to ``out = proximal(input)`` without incurring copy or allocation overhead if ``out`` //! already exists. template class DelayedProximalEnveloppeFunction : public Eigen::ReturnByValue> { public: typedef typename DERIVED::PlainObject PlainObject; typedef typename DERIVED::Index Index; typedef typename real_type::type Real; DelayedProximalEnveloppeFunction(FUNCTION const &func, DERIVED const &x) : func(func), x(x) {} DelayedProximalEnveloppeFunction(DelayedProximalEnveloppeFunction const &c) : func(c.func), x(c.x) {} DelayedProximalEnveloppeFunction(DelayedProximalEnveloppeFunction &&c) : func(std::move(c.func)), x(c.x) {} template void evalTo(DESTINATION &destination) const { destination.resizeLike(x); func(destination, x); } Index rows() const { return x.rows(); } Index cols() const { return x.cols(); } private: FUNCTION const func; DERIVED const &x; }; } /* details */ //! Eigen expression from proximal functions template using ProximalExpression = details::DelayedProximalFunction>; //! Eigen expression from proximal enveloppe functions template using EnveloppeExpression = details::DelayedProximalEnveloppeFunction>; } } /* sopt::proximal */ namespace Eigen { namespace internal { template struct traits> { typedef typename VECTOR::PlainObject ReturnType; }; template struct traits> { typedef typename VECTOR::PlainObject ReturnType; }; } } #endif sopt-2.0.0/cpp/sopt/real_type.h000066400000000000000000000034701277570055300164210ustar00rootroot00000000000000#ifndef SOPT_REAL_TYPE_H #define SOPT_REAL_TYPE_H #include "sopt/config.h" #include #include namespace sopt { namespace details { // Checks wether a type has contains a type "value_type" template struct HasValueType { using Have = char[1]; using HaveNot = char[2]; struct Fallback { struct value_type {}; }; struct Derived : T, Fallback {}; template static Have &test(typename U::value_type *); template static HaveNot &test(U *); public: static constexpr bool value = sizeof(test(nullptr)) == sizeof(HaveNot); }; // Specialization for fundamental type that cannot be derived from template struct HasValueType::value>::type> : std::false_type {}; //! Detects whether a class contains a value_type type template ::value> class has_value_type; template class has_value_type : public std::true_type {}; template class has_value_type : public std::false_type {}; //! Computes inner-most element type template ::value> class underlying_value_type; template class underlying_value_type { public: typedef T type; }; template class underlying_value_type { public: typedef typename underlying_value_type::type type; }; } //! Gets to the underlying real type template using real_type = details::underlying_value_type; //! True if underlying type is complex template struct is_complex : public std::false_type {}; //! True if underlying type is complex template struct is_complex, void> : public std::true_type {}; } /* sopt */ #endif sopt-2.0.0/cpp/sopt/relative_variation.h000066400000000000000000000027411277570055300203240ustar00rootroot00000000000000#ifndef SOPT_RELATIVE_VARIATION_H #define SOPT_RELATIVE_VARIATION_H #include "sopt/config.h" #include #include "sopt/logging.h" #include "sopt/maths.h" namespace sopt { template class RelativeVariation { public: //! Underlying scalar type typedef TYPE Scalar; //! Underlying scalar type typedef typename real_type::type Real; //! Maximum variation from one step to the next RelativeVariation(Real epsilon) : epsilon_(epsilon), previous(typename Array::Index(0)){}; //! Copy constructor RelativeVariation(RelativeVariation const &c) : epsilon_(c.epsilon_), previous(c.previous){}; //! True if object has changed by less than epsilon template bool operator()(Eigen::MatrixBase const &input) { return operator()(input.array()); } //! True if object has changed by less than epsilon template bool operator()(Eigen::ArrayBase const &input) { if(previous.size() != input.size()) { previous = input; return false; } auto const norm = (input - previous).matrix().squaredNorm(); previous = input; SOPT_LOW_LOG(" - relative variation: {} previous; }; } /* sopt */ #endif sopt-2.0.0/cpp/sopt/reweighted.h000066400000000000000000000240621277570055300165640ustar00rootroot00000000000000#ifndef SOPT_REWEIGHTED_H #define SOPT_REWEIGHTED_H #include "sopt/linear_transform.h" #include "sopt/types.h" namespace sopt { namespace algorithm { template class Reweighted; //! Factory function to create an l0-approximation by reweighting an l1 norm template Reweighted reweighted(ALGORITHM const &algo, typename Reweighted::t_SetWeights const &set_weights, typename Reweighted::t_Reweightee const &reweightee); //! \brief L0-approximation algorithm, through reweighting //! \details This algorithm approximates \f$min_x ||Ψ^Tx||_0 + f(x)\f$ by solving the set of //! problems \f$j\f$, \f$min_x ||W_jΨ^Tx||_1 + f(x)\f$ where the *diagonal* matrix \f$W_j\f$ is set //! using the results from \f$j-1\f$: \f$ δ_j W_j^{-1} = δ_j + ||W_{j-1}Ψ^T||_1\f$. \f$δ_j\f$ //! prevents division by zero. It is a series which converges to zero. By default, //! \f$δ_{j+1}=0.1δ_j\f$. //! //! The algorithm proceeds needs three forms of input: //! - the inner algorithm, e.g. ImagingProximalADMM //! - a function returning Ψ^Tx given x //! - a function to modify the inner algorithm with new weights template class Reweighted { public: //! Inner-loop algorithm typedef ALGORITHM Algorithm; //! Scalar type typedef typename Algorithm::Scalar Scalar; //! Real type typedef typename real_type::type Real; //! Weight vector type typedef Vector WeightVector; //! Type of then underlying vectors typedef typename Algorithm::t_Vector XVector; //! Type of the convergence function typedef typename Algorithm::t_IsConverged t_IsConverged; //! \brief Type of the function that is subject to reweighting //! \details E.g. \f$Ψ^Tx\f$. Note that l1-norm is not applied here. typedef std::function t_Reweightee; //! Type of the function to set weights typedef std::function t_SetWeights; //! Function to update delta at each turn typedef std::function t_DeltaUpdate; //! output from running reweighting scheme struct ReweightedResult { //! Number of iterations (outer loop) t_uint niters; //! Wether convergence was achieved bool good; //! Weights at last iteration WeightVector weights; //! Result from last inner loop typename Algorithm::DiagnosticAndResult algo; //! Default construction ReweightedResult() : niters(0), good(false), weights(WeightVector::Ones(1)), algo() {} }; Reweighted(Algorithm const &algo, t_SetWeights const &setweights, t_Reweightee const &reweightee) : algo_(algo), setweights_(setweights), reweightee_(reweightee), itermax_(std::numeric_limits::max()), min_delta_(0e0), is_converged_(), update_delta_([](Real delta) { return 1e-1 * delta; }) {} //! Underlying "inner-loop" algorithm Algorithm &algorithm() { return algo_; } //! Underlying "inner-loop" algorithm Algorithm const &algorithm() const { return algo_; } //! Sets the underlying "inner-loop" algorithm Reweighted &algorithm(Algorithm const &algo) { algo_ = algo; return *this; } //! Sets the underlying "inner-loop" algorithm Reweighted &algorithm(Algorithm &&algo) { algo_ = std::move(algo); return *this; } //! Function to reset the weights in the algorithm t_SetWeights const &set_weights() const { return setweights_; } //! Function to reset the weights in the algorithm Reweighted &set_weights(t_SetWeights const &setweights) const { setweights_ = setweights; return *this; } //! Sets the weights on the underlying algorithm void set_weights(Algorithm &algo, WeightVector const &weights) const { return set_weights()(algo, weights); } //! Function that needs to be reweighted //! \details E.g. \f$Ψ^Tx\f$. Note that l1-norm is not applied here. Reweighted &reweightee(t_Reweightee const &rw) { reweightee_ = rw; return *this; } //! Function that needs to be reweighted t_Reweightee const &reweightee() const { return reweightee_; } //! Forwards to the reweightee function XVector reweightee(XVector const &x) const { return reweightee()(algorithm(), x); } //! Maximum number of reweighted iterations t_uint itermax() const { return itermax_; } Reweighted &itermax(t_uint i) { itermax_ = i; return *this; } //! Lower limit for delta Real min_delta() const { return min_delta_; } Reweighted &min_delta(Real min_delta) { min_delta_ = min_delta; return *this; } //! Checks convergence of the reweighting scheme t_IsConverged const &is_converged() const { return is_converged_; } Reweighted &is_converged(t_IsConverged const &convergence) { is_converged_ = convergence; return *this; } bool is_converged(XVector const &x) const { return is_converged() ? is_converged()(x) : false; } //! \brief Performs reweighting //! \details This overload will compute an initial result without initial weights set to one. template typename std::enable_if::value or std::is_same::value), ReweightedResult>::type operator()(INPUT const &input) const; //! \brief Performs reweighting //! \details This overload will compute an initial result without initial weights set to one. ReweightedResult operator()() const; //! Reweighted algorithm, from prior call to inner-algorithm ReweightedResult operator()(typename Algorithm::DiagnosticAndResult const &warm) const; //! Reweighted algorithm, from prior call to reweighting algorithm ReweightedResult operator()(ReweightedResult const &warm) const; //! Updates delta Real update_delta(Real delta) const { return update_delta()(delta); } //! Updates delta t_DeltaUpdate const &update_delta() const { return update_delta_; } //! Updates delta Reweighted update_delta(t_DeltaUpdate const &ud) const { return update_delta_ = ud; } protected: //! Inner loop algorithm Algorithm algo_; //! Function to set weights t_SetWeights setweights_; //! \brief Function that is subject to reweighting //! \details E.g. \f$Ψ^Tx\f$. Note that l1-norm is not applied here. t_Reweightee reweightee_; //! Maximum number of reweighted iterations t_uint itermax_; //! \brief Lower limit for delta Real min_delta_; //! Checks convergence t_IsConverged is_converged_; //! Updates delta at each turn t_DeltaUpdate update_delta_; }; template template typename std:: enable_if::value or std::is_same::ReweightedResult>::value), typename Reweighted::ReweightedResult>::type Reweighted::operator()(INPUT const &input) const { Algorithm algo = algorithm(); set_weights(algo, WeightVector::Ones(1)); return operator()(algo(input)); } template typename Reweighted::ReweightedResult Reweighted::operator()() const { Algorithm algo = algorithm(); set_weights(algo, WeightVector::Ones(1)); return operator()(algo()); } template typename Reweighted::ReweightedResult Reweighted:: operator()(typename Algorithm::DiagnosticAndResult const &warm) const { ReweightedResult result; result.algo = warm; result.weights = WeightVector::Ones(1); return operator()(result); } template typename Reweighted::ReweightedResult Reweighted:: operator()(ReweightedResult const &warm) const { SOPT_HIGH_LOG("Starting reweighted scheme"); // Copies inner algorithm, so that operator() can be constant Algorithm algo(algorithm()); ReweightedResult result(warm); auto delta = std::max(standard_deviation(reweightee(warm.algo.x)), min_delta()); SOPT_LOW_LOG("- Initial delta: {}", delta); for(result.niters = 0; result.niters < itermax(); ++result.niters) { SOPT_LOW_LOG("Reweigting iteration {}/{} ", result.niters, itermax()); SOPT_LOW_LOG(" - delta: {}", delta); result.weights = delta / (delta + reweightee(result.algo.x).array().abs()); set_weights(algo, result.weights); result.algo = algo(result.algo); if(is_converged(result.algo.x)) { SOPT_MEDIUM_LOG("Reweighting scheme did converge in {} iterations", result.niters); result.good = true; break; } delta = std::max(min_delta(), update_delta(delta)); } // result is always good if no convergence function is defined if(not is_converged()) result.good = true; else if(not result.good) SOPT_ERROR("Reweighting scheme did *not* converge in {} iterations", itermax()); return result; } //! Factory function to create an l0-approximation by reweighting an l1 norm template Reweighted reweighted(ALGORITHM const &algo, typename Reweighted::t_SetWeights const &set_weights, typename Reweighted::t_Reweightee const &reweightee) { return {algo, set_weights, reweightee}; } template class ImagingProximalADMM; template class PositiveQuadrant; template Eigen::CwiseUnaryOp, const T> positive_quadrant(Eigen::DenseBase const &input); template Reweighted>> reweighted(ImagingProximalADMM const &algo) { auto const posq = positive_quadrant(algo); typedef typename std::remove_const::type Algorithm; typedef Reweighted RW; auto const reweightee = [](Algorithm const &posq, typename RW::XVector const &x) -> typename RW::XVector { return posq.algorithm().Psi().adjoint() * x; }; auto const set_weights = [](Algorithm &posq, typename RW::WeightVector const &weights) -> void { posq.algorithm().l1_proximal_weights(weights); }; return {posq, set_weights, reweightee}; } } // namespace algorithm } // namespace sopt #endif sopt-2.0.0/cpp/sopt/sampling.cc000066400000000000000000000004541277570055300164040ustar00rootroot00000000000000#include "sopt/sampling.h" namespace sopt { Sampling::Sampling(t_uint size, t_uint samples) : indices(size), size(size) { std::iota(indices.begin(), indices.end(), 0); std::shuffle(indices.begin(), indices.end(), std::mt19937(std::random_device()())); indices.resize(samples); } } /* sopt */ sopt-2.0.0/cpp/sopt/sampling.h000066400000000000000000000061211277570055300162430ustar00rootroot00000000000000#ifndef SOPT_SAMPLING_H #define SOPT_SAMPLING_H #include "sopt/config.h" #include "sopt/config.h" #include #include #include #include #include "sopt/linear_transform.h" #include "sopt/types.h" namespace sopt { //! \brief An operator that samples a set of measurements. //! \details Picks some elements from a vector class Sampling { public: //! Constructs from a vector Sampling(t_uint size, std::vector const &indices) : indices(indices), size(size) {} //! Constructs from the size and the number of samples to pick template Sampling(t_uint size, t_uint samples, RNG &&rng); //! Constructs from the size and the number of samples to pick Sampling(t_uint size, t_uint samples) : Sampling(size, samples, std::mt19937_64(std::random_device()())) {} // Performs sampling template void operator()(Eigen::DenseBase &out, Eigen::DenseBase const &x) const; // Performs sampling template void operator()(Eigen::DenseBase &&out, Eigen::DenseBase const &x) const { operator()(out, x); } // Performs adjunct of sampling template void adjoint(Eigen::DenseBase &out, Eigen::DenseBase const &x) const; // Performs adjunct sampling template void adjoint(Eigen::DenseBase &&out, Eigen::DenseBase const &x) const { adjoint(out, x); } //! Size of the vector returned by the adjoint operation t_uint cols() const { return size; } //! Number of measurements t_uint rows() const { return indices.size(); } protected: //! Set of indices to pick std::vector indices; //! Original vector size t_uint size; }; template void Sampling::operator()(Eigen::DenseBase &out, Eigen::DenseBase const &x) const { out.resize(indices.size()); for(decltype(indices.size()) i(0); i < indices.size(); ++i) { assert(indices[i] < static_cast(x.size())); out[i] = x[indices[i]]; } } template void Sampling::adjoint(Eigen::DenseBase &out, Eigen::DenseBase const &x) const { assert(static_cast(x.size()) == indices.size()); out.resize(out.size()); out.fill(0); for(decltype(indices.size()) i(0); i < indices.size(); ++i) { assert(indices[i] < static_cast(out.size())); out[indices[i]] = x[i]; } } //! Returns linear transform version of this object. template LinearTransform> linear_transform(Sampling const &sampling) { return linear_transform>( [sampling](Vector &out, Vector const &x) { sampling(out, x); }, {{0, 1, static_cast(sampling.rows())}}, [sampling](Vector &out, Vector const &x) { sampling.adjoint(out, x); }, {{0, 1, static_cast(sampling.cols())}}); } template Sampling::Sampling(t_uint size, t_uint samples, RNG &&rng) : indices(size), size(size) { std::iota(indices.begin(), indices.end(), 0); std::shuffle(indices.begin(), indices.end(), rng); indices.resize(samples); } } /* sopt */ #endif sopt-2.0.0/cpp/sopt/sdmm.h000066400000000000000000000277121277570055300154020ustar00rootroot00000000000000#ifndef SOPT_SDMM_H #define SOPT_SDMM_H #include "sopt/config.h" #include #include #include #include "sopt/conjugate_gradient.h" #include "sopt/exception.h" #include "sopt/linear_transform.h" #include "sopt/logging.h" #include "sopt/proximal.h" #include "sopt/proximal_expression.h" #include "sopt/types.h" #include "sopt/wrapper.h" namespace sopt { namespace algorithm { //! \brief Simultaneous-direction method of the multipliers //! \details The algorithm is detailed in (doi) 10.1093/mnras/stu202. template class SDMM { public: //! Values indicating how the algorithm ran struct Diagnostic { //! Number of iterations t_uint niters; //! Wether convergence was achieved bool good; //! Conjugate gradient result ConjugateGradient::Diagnostic cg_diagnostic; }; struct DiagnosticAndResult : public Diagnostic { //! Vector which minimizes the sum of functions. Vector x; }; //! Scalar type typedef SCALAR value_type; //! Scalar type typedef value_type Scalar; //! Real type typedef typename real_type::type Real; //! Type of then underlying vectors typedef Vector t_Vector; //! Type of the A and A^H operations typedef LinearTransform t_LinearTransform; //! Type of the proximal functions typedef ProximalFunction t_Proximal; //! Type of the convergence function typedef ConvergenceFunction t_IsConverged; SDMM() : itermax_(std::numeric_limits::max()), gamma_(1e-8), conjugate_gradient_(std::numeric_limits::max(), 1e-6), is_converged_([](t_Vector const &) { return false; }) {} virtual ~SDMM() {} // Macro helps define properties that can be initialized as in // auto sdmm = SDMM().prop0(value).prop1(value); #define SOPT_MACRO(NAME, TYPE) \ TYPE const &NAME() const { return NAME##_; } \ SDMM &NAME(TYPE const &NAME) { \ NAME##_ = NAME; \ return *this; \ } \ \ protected: \ TYPE NAME##_; \ \ public: //! Maximum number of iterations SOPT_MACRO(itermax, t_uint); //! Gamma SOPT_MACRO(gamma, Real); //! Conjugate gradient SOPT_MACRO(conjugate_gradient, ConjugateGradient); //! A function verifying convergence SOPT_MACRO(is_converged, t_IsConverged); #undef SOPT_MACRO //! Helps setup conjugate gradient SDMM &conjugate_gradient(t_uint itermax, t_real tolerance) { conjugate_gradient_.itermax(itermax); conjugate_gradient_.tolerance(tolerance); return *this; } //! \brief Appends a proximal and linear transform template SDMM &append(PROXIMAL proximal, T args) { proximals().emplace_back(proximal); transforms().emplace_back(linear_transform(args)); return *this; } //! \brief Appends a proximal with identity as the linear transform template SDMM &append(PROXIMAL proximal) { return append(proximal, linear_transform_identity()); } //! \brief Appends a proximal with the linear transform as pair of functions template SDMM &append(PROXIMAL proximal, L l, LADJOINT ladjoint) { return append(proximal, linear_transform(l, ladjoint)); } //! \brief Appends a proximal with the linear transform as pair of functions template SDMM &append(PROXIMAL proximal, L l, LADJOINT ladjoint, std::array sizes) { return append(proximal, linear_transform(l, ladjoint, sizes)); } //! \brief Appends a proximal with the linear transform as pair of functions template SDMM &append(PROXIMAL proximal, L l, std::array dsizes, LADJOINT ladjoint, std::array isizes) { return append(proximal, linear_transform(l, dsizes, ladjoint, isizes)); } //! \brief Implements SDMM //! \details Follows Combettes and Pesquet "Proximal Splitting Methods in Signal Processing", //! arXiv:0912.3522v4 [math.OC] (2010), equation 65. //! See therein for notation Diagnostic operator()(t_Vector &out, t_Vector const &input) const; DiagnosticAndResult operator()(t_Vector const &input) const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, input); return result; } //! Makes it simple to chain different calls to SDMM DiagnosticAndResult operator()(DiagnosticAndResult const &warmstart) const { DiagnosticAndResult result; static_cast(result) = operator()(result.x, warmstart.x); return result; } //! Linear transforms associated with each objective function std::vector const &transforms() const { return transforms_; } //! Linear transforms associated with each objective function std::vector &transforms() { return transforms_; } //! Linear transform associated with a given objective function t_LinearTransform const &transforms(t_uint i) const { return transforms_[i]; } //! Linear transform associated with a given objective function t_LinearTransform &transforms(t_uint i) { return transforms_[i]; } //! Proximal of each objective function std::vector const &proximals() const { return proximals_; } //! Linear transforms associated with each objective function std::vector &proximals() { return proximals_; } //! Proximal associated with a given objective function t_Proximal const &proximals(t_uint i) const { return proximals_[i]; } //! Proximal associated with a given objective function t_Proximal &proximals(t_uint i) { return proximals_[i]; } //! Lazy call to specific proximal function template proximal::ProximalExpression proximals(t_uint i, Eigen::MatrixBase const &x) const { return {proximals()[i], gamma(), x}; } //! Number of terms t_uint size() const { return proximals().size(); } // We must declare the first argument explicitly so that the function never // match the getter with the same name. //! \brief Forwards to internal conjugage gradient object //! \details Removes the need for ugly extra brackets. template auto conjugate_gradient(T0 &&t0, T &&... args) const -> decltype(this->conjugate_gradient()(std::forward(t0), std::forward(args)...)) { return conjugate_gradient()(std::forward(t0), std::forward(args)...); } //! Forwards to convergence function parameter bool is_converged(t_Vector const &x) const { return is_converged()(x); } protected: //! Linear transforms associated with each objective function std::vector transforms_; //! Proximal of each objective function std::vector proximals_; //! Type of the list of vectors typedef std::vector t_Vectors; //! Conjugate gradient step virtual ConjugateGradient::Diagnostic solve_for_xn(t_Vector &out, t_Vectors const &y, t_Vectors const &z) const; //! Direction step virtual void update_directions(t_Vectors &y, t_Vectors &z, t_Vector const &x) const; //! Initializes intermediate values virtual void initialization(t_Vectors &y, t_Vectors &z, t_Vector const &x) const; //! Checks that the input make sense virtual void sanity_check(t_Vector const &input) const; }; template typename SDMM::Diagnostic SDMM:: operator()(t_Vector &out, t_Vector const &input) const { sanity_check(input); bool convergence = false; t_uint niters(0); // Figures out where itermax or convergence reached auto const has_finished = [&convergence, &niters, this](t_Vector const &out) { convergence = is_converged(out); return niters >= itermax() or convergence; }; SOPT_HIGH_LOG("Performing SDMM "); out = input; t_Vectors y(transforms().size()), z(transforms().size()); // Initial step replaces iteration update with initialization initialization(y, z, input); auto cg_diagnostic = solve_for_xn(out, y, z); while(not has_finished(out)) { SOPT_LOW_LOG("Iteration {}/{}. ", niters, itermax()); // computes y and z from out and transforms update_directions(y, z, out); SOPT_LOW_LOG(" - sum z_ij = {}", std::accumulate(z.begin(), z.end(), Scalar(0e0), [](Scalar const &a, t_Vector const &z) { return a + z.sum(); })); // computes x = L^-1 y cg_diagnostic = solve_for_xn(out, y, z); SOPT_LOW_LOG(" - CG Residual = {} in {}/{} iterations", cg_diagnostic.residual, cg_diagnostic.niters, conjugate_gradient().itermax()); ++niters; } return {niters, convergence, cg_diagnostic}; } template ConjugateGradient::Diagnostic SDMM::solve_for_xn(t_Vector &out, t_Vectors const &y, t_Vectors const &z) const { assert(z.size() == transforms().size()); assert(y.size() == transforms().size()); SOPT_TRACE("Solving for x_n"); // Initialize b of A x = b = sum_i L_i^H(z_i - y_i) t_Vector b = out.Zero(out.size()); for(t_uint i(0); i < transforms().size(); ++i) b += transforms(i).adjoint() * (y[i] - z[i]); if(b.stableNorm() < 1e-12) { out.fill(0e0); return {0, 0, true}; } // Then create operator A auto A = [this](t_Vector &out, t_Vector const &input) { out = out.Zero(input.size()); for(auto const &transform : this->transforms()) out += transform.adjoint() * (transform * input).eval(); }; // Call conjugate gradient auto const diagnostic = this->conjugate_gradient(out, A, b); if(not diagnostic.good) { SOPT_ERROR("CG error - iterations: {}/{} - residuals {}\n", diagnostic.niters, conjugate_gradient().itermax(), diagnostic.residual); SOPT_THROW("Conjugate gradient failed to converge"); } return diagnostic; } template void SDMM::update_directions(t_Vectors &y, t_Vectors &z, t_Vector const &x) const { SOPT_TRACE("Updating directions"); for(t_uint i(0); i < transforms().size(); ++i) { z[i] += transforms(i) * x; y[i] = proximals(i, z[i]); z[i] -= y[i]; } } template void SDMM::initialization(t_Vectors &y, t_Vectors &z, t_Vector const &x) const { SOPT_TRACE("Initializing SDMM"); for(t_uint i(0); i < transforms().size(); i++) { y[i] = transforms(i) * x; z[i].resize(y[i].size()); z[i].fill(0); assert(z[i].size() == y[i].size()); SOPT_TRACE(" - transform {}: {}", i, y[i].transpose()); } } template void SDMM::sanity_check(t_Vector const &x) const { bool doexit = false; if(proximals().size() != transforms().size()) { SOPT_ERROR("Internal error: number of proximals and transforms do not match"); doexit = true; } if(x.size() == 0) SOPT_WARN("Input vector has zero size"); if(size() == 0) SOPT_WARN("No operators - SDMM is empty"); for(t_uint i(0); i < size(); ++i) { auto const xdual = t_Vector::Zero((transforms(i) * x).size()); auto const r = (transforms(i).adjoint() * xdual).size(); if(r != x.size()) { SOPT_ERROR("Output size of transform {} and input do not match: {} vs {}", i, r, x.size()); doexit = true; } } if(doexit) SOPT_THROW("Input to SDMM is inconsistent"); } } } /* sopt::algorithm */ #endif sopt-2.0.0/cpp/sopt/types.h000066400000000000000000000034051277570055300155770ustar00rootroot00000000000000#ifndef BICO_TRAITS_H #define BICO_TRAITS_H #include "sopt/config.h" #include #include #include #include "sopt/real_type.h" namespace sopt { //! Root of the type hierarchy for signed integers typedef int t_int; //! Root of the type hierarchy for unsigned integers typedef size_t t_uint; //! Root of the type hierarchy for real numbers typedef double t_real; //! Root of the type hierarchy for (real) complex numbers typedef std::complex t_complex; //! \brief A vector of a given type //! \details Operates as mathematical vector. template using Vector = Eigen::Matrix; //! \brief A matrix of a given type //! \details Operates as mathematical matrix. template using Matrix = Eigen::Matrix; //! \brief A 1-dimensional list of elements of given type //! \details Operates coefficient-wise, not matrix-vector-wise template using Array = Eigen::Array; //! \brief A 2-dimensional list of elements of given type //! \details Operates coefficient-wise, not matrix-vector-wise template using Image = Eigen::Array; //! Typical function out = A*x template > using OperatorFunction = std::function; //! Typical function signature for calls to proximal template using ProximalFunction = std::function &, typename real_type::type, Vector const &)>; //! Typical function signature for convergence template using ConvergenceFunction = std::function const &)>; } #endif sopt-2.0.0/cpp/sopt/utilities.cc000066400000000000000000000065401277570055300166070ustar00rootroot00000000000000#include "sopt/utilities.h" #include "sopt/config.h" #include #include #include #include "sopt/exception.h" #include "sopt/logging.h" #include "sopt/types.h" namespace { //! A single pixel //! Converts ABGR to greyscale double value double convert_to_greyscale(uint32_t &pixel) { uint8_t const blue = TIFFGetB(pixel); uint8_t const green = TIFFGetG(pixel); uint8_t const red = TIFFGetR(pixel); return static_cast(blue + green + red) / (3e0 * 255e0); } //! Converts greyscale double value to RGBA uint32_t convert_from_greyscale(double pixel) { uint32_t result = 0; uint8_t *ptr = (uint8_t *)&result; auto const g = [](double p) -> uint8_t { auto const scaled = 255e0 * p; if(scaled < 0) return 0; return scaled > 255 ? 255 : uint8_t(scaled); }; ptr[0] = g(pixel); ptr[1] = g(pixel); ptr[2] = g(pixel); ptr[3] = 255; return result; } } namespace sopt { namespace utilities { Image<> read_tiff(std::string const &filename) { SOPT_MEDIUM_LOG("Reading image file {} ", filename); TIFF *tif = TIFFOpen(filename.c_str(), "r"); if(not tif) SOPT_THROW("Could not open file ") << filename; uint32 width, height, t; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &t); SOPT_LOW_LOG("- image size {}, {} ", width, height); Image<> result = Image<>::Zero(height, width); uint32 *raster = (uint32 *)_TIFFmalloc(width * height * sizeof(uint32)); if(not raster) SOPT_THROW("Could not allocate memory to read file ") << filename; if(not TIFFReadRGBAImage(tif, width, height, raster, 0)) SOPT_THROW("Could not read file ") << filename; uint32_t *pixel = (uint32_t *)raster; for(uint32 i(0); i < height; ++i) for(uint32 j(0); j < width; ++j, ++pixel) result(i, j) = convert_to_greyscale(*pixel); _TIFFfree(raster); TIFFClose(tif); return result; } void write_tiff(Image<> const &image, std::string const &filename) { SOPT_MEDIUM_LOG("Writing image file {} ", filename); SOPT_LOW_LOG("- image size {}, {} ", image.rows(), image.cols()); TIFF *tif = TIFFOpen(filename.c_str(), "w"); if(not tif) SOPT_THROW("Could not open file ") << filename; uint32 const width = image.cols(); uint32 const height = image.rows(); SOPT_TRACE("Allocating buffer"); std::vector raster(width * height); TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, sizeof(decltype(raster)::value_type)); TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, height); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT); SOPT_TRACE("Initializing buffer"); auto pixel = raster.begin(); for(uint32 i(0); i < height; ++i) for(uint32 j(0); j < width; ++j, ++pixel) *pixel = convert_from_greyscale(image(i, j)); SOPT_TRACE("Writing strip"); TIFFWriteEncodedStrip(tif, 0, &raster[0], width * height * sizeof(decltype(raster)::value_type)); TIFFWriteDirectory(tif); SOPT_TRACE("Closing tif"); TIFFClose(tif); SOPT_TRACE("Freeing raster"); } } // utilities } // sopt sopt-2.0.0/cpp/sopt/utilities.h000066400000000000000000000005601277570055300164450ustar00rootroot00000000000000#ifndef SOPT_UTILITIES_H #define SOPT_UTILITIES_H #include "sopt/config.h" #include #include "sopt/types.h" namespace sopt { namespace utilities { //! Reads tiff image sopt::Image<> read_tiff(std::string const &name); //! Writes a tiff greyscale file void write_tiff(Image<> const &image, std::string const &filename); } } /* sopt::utilities */ #endif sopt-2.0.0/cpp/sopt/wavelets.h000066400000000000000000000073401277570055300162670ustar00rootroot00000000000000#ifndef SOPT_WAVELETS_H #define SOPT_WAVELETS_H // Convenience header to include wavelets headers and additional utilities #include "sopt/config.h" #include "sopt/linear_transform.h" #include "sopt/wavelets/sara.h" #include "sopt/wavelets/wavelets.h" namespace sopt { namespace details { namespace { //! Thin linear-transform wrapper around some operator accepting direct and indirect template LinearTransform> linear_transform(OP const &op) { return LinearTransform>( [&op](Vector &out, Vector const &x) { op.indirect(x.array(), out.array()); }, [&op](Vector &out, Vector const &x) { op.direct(out.array(), x.array()); }); } //! \brief Thin linear-transform wrapper around 2d wavelets //! \details Goes back and forth between vector representations and image representations, where //! images can be 2d. //! \param[in] op: Wavelet operator //! \param[in] rows: Number of rows in the image //! \param[in] cols: Number of columns in the image //! \param[in] factor: Allows for SARA transforms, i.e. more than one wavelet basis template LinearTransform> linear_transform(OP const &op, t_uint rows, t_uint cols, t_uint factor = 1) { if(rows == 1 or cols == 1) return linear_transform(op); return LinearTransform>( [&op, rows, cols, factor](Vector &out, Vector const &x) { assert(static_cast(x.size()) == rows * cols * factor); out.resize(rows * cols); auto signal = Image::Map(out.data(), rows, cols); auto const coeffs = Image::Map(x.data(), rows, cols * factor); op.indirect(coeffs, signal); }, {{0, 1, static_cast(rows * cols)}}, [&op, rows, cols, factor](Vector &out, Vector const &x) { assert(static_cast(x.size()) == rows * cols); out.resize(rows * cols * factor); auto const signal = Image::Map(x.data(), rows, cols); auto coeffs = Image::Map(out.data(), rows, cols * factor); op.direct(coeffs, signal); }, {{0, 1, static_cast(factor * rows * cols)}}); } } // anonymous } // details //! \brief Thin linear-transform wrapper around 1d wavelets //! \warning Because of the way Purify defines things, Ψ^T is actually the transform from signal to //! coefficients. template LinearTransform> linear_transform(wavelets::Wavelet const &wavelet) { return details::linear_transform(wavelet); } //! \brief Thin linear-transform wrapper around 1d sara operator //! \note Because of the way Purify defines things, Ψ^T is actually the transform from signal to //! coefficients. template LinearTransform> linear_transform(wavelets::SARA const &sara) { return details::linear_transform(sara); } //! \brief Thin linear-transform wrapper around 2d wavelets //! \note Because of the way Purify defines things, Ψ^T is actually the transform from signal to //! coefficients. template LinearTransform> linear_transform(wavelets::Wavelet const &wavelet, t_uint rows, t_uint cols = 1) { return details::linear_transform(wavelet, rows, cols); } //! \brief Thin linear-transform wrapper around 2d wavelets //! \param[in] sara: SARA wavelet dictionary //! \param[in] rows: Number of rows in the image //! \param[in] cols: Number of columns in the image //! \note Because of the way Purify defines things, Ψ^T is actually the transform from signal to //! coefficients. template LinearTransform> linear_transform(wavelets::SARA const &sara, t_uint rows, t_uint cols = 1) { return details::linear_transform(sara, rows, cols, sara.size()); } } /* sopt */ #endif sopt-2.0.0/cpp/sopt/wavelets/000077500000000000000000000000001277570055300161125ustar00rootroot00000000000000sopt-2.0.0/cpp/sopt/wavelets/direct.h000066400000000000000000000114171277570055300175410ustar00rootroot00000000000000#ifndef SOPT_WAVELETS_DIRECT_H #define SOPT_WAVELETS_DIRECT_H #include "sopt/config.h" #include #include "sopt/types.h" #include "sopt/wavelets/wavelet_data.h" // Function inside anonymouns namespace won't appear in library namespace sopt { namespace wavelets { namespace { //! \brief Single-level 1d direct transform //! \param[out] coeffs_: output of the function (despite the const) //! \param[in] signal: input signal for which to compute wavelet transform //! \param[in] wavelet: contains wavelet coefficients template typename std::enable_if::type direct_transform_impl(Eigen::ArrayBase const &coeffs_, Eigen::ArrayBase const &signal, WaveletData const &wavelet) { Eigen::ArrayBase &coeffs = const_cast &>(coeffs_); assert(coeffs.size() == signal.size()); assert(wavelet.direct_filter.low.size() == wavelet.direct_filter.high.size()); auto const N = signal.size() / 2; down_convolve(coeffs.head(N), signal, wavelet.direct_filter.low); down_convolve(coeffs.tail(coeffs.size() - N), signal, wavelet.direct_filter.high); } //! Single-level 2d direct transform //! \param[out] coeffs_: output of the function (despite the const) //! \param[inout] signal: input signal for which to compute wavelet transform. Input is modified. //! \param[in] wavelet: contains wavelet coefficients template typename std::enable_if::type direct_transform_impl(Eigen::ArrayBase const &coeffs_, Eigen::ArrayBase const &signal_, WaveletData const &wavelet) { Eigen::ArrayBase &coeffs = const_cast &>(coeffs_); Eigen::ArrayBase &signal = const_cast &>(signal_); assert(coeffs.rows() == signal.rows()); assert(coeffs.cols() == signal.cols()); assert(wavelet.direct_filter.low.size() == wavelet.direct_filter.high.size()); for(t_uint i(0); i < static_cast(coeffs.rows()); ++i) direct_transform_impl(coeffs.row(i).transpose(), signal.row(i).transpose(), wavelet); for(t_uint i(0); i < static_cast(coeffs.cols()); ++i) { signal.col(i) = coeffs.col(i); direct_transform_impl(coeffs.col(i), signal.col(i), wavelet); } } } //! \brief N-levels 1d direct transform //! \param[out] coeffs_: output of the function (despite the const) //! \param[in] signal: input signal for which to compute wavelet transfor //! \param[in] wavelet: contains wavelet coefficients //! \note The size of the coefficients should a multiple of $2^l$ where $l$ is the number of //! levels. template typename std::enable_if::type direct_transform(Eigen::ArrayBase &coeffs, Eigen::ArrayBase const &signal, t_uint levels, WaveletData const &wavelet) { assert(coeffs.rows() == signal.rows()); assert(coeffs.cols() == signal.cols()); auto input = copy(signal); if(levels > 0) direct_transform_impl(coeffs, input, wavelet); for(t_uint level(1); level < levels; ++level) { auto const N = static_cast(signal.size()) >> level; input.head(N) = coeffs.head(N); direct_transform_impl(coeffs.head(N), input.head(N), wavelet); } } //! N-levels 2d direct transform //! \param[in] signal: input signal for which to compute wavelet transfor //! \param[in] wavelet: contains wavelet coefficients //! \note The size of the coefficients should a multiple of $2^l$ where $l$ is the number of //! levels. template typename std::enable_if::type direct_transform(Eigen::ArrayBase const &coeffs_, Eigen::ArrayBase const &signal, t_uint levels, WaveletData const &wavelet) { assert(coeffs_.rows() == signal.rows()); assert(coeffs_.cols() == signal.cols()); Eigen::ArrayBase &coeffs = const_cast &>(coeffs_); if(levels == 0) { coeffs = signal; return; } auto input = copy(signal); direct_transform_impl(coeffs, input, wavelet); for(t_uint level(1); level < levels; ++level) { auto const Nx = static_cast(signal.rows()) >> level; auto const Ny = static_cast(signal.cols()) >> level; input.topLeftCorner(Nx, Ny) = coeffs.topLeftCorner(Nx, Ny); direct_transform_impl(coeffs.topLeftCorner(Nx, Ny), input.topLeftCorner(Nx, Ny), wavelet); } } //! \brief Direct 1d and 2d transform //! \note The size of the coefficients should a multiple of $2^l$ where $l$ is the number of //! levels. template auto direct_transform(Eigen::ArrayBase const &signal, t_uint levels, WaveletData const &wavelet) -> decltype(copy(signal)) { auto result = copy(signal); direct_transform(result, signal, levels, wavelet); return result; } } } #endif sopt-2.0.0/cpp/sopt/wavelets/indirect.h000066400000000000000000000117111277570055300200650ustar00rootroot00000000000000#ifndef SOPT_WAVELET_INDIRECT_H #define SOPT_WAVELET_INDIRECT_H #include "sopt/config.h" #include "sopt/types.h" #include "sopt/wavelets/innards.impl.h" #include "sopt/wavelets/wavelet_data.h" // Function inside anonymouns namespace won't appear in library namespace sopt { namespace wavelets { namespace { //! Single-level 1d indirect transform //! \param[in] coeffs_: input coefficients //! \param[out] signal: output with the reconstituted signal //! \param[in] wavelet: contains wavelet coefficients template typename std::enable_if::type indirect_transform_impl(Eigen::ArrayBase const &coeffs, Eigen::ArrayBase const &signal_, WaveletData const &wavelet) { Eigen::ArrayBase &signal = const_cast &>(signal_); assert(coeffs.size() == signal.size()); assert(coeffs.size() % 2 == 0); up_convolve_sum(signal, coeffs, wavelet.indirect_filter.low_even, wavelet.indirect_filter.low_odd, wavelet.indirect_filter.high_even, wavelet.indirect_filter.high_odd); } //! Single-level 2d indirect transform //! \param[in] coeffs_: input coefficients //! \param[out] signal: output with the reconstituted signal //! \param[in] wavelet: contains wavelet coefficients template typename std::enable_if::type indirect_transform_impl(Eigen::ArrayBase const &coeffs_, Eigen::ArrayBase const &signal_, WaveletData const &wavelet) { Eigen::ArrayBase &coeffs = const_cast &>(coeffs_); Eigen::ArrayBase &signal = const_cast &>(signal_); assert(coeffs.rows() == signal.rows() and coeffs.cols() == signal.cols()); assert(coeffs.rows() % 2 == 0 and coeffs.cols() % 2 == 0); for(typename T0::Index i(0); i < signal.rows(); ++i) indirect_transform_impl(coeffs.row(i).transpose(), signal.row(i).transpose(), wavelet); coeffs = signal; for(typename T0::Index j(0); j < signal.cols(); ++j) indirect_transform_impl(coeffs.col(j), signal.col(j), wavelet); } } //! \brief N-levels 1d indirect transform //! \param[in] coeffs_: input coefficients //! \param[out] signal: output with the reconstituted signal //! \param[in] wavelet: contains wavelet coefficients //! \note The size of the coefficients should a multiple of $2^l$ where $l$ is the number of //! levels. template typename std::enable_if::type indirect_transform(Eigen::ArrayBase const &coeffs, Eigen::ArrayBase &signal, t_uint levels, WaveletData const &wavelet) { if(levels == 0) return; assert(coeffs.rows() == signal.rows()); assert(coeffs.cols() == signal.cols()); assert(coeffs.size() % (1u << levels) == 0); auto input = copy(coeffs); for(t_uint level(levels - 1); level > 0; --level) { auto const N = static_cast(signal.size()) >> level; indirect_transform_impl(input.head(N), signal.head(N), wavelet); input.head(N) = signal.head(N); } indirect_transform_impl(input, signal, wavelet); } //! \brief N-levels 2d indirect transform //! \param[in] coeffs_: input coefficients //! \param[out] signal: output with the reconstituted signal //! \param[in] wavelet: contains wavelet coefficients //! \note The size of the signal and coefficients should a multiple of $2^l$ where $l$ is the //! number of levels. template typename std::enable_if::type indirect_transform(Eigen::ArrayBase const &coeffs_, Eigen::ArrayBase const &signal_, t_uint levels, WaveletData const &wavelet) { Eigen::ArrayBase &coeffs = const_cast &>(coeffs_); Eigen::ArrayBase &signal = const_cast &>(signal_); assert(coeffs.rows() == signal.rows()); assert(coeffs.cols() == signal.cols()); assert(coeffs.size() % (1u << levels) == 0); if(levels == 0) { signal = coeffs_; return; } auto input = copy(coeffs); for(t_uint level(levels - 1); level > 0; --level) { auto const Nx = static_cast(signal.rows()) >> level; auto const Ny = static_cast(signal.cols()) >> level; indirect_transform_impl(input.topLeftCorner(Nx, Ny), signal.topLeftCorner(Nx, Ny), wavelet); input.topLeftCorner(Nx, Ny) = signal.topLeftCorner(Nx, Ny); } indirect_transform_impl(input, signal, wavelet); } //! Indirect 1d and 2d transform //! \param[in] coeffs_: input coefficients //! \param[in] wavelet: contains wavelet coefficients //! \returns the reconstituted signal //! \note The size of the coefficients should a multiple of $2^l$ where $l$ is the number of //! levels. template auto indirect_transform(Eigen::ArrayBase const &coeffs, t_uint levels, WaveletData const &wavelet) -> decltype(copy(coeffs)) { auto result = copy(coeffs); indirect_transform(coeffs, result, levels, wavelet); return result; } } } #endif sopt-2.0.0/cpp/sopt/wavelets/innards.impl.h000066400000000000000000000137401277570055300206660ustar00rootroot00000000000000#ifndef SOPT_WAVELETS_INNARDS_H #define SOPT_WAVELETS_INNARDS_H #include "sopt/config.h" #include // Function inside anonymouns namespace won't appear in library namespace sopt { namespace wavelets { namespace { //! \brief Returns evaluated expression or copy of input //! \details Gets C++ to figure out what the exact type is. Eigen tries and avoids copies. But //! sometimes we actually want a copy, to make sure the arguments of a function are not modified template auto copy(Eigen::ArrayBase const &a) -> typename std::remove_const::type>::type { return a.eval(); } //! \brief Applies scalar product of the size b //! \details In practice, the operation is equivalent to the following //! - `a` can be seen as a periodic vector: `a[i] == a[i % a.size()]` //! - `a'` is the segment `a` = a[offset:offset+b.size()]` //! - the result is the scalar product of `a'` by `b`. template typename T0::Scalar periodic_scalar_product(Eigen::ArrayBase const &a, Eigen::ArrayBase const &b, typename T0::Index offset) { auto const Na = static_cast(a.size()); auto const Nb = static_cast(b.size()); // offset in [0, a.size()[ offset %= Na; if(offset < 0) offset += Na; // Simple case, just do it if(Na > Nb + offset) { return (a.segment(offset, Nb) * b).sum(); } // Wrap around, do it, but carefully typename T0::Scalar result(0); for(typename T0::Index i(0), j(offset); i < Nb; ++i, ++j) result += a(j % Na) * b(i); return result; } //! \brief Convolves the signal by the filter //! \details The signal is seen as a periodic vector during convolution template void convolve(Eigen::ArrayBase &result, Eigen::ArrayBase const &signal, Eigen::ArrayBase const &filter) { assert(result.size() == signal.size()); for(typename T0::Index i(0); i < t_int(signal.size()); ++i) result(i) = periodic_scalar_product(signal, filter, i); } //! \brief Convolve variation for vector blocks template void convolve(Eigen::VectorBlock &&result, Eigen::ArrayBase const &signal, Eigen::ArrayBase const &filter) { return convolve(result, signal, filter); } //! \brief Convolves and down-samples the signal by the filter //! \details Just like convolve, but does every other point. template void down_convolve(Eigen::ArrayBase &result, Eigen::ArrayBase const &signal, Eigen::ArrayBase const &filter) { assert(result.size() * 2 <= signal.size()); if(signal.rows() == 1) for(typename T0::Index i(0); i < result.size(); ++i) result(i) = periodic_scalar_product(signal.transpose(), filter, 2 * i); else for(typename T0::Index i(0); i < result.size(); ++i) result(i) = periodic_scalar_product(signal, filter, 2 * i); } //! \brief Dowsampling + convolve variation for vector blocks template void down_convolve(Eigen::VectorBlock &&result, Eigen::ArrayBase const &signal, Eigen::ArrayBase const &filter) { down_convolve(result, signal, filter); } //! Convolve and sims low and high pass of a signal template void convolve_sum(Eigen::ArrayBase &result, Eigen::ArrayBase const &low_pass_signal, Eigen::ArrayBase const &low_pass, Eigen::ArrayBase const &high_pass_signal, Eigen::ArrayBase const &high_pass) { assert(result.size() == low_pass_signal.size()); assert(result.size() == high_pass_signal.size()); assert(low_pass.size() == high_pass.size()); static_assert(std::is_signed::value, "loffset, hoffset expect signed values"); auto const loffset = 1 - static_cast(low_pass.size()); auto const hoffset = 1 - static_cast(high_pass.size()); for(typename T0::Index i(0); i < result.size(); ++i) { result(i) = periodic_scalar_product(low_pass_signal, low_pass, i + loffset) + periodic_scalar_product(high_pass_signal, high_pass, i + hoffset); } } //! \brief Convolves and up-samples at the same time //! \details If Cn shuffles the (periodic) vector right, U does the upsampling, //! and O is the convolution operation, then the normal upsample + convolution //! is O(Cn[U [a]], b). What we are doing here is U[O(Cn'[a'], b')]. This avoids //! some unnecessary operations (multiplying and summing zeros) and removes the //! need for temporary copies. Testing shows the operations are equivalent. But //! I certainly cannot show how on paper. template void up_convolve_sum(Eigen::ArrayBase &result, Eigen::ArrayBase const &coeffs, Eigen::ArrayBase const &low_even, Eigen::ArrayBase const &low_odd, Eigen::ArrayBase const &high_even, Eigen::ArrayBase const &high_odd) { assert(result.size() <= coeffs.size()); assert(result.size() % 2 == 0); assert(low_even.size() == high_even.size()); assert(low_odd.size() == high_odd.size()); auto const Nlow = (coeffs.size() + 1) / 2; auto const Nhigh = coeffs.size() / 2; auto const size = low_even.size() + low_odd.size(); auto const is_even = size % 2 == 0; auto const even_offset = (1 - size) / 2; auto const odd_offset = (1 - size) / 2 + (is_even ? 0 : 1); for(typename T0::Index i(0); i + 1 < result.size(); i += 2) { result(i + (is_even ? 1 : 0)) = periodic_scalar_product(coeffs.head(Nlow), low_even, i / 2 + even_offset) + periodic_scalar_product(coeffs.tail(Nhigh), high_even, i / 2 + even_offset); result(i + (is_even ? 0 : 1)) = periodic_scalar_product(coeffs.head(Nlow), low_odd, i / 2 + odd_offset) + periodic_scalar_product(coeffs.tail(Nhigh), high_odd, i / 2 + odd_offset); } } } } } #endif sopt-2.0.0/cpp/sopt/wavelets/sara.h000066400000000000000000000217711277570055300172210ustar00rootroot00000000000000#ifndef SOPT_WAVELETS_SARA_H #define SOPT_WAVELETS_SARA_H #include "sopt/config.h" #include #include #include #include #include "sopt/logging.h" #include "sopt/wavelets/wavelets.h" namespace sopt { namespace wavelets { //! Sparsity Averaging Reweighted Analysis class SARA : public std::vector { public: #ifndef SOPT_HAS_NOT_USING // Constructors using std::vector::vector; #else //! Default constructor SARA() : std::vector(){}; #endif //! Easy constructor SARA(std::initializer_list> const &init) : SARA(init.begin(), init.end()) {} //! Construct from any iterator over a (std:string, t_uint) tuple template (*std::declval())), std::string>::value and std::is_convertible(*std::declval())), t_uint>::value>::type> SARA(ITERATOR first, ITERATOR last) { for(; first != last; ++first) emplace_back(std::get<0>(*first), std::get<1>(*first)); } //! Destructor virtual ~SARA() {} //! \brief Direct transform //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the maximum number of levels. Can be a matrix (2d-transform) //! or a column vector (1-d transform). //! \return wavelets coefficients arranged by columns: if the input is n by m, then the output //! is n by m * d, with d the number of wavelets. //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template typename T0::PlainObject direct(Eigen::ArrayBase const &signal) const; //! \brief Direct transform //! \param[inout] coefficients: Output wavelet coefficients. Must be of the type as the input. //! If the input is n by m, and d is the number of wavelets, then the output should be n by (m * //! d). //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the maximum number of levels. Can be a matrix (2d-transform) //! or a column vector (1-d transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template void direct(Eigen::ArrayBase &coefficients, Eigen::ArrayBase const &signal) const; //! \brief Direct transform //! \param[inout] coefficients: Output wavelet coefficients. Must be of the type as the input. //! If the input is n by m, and l is the number of wavelets, then the output should be n by (m * //! l). //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the number of levels. Can be a matrix (2d-transform) or a //! column vector (1-d transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. This version //! allows non-constant Eigen expressions to be passe on without the ugly `const_cast` of the //! cannonical approach. template void direct(Eigen::ArrayBase &&coefficients, Eigen::ArrayBase const &signal) const { direct(coefficients, signal); } //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template typename T0::PlainObject indirect(Eigen::ArrayBase const &coeffs) const; //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! \param[inout] signal: Reconstructed signal. Must be of the same size and type as the input. //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template void indirect(Eigen::ArrayBase const &coefficients, Eigen::ArrayBase &signal) const; //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! \param[inout] signal: Reconstructed signal. Must be of the same size and type as the input. //! \details Supports 1 and 2 dimensional tranforms for real and complex data. This version //! allows non-constant Eigen expressions to be passe on without the ugly `const_cast` of the //! cannonical approach. template void indirect(Eigen::ArrayBase const &coeffs, Eigen::ArrayBase &&signal) const { indirect(coeffs, signal); } //! Number of levels over which to do transform t_uint max_levels() const { auto cmp = [](Wavelet const &a, Wavelet const &b) { return a.levels() < b.levels(); }; return std::max_element(begin(), end(), cmp)->levels(); } //! Adds a wavelet of specific type void emplace_back(std::string const &name, t_uint nlevels) { std::vector::emplace_back(factory(name, nlevels)); } }; #define SOPT_WAVELET_ERROR_MACRO(INPUT) \ if(INPUT.rows() % (1u << max_levels()) != 0) \ throw std::length_error("Inconsistent number of columns and wavelet levels"); \ else if(INPUT.cols() != 1 and INPUT.cols() % (1u << max_levels())) \ throw std::length_error("Inconsistent number of rows and wavelet levels"); template void SARA::direct(Eigen::ArrayBase &coeffs, Eigen::ArrayBase const &signal) const { SOPT_WAVELET_ERROR_MACRO(signal); if(coeffs.rows() != signal.rows() or coeffs.cols() != signal.cols() * static_cast(size())) coeffs.derived().resize(signal.rows(), signal.cols() * size()); if(coeffs.rows() != signal.rows() or coeffs.cols() != signal.cols() * static_cast(size())) throw std::length_error("Incorrect size for output matrix(or could not resize)"); auto const Ncols = signal.cols(); #ifndef SOPT_OPENMP SOPT_TRACE("Calling direct sara without threads"); for(size_type i(0); i < size(); ++i) at(i).direct(coeffs.leftCols((i + 1) * Ncols).rightCols(Ncols), signal); #else #pragma omp parallel { if(omp_get_thread_num() == 0) { SOPT_TRACE("Calling direct sara with {} threads of {}", omp_get_num_threads(), omp_get_max_threads()); } #pragma omp for for(size_type i = 0; i < size(); ++i) at(i).direct(coeffs.leftCols((i + 1) * Ncols).rightCols(Ncols), signal); } #endif coeffs /= std::sqrt(size()); } template void SARA::indirect(Eigen::ArrayBase const &coeffs, Eigen::ArrayBase &signal) const { SOPT_WAVELET_ERROR_MACRO(coeffs); if(coeffs.cols() % size() != 0) throw std::length_error( "Columns of coefficient matrix and number of wavelets are inconsistent"); if(coeffs.rows() != signal.rows() or coeffs.cols() != signal.cols() * static_cast(size())) signal.derived().resize(coeffs.rows(), coeffs.cols() / size()); if(coeffs.rows() != signal.rows() or coeffs.cols() != signal.cols() * static_cast(size())) throw std::length_error("Incorrect size for output matrix(or could not resize)"); auto const Ncols = signal.cols(); #ifndef SOPT_OPENMP SOPT_TRACE("Calling indirect sara without threads"); signal = front().indirect(coeffs.leftCols(Ncols).rightCols(Ncols)); for(size_type i(1); i < size(); ++i) signal += at(i).indirect(coeffs.leftCols((i + 1) * Ncols).rightCols(Ncols)); #else signal.fill(0); #pragma omp parallel { if(omp_get_thread_num() == 0) { SOPT_TRACE("Calling indirect sara with {} threads of {}", omp_get_num_threads(), omp_get_max_threads()); } Image reductor = Image::Zero(signal.rows(), Ncols); #pragma omp for for(size_type i = 0; i < size(); ++i) reductor += at(i).indirect(coeffs.leftCols((i + 1) * Ncols).rightCols(Ncols)); #pragma omp critical signal += reductor; } #endif signal /= std::sqrt(size()); } #undef SOPT_WAVELET_ERROR_MACRO template typename T0::PlainObject SARA::indirect(Eigen::ArrayBase const &coeffs) const { typedef decltype(this->front().indirect(coeffs)) t_Output; t_Output signal = t_Output::Zero(coeffs.rows(), coeffs.cols() / size()); (*this).indirect(coeffs, signal); return signal; } template typename T0::PlainObject SARA::direct(Eigen::ArrayBase const &signal) const { typedef decltype(this->front().direct(signal)) t_Output; t_Output result = t_Output::Zero(signal.rows(), signal.cols() * size()); (*this).direct(result, signal); return result; } } } #endif sopt-2.0.0/cpp/sopt/wavelets/wavelet_data.cc000066400000000000000000004037301277570055300210700ustar00rootroot00000000000000#include "sopt/wavelets/wavelet_data.h" #include "sopt/config.h" #include #include #include "sopt/types.h" namespace sopt { namespace wavelets { namespace { //! Vector setup from initializer list, because easier WaveletData::t_vector init_db(std::initializer_list const &input) { sopt::Vector<> result(input.size()); std::copy(input.begin(), input.end(), result.data()); return result; } //! Every other element is negative WaveletData::t_vector negate_even(WaveletData::t_vector const &coeffs) { WaveletData::t_vector result(coeffs); for(t_int i(0); i < static_cast(coeffs.size()); i += 2) result(i) = -result(i); return result; } //! Odd elements only WaveletData::t_vector odd(WaveletData::t_vector const &coeffs) { WaveletData::t_vector result(coeffs.size() / 2); for(t_int i(1); i < static_cast(coeffs.size()); i += 2) result(i / 2) = coeffs(i); return result; } //! Even elements only WaveletData::t_vector even(WaveletData::t_vector const &coeffs) { WaveletData::t_vector result((coeffs.size() + 1) / 2); for(t_int i(0), j(0); i < static_cast(coeffs.size()); i += 2, ++j) result(j) = coeffs(i); return result; } } WaveletData::WaveletData(std::initializer_list const &coeffs) : WaveletData(init_db(coeffs)) {} WaveletData::WaveletData(t_vector const &coeffs) : coefficients(coeffs), direct_filter{coeffs, negate_even(coeffs.reverse())}, indirect_filter{even(coeffs.reverse()), odd(coeffs.reverse()), even(coeffs), -odd(coeffs)} {} WaveletData const Daubechies1({7.071067811865475244008443621048490392848359376884740365883398e-01, 7.071067811865475244008443621048490392848359376884740365883398e-01}); WaveletData const Daubechies2({4.829629131445341433748715998644486838169524195042022752011715e-01, 8.365163037378079055752937809168732034593703883484392934953414e-01, 2.241438680420133810259727622404003554678835181842717613871683e-01, -1.294095225512603811744494188120241641745344506599652569070016e-01}); WaveletData const Daubechies3({3.326705529500826159985115891390056300129233992450683597084705e-01, 8.068915093110925764944936040887134905192973949948236181650920e-01, 4.598775021184915700951519421476167208081101774314923066433867e-01, -1.350110200102545886963899066993744805622198452237811919756862e-01, -8.544127388202666169281916918177331153619763898808662976351748e-02, 3.522629188570953660274066471551002932775838791743161039893406e-02}); WaveletData const Daubechies4({2.303778133088965008632911830440708500016152482483092977910968e-01, 7.148465705529156470899219552739926037076084010993081758450110e-01, 6.308807679298589078817163383006152202032229226771951174057473e-01, -2.798376941685985421141374718007538541198732022449175284003358e-02, -1.870348117190930840795706727890814195845441743745800912057770e-01, 3.084138183556076362721936253495905017031482172003403341821219e-02, 3.288301166688519973540751354924438866454194113754971259727278e-02, -1.059740178506903210488320852402722918109996490637641983484974e-02}); WaveletData const Daubechies5({1.601023979741929144807237480204207336505441246250578327725699e-01, 6.038292697971896705401193065250621075074221631016986987969283e-01, 7.243085284377729277280712441022186407687562182320073725767335e-01, 1.384281459013207315053971463390246973141057911739561022694652e-01, -2.422948870663820318625713794746163619914908080626185983913726e-01, -3.224486958463837464847975506213492831356498416379847225434268e-02, 7.757149384004571352313048938860181980623099452012527983210146e-02, -6.241490212798274274190519112920192970763557165687607323417435e-03, -1.258075199908199946850973993177579294920459162609785020169232e-02, 3.335725285473771277998183415817355747636524742305315099706428e-03}); WaveletData const Daubechies6({1.115407433501094636213239172409234390425395919844216759082360e-01, 4.946238903984530856772041768778555886377863828962743623531834e-01, 7.511339080210953506789344984397316855802547833382612009730420e-01, 3.152503517091976290859896548109263966495199235172945244404163e-01, -2.262646939654398200763145006609034656705401539728969940143487e-01, -1.297668675672619355622896058765854608452337492235814701599310e-01, 9.750160558732304910234355253812534233983074749525514279893193e-02, 2.752286553030572862554083950419321365738758783043454321494202e-02, -3.158203931748602956507908069984866905747953237314842337511464e-02, 5.538422011614961392519183980465012206110262773864964295476524e-04, 4.777257510945510639635975246820707050230501216581434297593254e-03, -1.077301085308479564852621609587200035235233609334419689818580e-03}); WaveletData const Daubechies7({7.785205408500917901996352195789374837918305292795568438702937e-02, 3.965393194819173065390003909368428563587151149333287401110499e-01, 7.291320908462351199169430703392820517179660611901363782697715e-01, 4.697822874051931224715911609744517386817913056787359532392529e-01, -1.439060039285649754050683622130460017952735705499084834401753e-01, -2.240361849938749826381404202332509644757830896773246552665095e-01, 7.130921926683026475087657050112904822711327451412314659575113e-02, 8.061260915108307191292248035938190585823820965629489058139218e-02, -3.802993693501441357959206160185803585446196938467869898283122e-02, -1.657454163066688065410767489170265479204504394820713705239272e-02, 1.255099855609984061298988603418777957289474046048710038411818e-02, 4.295779729213665211321291228197322228235350396942409742946366e-04, -1.801640704047490915268262912739550962585651469641090625323864e-03, 3.537137999745202484462958363064254310959060059520040012524275e-04}); WaveletData const Daubechies8({5.441584224310400995500940520299935503599554294733050397729280e-02, 3.128715909142999706591623755057177219497319740370229185698712e-01, 6.756307362972898068078007670471831499869115906336364227766759e-01, 5.853546836542067127712655200450981944303266678053369055707175e-01, -1.582910525634930566738054787646630415774471154502826559735335e-02, -2.840155429615469265162031323741647324684350124871451793599204e-01, 4.724845739132827703605900098258949861948011288770074644084096e-04, 1.287474266204784588570292875097083843022601575556488795577000e-01, -1.736930100180754616961614886809598311413086529488394316977315e-02, -4.408825393079475150676372323896350189751839190110996472750391e-02, 1.398102791739828164872293057263345144239559532934347169146368e-02, 8.746094047405776716382743246475640180402147081140676742686747e-03, -4.870352993451574310422181557109824016634978512157003764736208e-03, -3.917403733769470462980803573237762675229350073890493724492694e-04, 6.754494064505693663695475738792991218489630013558432103617077e-04, -1.174767841247695337306282316988909444086693950311503927620013e-04}); WaveletData const Daubechies9({3.807794736387834658869765887955118448771714496278417476647192e-02, 2.438346746125903537320415816492844155263611085609231361429088e-01, 6.048231236901111119030768674342361708959562711896117565333713e-01, 6.572880780513005380782126390451732140305858669245918854436034e-01, 1.331973858250075761909549458997955536921780768433661136154346e-01, -2.932737832791749088064031952421987310438961628589906825725112e-01, -9.684078322297646051350813353769660224825458104599099679471267e-02, 1.485407493381063801350727175060423024791258577280603060771649e-01, 3.072568147933337921231740072037882714105805024670744781503060e-02, -6.763282906132997367564227482971901592578790871353739900748331e-02, 2.509471148314519575871897499885543315176271993709633321834164e-04, 2.236166212367909720537378270269095241855646688308853754721816e-02, -4.723204757751397277925707848242465405729514912627938018758526e-03, -4.281503682463429834496795002314531876481181811463288374860455e-03, 1.847646883056226476619129491125677051121081359600318160732515e-03, 2.303857635231959672052163928245421692940662052463711972260006e-04, -2.519631889427101369749886842878606607282181543478028214134265e-04, 3.934732031627159948068988306589150707782477055517013507359938e-05}); WaveletData const Daubechies10({2.667005790055555358661744877130858277192498290851289932779975e-02, 1.881768000776914890208929736790939942702546758640393484348595e-01, 5.272011889317255864817448279595081924981402680840223445318549e-01, 6.884590394536035657418717825492358539771364042407339537279681e-01, 2.811723436605774607487269984455892876243888859026150413831543e-01, -2.498464243273153794161018979207791000564669737132073715013121e-01, -1.959462743773770435042992543190981318766776476382778474396781e-01, 1.273693403357932600826772332014009770786177480422245995563097e-01, 9.305736460357235116035228983545273226942917998946925868063974e-02, -7.139414716639708714533609307605064767292611983702150917523756e-02, -2.945753682187581285828323760141839199388200516064948779769654e-02, 3.321267405934100173976365318215912897978337413267096043323351e-02, 3.606553566956169655423291417133403299517350518618994762730612e-03, -1.073317548333057504431811410651364448111548781143923213370333e-02, 1.395351747052901165789318447957707567660542855688552426721117e-03, 1.992405295185056117158742242640643211762555365514105280067936e-03, -6.858566949597116265613709819265714196625043336786920516211903e-04, -1.164668551292854509514809710258991891527461854347597362819235e-04, 9.358867032006959133405013034222854399688456215297276443521873e-05, -1.326420289452124481243667531226683305749240960605829756400674e-05}); WaveletData const Daubechies11({1.869429776147108402543572939561975728967774455921958543286692e-02, 1.440670211506245127951915849361001143023718967556239604318852e-01, 4.498997643560453347688940373853603677806895378648933474599655e-01, 6.856867749162005111209386316963097935940204964567703495051589e-01, 4.119643689479074629259396485710667307430400410187845315697242e-01, -1.622752450274903622405827269985511540744264324212130209649667e-01, -2.742308468179469612021009452835266628648089521775178221905778e-01, 6.604358819668319190061457888126302656753142168940791541113457e-02, 1.498120124663784964066562617044193298588272420267484653796909e-01, -4.647995511668418727161722589023744577223260966848260747450320e-02, -6.643878569502520527899215536971203191819566896079739622858574e-02, 3.133509021904607603094798408303144536358105680880031964936445e-02, 2.084090436018106302294811255656491015157761832734715691126692e-02, -1.536482090620159942619811609958822744014326495773000120205848e-02, -3.340858873014445606090808617982406101930658359499190845656731e-03, 4.928417656059041123170739741708273690285547729915802418397458e-03, -3.085928588151431651754590726278953307180216605078488581921562e-04, -8.930232506662646133900824622648653989879519878620728793133358e-04, 2.491525235528234988712216872666801088221199302855425381971392e-04, 5.443907469936847167357856879576832191936678525600793978043688e-05, -3.463498418698499554128085159974043214506488048233458035943601e-05, 4.494274277236510095415648282310130916410497987383753460571741e-06}); WaveletData const Daubechies12({1.311225795722951750674609088893328065665510641931325007748280e-02, 1.095662728211851546057045050248905426075680503066774046383657e-01, 3.773551352142126570928212604879206149010941706057526334705839e-01, 6.571987225793070893027611286641169834250203289988412141394281e-01, 5.158864784278156087560326480543032700677693087036090056127647e-01, -4.476388565377462666762747311540166529284543631505924139071704e-02, -3.161784537527855368648029353478031098508839032547364389574203e-01, -2.377925725606972768399754609133225784553366558331741152482612e-02, 1.824786059275796798540436116189241710294771448096302698329011e-01, 5.359569674352150328276276729768332288862665184192705821636342e-03, -9.643212009650708202650320534322484127430880143045220514346402e-02, 1.084913025582218438089010237748152188661630567603334659322512e-02, 4.154627749508444073927094681906574864513532221388374861287078e-02, -1.221864906974828071998798266471567712982466093116558175344811e-02, -1.284082519830068329466034471894728496206109832314097633275225e-02, 6.711499008795509177767027068215672450648112185856456740379455e-03, 2.248607240995237599950865211267234018343199786146177099262010e-03, -2.179503618627760471598903379584171187840075291860571264980942e-03, 6.545128212509595566500430399327110729111770568897356630714552e-06, 3.886530628209314435897288837795981791917488573420177523436096e-04, -8.850410920820432420821645961553726598738322151471932808015443e-05, -2.424154575703078402978915320531719580423778362664282239377532e-05, 1.277695221937976658714046362616620887375960941439428756055353e-05, -1.529071758068510902712239164522901223197615439660340672602696e-06}); WaveletData const Daubechies13({9.202133538962367972970163475644184667534171916416562386009703e-03, 8.286124387290277964432027131230466405208113332890135072514277e-02, 3.119963221604380633960784112214049693946683528967180317160390e-01, 6.110558511587876528211995136744180562073612676018239438526582e-01, 5.888895704312189080710395347395333927665986382812836042235573e-01, 8.698572617964723731023739838087494399231884076619701250882016e-02, -3.149729077113886329981698255932282582876888450678789025950306e-01, -1.245767307508152589413808336021260180792739295173634719572069e-01, 1.794760794293398432348450072339369013581966256244133393042881e-01, 7.294893365677716380902830610477661983325929026879873553627963e-02, -1.058076181879343264509667304196464849478860754801236658232360e-01, -2.648840647534369463963912248034785726419604844297697016264224e-02, 5.613947710028342886214501998387331119988378792543100244737056e-02, 2.379972254059078811465170958554208358094394612051934868475139e-03, -2.383142071032364903206403067757739134252922717636226274077298e-02, 3.923941448797416243316370220815526558824746623451404043918407e-03, 7.255589401617566194518393300502698898973529679646683695269828e-03, -2.761911234656862178014576266098445995350093330501818024966316e-03, -1.315673911892298936613835370593643376060412592653652307238124e-03, 9.323261308672633862226517802548514100918088299801952307991569e-04, 4.925152512628946192140957387866596210103778299388823500840094e-05, -1.651289885565054894616687709238000755898548214659776703347801e-04, 3.067853757932549346649483228575476236600428217237900563128230e-05, 1.044193057140813708170714991080596951670706436217328169641474e-05, -4.700416479360868325650195165061771321650383582970958556568059e-06, 5.220035098454864691736424354843176976747052155243557001531901e-07}); WaveletData const Daubechies14({6.461153460087947818166397448622814272327159419201199218101404e-03, 6.236475884939889832798566758434877428305333693407667164602518e-02, 2.548502677926213536659077886778286686187042416367137443780084e-01, 5.543056179408938359926831449851154844078269830951634609683997e-01, 6.311878491048567795576617135358172348623952456570017289788809e-01, 2.186706877589065214917475918217517051765774321270432059030273e-01, -2.716885522787480414142192476181171094604882465683330814311896e-01, -2.180335299932760447555558812702311911975240669470604752747127e-01, 1.383952138648065910739939690021573713989900463229686119059119e-01, 1.399890165844607012492943162271163440328221555614326181333683e-01, -8.674841156816968904560822066727795382979149539517503657492964e-02, -7.154895550404613073584145115173807990958069673129538099990913e-02, 5.523712625921604411618834060533403397913833632511672157671107e-02, 2.698140830791291697399031403215193343375766595807274233284349e-02, -3.018535154039063518714822623489137573781575406658652624883756e-02, -5.615049530356959133218371367691498637457297203925810387698680e-03, 1.278949326633340896157330705784079299374903861572058313481534e-02, -7.462189892683849371817160739181780971958187988813302900435487e-04, -3.849638868022187445786349316095551774096818508285700493058915e-03, 1.061691085606761843032566749388411173033941582147830863893939e-03, 7.080211542355278586442977697617128983471863464181595371670094e-04, -3.868319473129544821076663398057314427328902107842165379901468e-04, -4.177724577037259735267979539839258928389726590132730131054323e-05, 6.875504252697509603873437021628031601890370687651875279882727e-05, -1.033720918457077394661407342594814586269272509490744850691443e-05, -4.389704901781394115254042561367169829323085360800825718151049e-06, 1.724994675367812769885712692741798523587894709867356576910717e-06, -1.787139968311359076334192938470839343882990309976959446994022e-07}); WaveletData const Daubechies15({4.538537361578898881459394910211696346663671243788786997916513e-03, 4.674339489276627189170969334843575776579151700214943513113197e-02, 2.060238639869957315398915009476307219306138505641930902702047e-01, 4.926317717081396236067757074029946372617221565130932402160160e-01, 6.458131403574243581764209120106917996432608287494046181071489e-01, 3.390025354547315276912641143835773918756769491793554669336690e-01, -1.932041396091454287063990534321471746304090039142863827937754e-01, -2.888825965669656462484125009822332981311435630435342594971292e-01, 6.528295284877281692283107919869574882039174285596144125965101e-02, 1.901467140071229823484893116586020517959501258174336696878156e-01, -3.966617655579094448384366751896200668381742820683736805449745e-02, -1.111209360372316933656710324674058608858623762165914120505657e-01, 3.387714392350768620854817844433523770864744687411265369463195e-02, 5.478055058450761268913790312581879108609415997422768564244845e-02, -2.576700732843996258594525754269826392203641634825340138396836e-02, -2.081005016969308167788483424677000162054657951364899040996166e-02, 1.508391802783590236329274460170322736244892823305627716233968e-02, 5.101000360407543169708860185565314724801066527344222055526631e-03, -6.487734560315744995181683149218690816955845639388826407928967e-03, -2.417564907616242811667225326300179605229946995814535223329411e-04, 1.943323980382211541764912332541087441011424865579531401452302e-03, -3.734823541376169920098094213645414611387630968030256625740226e-04, -3.595652443624688121649620075909808858194202454084090305627480e-04, 1.558964899205997479471658241227108816255567059625495915228603e-04, 2.579269915531893680925862417616855912944042368767340709160119e-05, -2.813329626604781364755324777078478665791443876293788904267255e-05, 3.362987181737579803124845210420177472134846655864078187186304e-06, 1.811270407940577083768510912285841160577085925337507850590290e-06, -6.316882325881664421201597299517657654166137915121195510416641e-07, 6.133359913305752029056299460289788601989190450885396512173845e-08}); WaveletData const Daubechies16({3.189220925347738029769547564645958687067086750131428767875878e-03, 3.490771432367334641030147224023020009218241430503984146140054e-02, 1.650642834888531178991252730561134811584835002342723240213592e-01, 4.303127228460038137403925424357684620633970478036986773924646e-01, 6.373563320837888986319852412996030536498595940814198125967751e-01, 4.402902568863569000390869163571679288527803035135272578789884e-01, -8.975108940248964285718718077442597430659247445582660149624718e-02, -3.270633105279177046462905675689119641757228918228812428141723e-01, -2.791820813302827668264519595026873204339971219174736041535479e-02, 2.111906939471042887209680163268837900928491426167679439251042e-01, 2.734026375271604136485245757201617965429027819507130220231500e-02, -1.323883055638103904500474147756493375092287817706027978798549e-01, -6.239722752474871765674503394120025865444656311678760990761458e-03, 7.592423604427631582148498743941422461530405946100943351940313e-02, -7.588974368857737638494890864636995796586975144990925400097160e-03, -3.688839769173014233352666320894554314718748429706730831064068e-02, 1.029765964095596941165000580076616900528856265803662208854147e-02, 1.399376885982873102950451873670329726409840291727868988490100e-02, -6.990014563413916670284249536517288338057856199646469078115759e-03, -3.644279621498389932169000540933629387055333973353108668841215e-03, 3.128023381206268831661202559854678767821471906193608117450360e-03, 4.078969808497128362417470323406095782431952972310546715071397e-04, -9.410217493595675889266453953635875407754747216734480509250273e-04, 1.142415200387223926440228099555662945839684344936472652877091e-04, 1.747872452253381803801758637660746874986024728615399897971953e-04, -6.103596621410935835162369150522212811957259981965919143961722e-05, -1.394566898820889345199078311998401982325273569198675335408707e-05, 1.133660866127625858758848762886536997519471068203753661757843e-05, -1.043571342311606501525454737262615404887478930635676471546032e-06, -7.363656785451205512099695719725563646585445545841663327433569e-07, 2.308784086857545866405412732942006121306306735866655525372544e-07, -2.109339630100743097000572623603489906836297584591605307745349e-08}); WaveletData const Daubechies17({2.241807001037312853535962677074436914062191880560370733250531e-03, 2.598539370360604338914864591720788315473944524878241294399948e-02, 1.312149033078244065775506231859069960144293609259978530067004e-01, 3.703507241526411504492548190721886449477078876896803823650425e-01, 6.109966156846228181886678867679372082737093893358726291371783e-01, 5.183157640569378393254538528085968046216817197718416402439904e-01, 2.731497040329363500431250719147586480350469818964563003672942e-02, -3.283207483639617360909665340725061767581597698151558024679130e-01, -1.265997522158827028744679110933825505053966260104086162103728e-01, 1.973105895650109927854047044781930142551422414135646917122284e-01, 1.011354891774702721509699856433434802196622545499664876109437e-01, -1.268156917782863110948571128662331680384792185915017065732137e-01, -5.709141963167692728911239478651382324161160869845347053990144e-02, 8.110598665416088507965885748555429201024364190954499194020678e-02, 2.231233617810379595339136059534813756232242114093689244020869e-02, -4.692243838926973733300897059211400507138768125498030602878439e-02, -3.270955535819293781655360222177494452069525958061609392809275e-03, 2.273367658394627031845616244788448969906713741338339498024864e-02, -3.042989981354637068592482637907206078633395457225096588287881e-03, -8.602921520322854831713706413243659917926736284271730611920986e-03, 2.967996691526094872806485060008038269959463846548378995044195e-03, 2.301205242153545624302059869038423604241976680189447476064764e-03, -1.436845304802976126222890402980384903503674530729935809561434e-03, -3.281325194098379713954444017520115075812402442728749700195651e-04, 4.394654277686436778385677527317841632289249319738892179465910e-04, -2.561010956654845882729891210949920221664082061531909655178413e-05, -8.204803202453391839095482576282189866136273049636764338689593e-05, 2.318681379874595084482068205706277572106695174091895338530734e-05, 6.990600985076751273204549700855378627762758585902057964027481e-06, -4.505942477222988194102268206378312129713572600716499944918416e-06, 3.016549609994557415605207594879939763476168705217646897702706e-07, 2.957700933316856754979905258816151367870345628924317307354639e-07, -8.423948446002680178787071296922877068410310942222799622593133e-08, 7.267492968561608110879767441409035034158581719789791088892046e-09}); WaveletData const Daubechies18({1.576310218440760431540744929939777747670753710991660363684429e-03, 1.928853172414637705921391715829052419954667025288497572236714e-02, 1.035884658224235962241910491937253596470696555220241672976224e-01, 3.146789413370316990571998255652579931786706190489374509491307e-01, 5.718268077666072234818589370900623419393673743130930561295324e-01, 5.718016548886513352891119994065965025668047882818525060759395e-01, 1.472231119699281415750977271081072312557864107355701387801677e-01, -2.936540407365587442479030994981150723935710729035053239661752e-01, -2.164809340051429711237678625668271471437937235669492408388692e-01, 1.495339755653777893509301738913667208804816691893765610261943e-01, 1.670813127632574045149318139950134745324205646353988083152250e-01, -9.233188415084628060429372558659459731431848000144569612074508e-02, -1.067522466598284855932200581614984861385266404624112083917702e-01, 6.488721621190544281947577955141911463129382116634147846137149e-02, 5.705124773853688412090768846499622260596226120431038524600676e-02, -4.452614190298232471556143559744653492971477891439833592755034e-02, -2.373321039586000103275209582665216110197519330713490233071565e-02, 2.667070592647059029987908631672020343207895999936072813363471e-02, 6.262167954305707485236093144497882501990325204745013190268052e-03, -1.305148094661200177277636447600807169755191054507571666606133e-02, 1.186300338581174657301741592161819084544899417452317405185615e-04, 4.943343605466738130665529516802974834299638313366477765295203e-03, -1.118732666992497072800658855238650182318060482584970145512687e-03, -1.340596298336106629517567228251583609823044524685986640323942e-03, 6.284656829651457125619449885420838217551022796301582874349652e-04, 2.135815619103406884039052814341926025873200325996466522543440e-04, -1.986485523117479485798245416362489554927797880264017876139605e-04, -1.535917123534724675069770335876717193700472427021513236587288e-07, 3.741237880740038181092208138035393952304292615793985030731363e-05, -8.520602537446695203919254911655523022437596956226376512305917e-06, -3.332634478885821888782452033341036827311505907796498439829337e-06, 1.768712983627615455876328730755375176412501359114058815453100e-06, -7.691632689885176146000152878539598405817397588156525116769908e-08, -1.176098767028231698450982356561292561347579777695396953528141e-07, 3.068835863045174800935478294933975372450179787894574492930570e-08, -2.507934454948598267195173183147126731806317144868275819941403e-09}); WaveletData const Daubechies19({1.108669763181710571099154195209715164245299677773435932135455e-03, 1.428109845076439737439889152950199234745663442163665957870715e-02, 8.127811326545955065296306784901624839844979971028620366497726e-02, 2.643884317408967846748100380289426873862377807211920718417385e-01, 5.244363774646549153360575975484064626044633641048072116393160e-01, 6.017045491275378948867077135921802620536565639585963293313931e-01, 2.608949526510388292872456675310528324172673101301907739925213e-01, -2.280913942154826463746325776054637207093787237086425909534822e-01, -2.858386317558262418545975695028984237217356095588335149922119e-01, 7.465226970810326636763433111878819005865866149731909656365399e-02, 2.123497433062784888090608567059824197077074200878839448416908e-01, -3.351854190230287868169388418785731506977845075238966819814032e-02, -1.427856950387365749779602731626112812998497706152428508627562e-01, 2.758435062562866875014743520162198655374474596963423080762818e-02, 8.690675555581223248847645428808443034785208002468192759640352e-02, -2.650123625012304089901835843676387361075068017686747808171345e-02, -4.567422627723090805645444214295796017938935732115630050880109e-02, 2.162376740958504713032984257172372354318097067858752542571020e-02, 1.937554988917612764637094354457999814496885095875825546406963e-02, -1.398838867853514163250401235248662521916813867453095836808366e-02, -5.866922281012174726584493436054373773814608340808758177372765e-03, 7.040747367105243153014511207400620109401689897665383078229398e-03, 7.689543592575483559749139148673955163477947086039406129546422e-04, -2.687551800701582003957363855070398636534038920982478290170267e-03, 3.418086534585957765651657290463808135214214848819517257794031e-04, 7.358025205054352070260481905397281875183175792779904858189494e-04, -2.606761356786280057318315130897522790383939362073563408613547e-04, -1.246007917341587753449784408901653990317341413341980904757592e-04, 8.711270467219922965416862388191128268412933893282083517729443e-05, 5.105950487073886053049222809934231573687367992106282669389264e-06, -1.664017629715494454620677719899198630333675608812018108739144e-05, 3.010964316296526339695334454725943632645798938162427168851382e-06, 1.531931476691193063931832381086636031203123032723477463624141e-06, -6.862755657769142701883554613486732854452740752771392411758418e-07, 1.447088298797844542078219863291615420551673574071367834316167e-08, 4.636937775782604223430857728210948898871748291085962296649320e-08, -1.116402067035825816390504769142472586464975799284473682246076e-08, 8.666848838997619350323013540782124627289742190273059319122840e-10}); WaveletData const Daubechies20({7.799536136668463215861994818889370970510722039232863880031127e-04, 1.054939462495039832454480973015641498231961468733236691299796e-02, 6.342378045908151497587346582668785136406523315729666353643372e-02, 2.199421135513970450080335972537209392121306761010882209298252e-01, 4.726961853109016963710241465101446230757804141171727845834637e-01, 6.104932389385938201631515660084201906858628924695448898824748e-01, 3.615022987393310629195602665268631744967084723079677894136358e-01, -1.392120880114838725806970545155530518264944915437808314813582e-01, -3.267868004340349674031122837905370666716645587480021744425550e-01, -1.672708830907700757517174997304297054003744303620479394006890e-02, 2.282910508199163229728429126648223086437547237250290835639880e-01, 3.985024645777120219790581076522174181104027576954427684456660e-02, -1.554587507072679559315307870562464374359996091752285157077477e-01, -2.471682733861358401587992299169922262915151413349313513685587e-02, 1.022917191744425578861013681016866083888381385233081516583444e-01, 5.632246857307435506953246988215209861566800664402785938591145e-03, -6.172289962468045973318658334083283558209278762007041823250642e-02, 5.874681811811826491300679742081997167209743446956901841959711e-03, 3.229429953076958175885440860617219117564558605035979601073235e-02, -8.789324923901561348753650366700695916503030939283830968151332e-03, -1.381052613715192007819606423860356590496904285724730356602106e-02, 6.721627302259456835336850521405425560520025237915708362002910e-03, 4.420542387045790963058229526673514088808999478115581153468068e-03, -3.581494259609622777556169638358238375765194248623891034940330e-03, -8.315621728225569192482585199373230956924484221135739973390038e-04, 1.392559619323136323905254999347967283760544147397530531142397e-03, -5.349759843997695051759716377213680036185796059087353172073952e-05, -3.851047486992176060650288501475716463266233035937022303649838e-04, 1.015328897367029050797488785306056522529979267572003990901472e-04, 6.774280828377729558011184406727978221295796652200819839464354e-05, -3.710586183394712864227221271216408416958225264980612822617745e-05, -4.376143862183996810373095822528607606900620592585762190542483e-06, 7.241248287673620102843105877497181565468725757387007139555885e-06, -1.011994010018886150340475413756849103197395069431085005709201e-06, -6.847079597000556894163334787575159759109091330092963990364192e-07, 2.633924226270001084129057791994367121555769686616747162262697e-07, 2.014322023550512694324757845944026047904414136633776958392681e-10, -1.814843248299695973210605258227024081458531110762083371310917e-08, 4.056127055551832766099146230616888024627380574113178257963252e-09, -2.998836489619319566407767078372705385732460052685621923178375e-10}); WaveletData const Daubechies21({5.488225098526837086776336675992521426750673054588245523834775e-04, 7.776639052354783754338787398088799862510779059555623704879234e-03, 4.924777153817727491399853378340056968104483161598320693657954e-02, 1.813596254403815156260378722764624190931951510708050516519181e-01, 4.196879449393627730946850609089266339973601543036294871772653e-01, 6.015060949350038975629880664020955953066542593896126705346122e-01, 4.445904519276003403643290994523601016151342743089878478478962e-01, -3.572291961725529045922914178005307189036762547143966578066838e-02, -3.356640895305295094832978867114363069987575282256098351499731e-01, -1.123970715684509813515004981340306901641824212464197973490295e-01, 2.115645276808723923846781645238468659430862736248896128529373e-01, 1.152332984396871041993434411681730428103160016594558944687967e-01, -1.399404249325472249247758764839776903226503657502071670245304e-01, -8.177594298086382887387303634193790542522570670234556157566786e-02, 9.660039032372422070232189700372539681627783322249829842275517e-02, 4.572340574922879239251202944731235421034828710753381191345186e-02, -6.497750489373232063332311106008616685748929419452249544690967e-02, -1.865385920211851534093244412008141266131208093007217139232170e-02, 3.972683542785044175197464400756126818299918992482587866999707e-02, 3.357756390338110842532604766376200760791669954106679933144723e-03, -2.089205367797907948785235479746212371728219866525211135343707e-02, 2.403470920805434762380632169785689545910525667396313550679652e-03, 8.988824381971911875349463398395464114417817949738911101372312e-03, -2.891334348588901247375268718015882610844675931117463495551958e-03, -2.958374038932831280750770228215510959830170264176955719827510e-03, 1.716607040630624138494506282569230126333308533535502799235333e-03, 6.394185005120302146432543767052865436099994387647359452249347e-04, -6.906711170821016507268939228893784790518270744313525548714065e-04, -3.196406277680437193708834220804640347636984901270948088339102e-05, 1.936646504165080615323696689856004910579777568504218782029027e-04, -3.635520250086338309442855006186370752206331429871136596927137e-05, -3.499665984987447953974079490046597240276268044409625722689849e-05, 1.535482509276049283124233498646050472096482329299719141107128e-05, 2.790330539814487046106169582691767916283793946025922387556917e-06, -3.090017164545699197158555936852697325985864588418167982685400e-06, 3.166095442367030556603889009833954440058545355777781782000278e-07, 2.992136630464852794401294607536813682771292352506328096125857e-07, -1.000400879030597332045460600516621971679363965166249211063755e-07, -2.254014974673330131563184851456825991617915549643308754828159e-09, 7.058033541231121859020947976903904685464512825731230495144226e-09, -1.471954197650365265189549600816698778213247061389470277337173e-09, 1.038805571023706553035373138760372703492942617518816122570050e-10}); WaveletData const Daubechies22({3.862632314910982158524358900615460368877852009576899680767316e-04, 5.721854631334539120809783403484493333555361591386208129183833e-03, 3.806993723641108494769873046391825574447727068953448390456335e-02, 1.483675408901114285014404448710249837385836373168215616427030e-01, 3.677286834460374788614690818452372827430535649696462720334897e-01, 5.784327310095244271421181831735444106385099957908657145590104e-01, 5.079010906221639018391523325390716836568713192498711562711282e-01, 7.372450118363015165570139016530653113725172412104955350368114e-02, -3.127265804282961918033226222621788537078452535993545440716988e-01, -2.005684061048870939324361244042200174132905844868237447130382e-01, 1.640931881067664818606223226286885712554385317412228836705888e-01, 1.799731879928913037252154295313083168387840791424988422757762e-01, -9.711079840911470969274209179691733251456735137994201552926799e-02, -1.317681376866834107513648518146838345477875022352088357523838e-01, 6.807631439273221556739202147004580559367442550641388181886023e-02, 8.455737636682607503362813659356786494357635805197410905877078e-02, -5.136425429744413245727949984018884707909441768477091944584584e-02, -4.653081182750671347875833607846979997825771277976548080904423e-02, 3.697084662069802057615318892988581825637896696876361343354380e-02, 2.058670762756536044060249710676656807281671451609632981487139e-02, -2.348000134449318868560142854519364987363882333754753819791381e-02, -6.213782849364658499069336123807608293122900450508440420104462e-03, 1.256472521834337406887017835495604463815382993214296088172221e-02, 3.001373985076435951229129255588255746904937042979316054485183e-04, -5.455691986156717076595353163071679107868762395367234726592273e-03, 1.044260739186025323350755659184734060807432172611689413745029e-03, 1.827010495657279080112597436850157110235336772062961041154607e-03, -7.706909881231196232880372722955519781655769913634565757339739e-04, -4.237873998391800799531947768003976978197438302533528661825758e-04, 3.286094142136787341983758471405935405823323072829619248523697e-04, 4.345899904532003379046992625575076092823809665933575578710696e-05, -9.405223634815760421845190098352673647881298980040512091599943e-05, 1.137434966212593172736144274866639210339820203135670505287250e-05, 1.737375695756189356163565074505405906859746605867772002320509e-05, -6.166729316467578372152251668422979152169587307212708981768966e-06, -1.565179131995160159307426993578204733378112742579926503832095e-06, 1.295182057318877573889711232345068147800395721925682566394936e-06, -8.779879873361286276888117046153049053917243760475816789226764e-08, -1.283336228751754417819693932114064887075096030264748079976736e-07, 3.761228749337362366156711648187743399164239397803629022612862e-08, 1.680171404922988885554331183691280245962290247654438114807112e-09, -2.729623146632976083449327361739104754443221903317745768938846e-09, 5.335938821667489905169783227036804533253011117886586305435615e-10, -3.602113484339554703794807810939301847299106970237814334104274e-11}); WaveletData const Daubechies23({2.719041941282888414192673609703302357098336003920923958924757e-04, 4.202748893183833538390034372523511472345215563611003407984701e-03, 2.931000365788411514736204018929480427874317460676079959515131e-02, 1.205155317839719336306053895611899089004274336891709067958035e-01, 3.184508138528652363416527748460472152790575031409830417259640e-01, 5.449311478735204282674240672421984387504149924834544495466793e-01, 5.510185172419193913452724227212507720514144116478727269717859e-01, 1.813926253638400136259098302138614937264260737638175539416540e-01, -2.613921480306441118856795735210118413900307577511142987337375e-01, -2.714020986078430556604069575184718123763697177381058877113471e-01, 9.212540708241805260646030910734894258577648089100630012130261e-02, 2.235736582420402317149513960822561717689875252792817094811874e-01, -3.303744709428937875006612792463031409461636228731285046551636e-02, -1.640113215318759250156057837165276039181451149292112929401186e-01, 2.028307457564929974897286607551313323418860610791382310375731e-02, 1.122970436181072886950734465075645977754665593869789965874572e-01, -2.112621235622724100704783293549467048999443844657058425212982e-02, -7.020739157490110946204219011957565343899895499962369353294028e-02, 2.176585683449997560776882472168730165799461445156766923497545e-02, 3.849533252256919901057154320407596073180564628069920893870768e-02, -1.852351365015615979794689960740674782817814176166333519597796e-02, -1.753710100303584537915846117408613551147985251726558719415169e-02, 1.275194393152828646243157404474947115052750581861997731041018e-02, 6.031840650024162816289878206037841640814102314209075233751820e-03, -7.075319273706152814194039481466556204493276773483821748740018e-03, -1.134865473356251691289337120013286756337393784110786907825400e-03, 3.122876449818144997419144765125750522437659393621577492535411e-03, -2.465014005163512031940473100375377210862560761576109755841161e-04, -1.061231228886651321139357625683805642193648671030425010215075e-03, 3.194204927099011503676530359692366990929679170022583007683112e-04, 2.567624520078737205563856675376636092314813400664190770435450e-04, -1.500218503490340967673163290447832236259277810659068637402668e-04, -3.378894834120903434270962452674534330903724108906662510305045e-05, 4.426071203109246077621875303440935335701832843654692827539837e-05, -2.635207889249186237209225933170897825432335273771458456888097e-06, -8.347875567854625544366043748844183086765894974439245409223337e-06, 2.397569546840240057403739507525641239509517148980849889986407e-06, 8.147574834779447778085443041422881439860288287528356019216814e-07, -5.339005405209421154584783682848780965053642859373536945701365e-07, 1.853091785633965019353699857864654181728710556702529908304185e-08, 5.417549179539278736503176166323685597634496102979977037271945e-08, -1.399935495437998845130909687361847103274208993447892120341999e-08, -9.472885901812050535221582074673490573092096712822067564903012e-10, 1.050446453696543404071105111096438573423068913105255997908040e-09, -1.932405111313417542192651899622541612314066389643607507706887e-10, 1.250203302351040941433216718217504240541423430995137507404787e-11}); WaveletData const Daubechies24({1.914358009475513695026138336474115599435172088053846745168462e-04, 3.082081714905494436206199424544404720984720556128685270556458e-03, 2.248233994971641072358415157184825628226776692231940577581580e-02, 9.726223583362519663806545734008355914527504417674578571164300e-02, 2.729089160677263268706137134412557268751671263458895098625356e-01, 5.043710408399249919771876890402814109246866444441814540282099e-01, 5.749392210955419968460807901923407033144945935105622912839838e-01, 2.809855532337118833442626085115402941842959475929278883281409e-01, -1.872714068851562376981887159775791469060265778441667840307934e-01, -3.179430789993627375453948489797707550898087789160025182664299e-01, 4.776613684344728187950198323031360866349104994035553200788631e-03, 2.392373887803108551973268291945824822214858134512317715815616e-01, 4.252872964148383258147364472170645232684343235486951540533893e-02, -1.711753513703468896897638515080572393949165942335556397917666e-01, -3.877717357792001620177594726199572688446488033750771020190283e-02, 1.210163034692242362312637311149062286659377039046006801523826e-01, 2.098011370914481534980883827326017063121637262728447783605518e-02, -8.216165420800166702291466006164189460916816748629968198028898e-02, -4.578436241819221637997516339765068825260159169893967894877272e-03, 5.130162003998087915555334881398688958843078494595140394873884e-02, -4.944709428125628299815920032649550811877887219282751174798211e-03, -2.821310709490189098113895361900699228886900995412759197674058e-02, 7.661721881646585897329899904308764405384658404613669817843430e-03, 1.304997087108573583052494067883717533043101857128653233783396e-02, -6.291435370018187780721843581169343900864298634085743861509767e-03, -4.746568786323113800477796959513558401732252800905982385017245e-03, 3.736046178282523345179052160810332868725126356493155728625572e-03, 1.153764936839481504858282495202271984454410046682805375157566e-03, -1.696456818974824394274534636412116243080312601322325642741589e-03, -4.416184856141520063365958900079406737636243682138363561877750e-05, 5.861270593183109933716735450272894035425792347806515678695765e-04, -1.181233237969554740613021227756568966806892308457221016257961e-04, -1.460079817762616838924301818082729036314539476811023255670666e-04, 6.559388639305634085303738560455061974369354538271316071502698e-05, 2.183241460466558363365044032984257709791187640963509380549307e-05, -2.022888292612697682860859987200455702614855595412267510558659e-05, 1.341157750809114719319937553186023660581084151828593222893663e-08, 3.901100338597702610409014129024223853127911530009766793352492e-06, -8.980253143938407724149926669980791166378388013293887718404796e-07, -4.032507756879971624098983247358983425236092110387724315244646e-07, 2.166339653278574639176393978510246335478946697396400359281412e-07, -5.057645419792500308492508924343248979317507866520688417567606e-10, -2.255740388176086107368821674947175804005323153443170526520277e-08, 5.157776789671999638950774266313208715015419699643333784626363e-09, 4.748375824256231118094453549799175824526559994333227456737433e-10, -4.024658644584379774251499574468195118601698713554294941756559e-10, 6.991801157638230974132696433509625934021677793453732225542951e-11, -4.342782503803710247259037552886749457951053124203814185811297e-12}); WaveletData const Daubechies25({1.348029793470188994578489247159356055370460656508881471268611e-04, 2.256959591854779520121391049628056149270016860666661928130747e-03, 1.718674125404015533817186914954848902241194002444696221013131e-02, 7.803586287213267559750659320481403668422052199257139168386084e-02, 2.316935078860218199900621518057089104946216881512075361624214e-01, 4.596834151460945937896973864539659944010260858049947396093277e-01, 5.816368967460577833534892038757085635755639698734580573323031e-01, 3.678850748029466984371319740855532278670733841012809062966976e-01, -9.717464096463814276130048169040892607068486428294030952842447e-02, -3.364730796417461309562110148848845218930261030262170601615289e-01, -8.758761458765466140226687673880006154266689569025041229545538e-02, 2.245378197451017129525176510409543155930843160711989062118482e-01, 1.181552867199598604563067876819931882639429216001523151773895e-01, -1.505602137505796309518094206831433270850173484773520730186277e-01, -9.850861528996022153725952822686729410420350758543226219234795e-02, 1.066338050184779528831274540522414711301747903916268438037723e-01, 6.675216449401860666895983072443984697329752470942906490126865e-02, -7.708411105657419356208567671699032054872853174701595359329826e-02, -3.717396286112250887598137324046870459877639250821705817221557e-02, 5.361790939877949960629041419546536897037332284703545849594129e-02, 1.554260592910229163981295854603203625062268043511894295387375e-02, -3.404232046065334099320628584033729153497903561399447916116575e-02, -3.079836794847036661636693963570288706232460663070983852354326e-03, 1.892280447662762841086581178691039363674755753459524525886478e-02, -1.989425782202736494289461896386235348901617760816745484282494e-03, -8.860702618046368399013064252456556969199612331833605310278698e-03, 2.726936258738495739871469244610042793734119359765762028996059e-03, 3.322707773973191780118197357194829286271392998979276105842863e-03, -1.842484290203331280837780430014195744813667655929909114672154e-03, -8.999774237462950491085382524008429604309720852269895692000702e-04, 8.772581936748274843488806190175921376284150686011179612908221e-04, 1.153212440466300456460181455345639872216326644527860903202733e-04, -3.098800990984697989530544245356271119416614147098459162436317e-04, 3.543714523276059005284289830559259809540337561365927850248007e-05, 7.904640003965528255137496303166001735463107762646364003487560e-05, -2.733048119960041746353244004225286857636045649642652816856524e-05, -1.277195293199783804144903848434605690990373526086311486716394e-05, 8.990661393062588905369930197413951232059323587543226269327396e-06, 5.232827708153076417963912065899772684403904504491727061662335e-07, -1.779201332653634562565948556039009149458987774189389221295909e-06, 3.212037518862519094895005816661093988294166712919881121802831e-07, 1.922806790142371601278104244711267420759978799176017569693322e-07, -8.656941732278507163388031517930974947984281611717187862530250e-08, -2.611598556111770864259843089151782206922842627174274274741722e-09, 9.279224480081372372250073354726511359667401736947170444723772e-09, -1.880415755062155537197782595740975189878162661203102565611681e-09, -2.228474910228168899314793352064795957306403503495743572518755e-10, 1.535901570162657197021927739530721955859277615795931442682785e-10, -2.527625163465644811048864286169758128142169484216932624854015e-11, 1.509692082823910867903367712096001664979004526477422347957324e-12}); WaveletData const Daubechies26({9.493795750710592117802731381148054398461637804818126397577999e-05, 1.650520233532988247022384885622071050555268137055829216839523e-03, 1.309755429255850082057770240106799154079932963479202407364818e-02, 6.227474402514960484193581705107415937690538641013309745983962e-02, 1.950394387167700994245891508369324694703820522489789125908612e-01, 4.132929622783563686116108686666547082846741228042232731476147e-01, 5.736690430342222603195557147853022060758392664086633396520345e-01, 4.391583117891662321931477565794105633815363384084590559889493e-01, 1.774076780986685727823533562031556893226571319881417676492595e-03, -3.263845936917800216385340830055349953447745005769416287177497e-01, -1.748399612893925042664835683606584215248582345438816346170042e-01, 1.812918323111226960705459766025430918716233584167982942044424e-01, 1.827554095896723746537533832033286839689931924709760567945595e-01, -1.043239002859270439148009137202747658420968144330108510179290e-01, -1.479771932752544935782314546369458188243947772922980064071205e-01, 6.982318611329236513756591683950208955110603212379412334701145e-02, 1.064824052498086303236593797715344405836015002929319291715777e-01, -5.344856168148319149493577269390074213960237013099439431132086e-02, -6.865475960403591525454725258715351280947435823354011140858001e-02, 4.223218579637203541206570902753288247790857760067894456114927e-02, 3.853571597111186425832144567362328142994885395255438867968781e-02, -3.137811036306775484244644776337594435094096964336402798072360e-02, -1.776090356835818354094298625884058170354129044259951019182732e-02, 2.073492017996382475887790073068984224515077665517103399898854e-02, 5.829580555318887971939315747596613038479561943085291072787359e-03, -1.178549790619302893728624468402138072504226527540325463847390e-02, -5.287383992626814439198630765217969804966319971038003993984480e-04, 5.601947239423804853206514239940474788977188460452053462770324e-03, -9.390582504738289646165698675070641765810790863514339205205998e-04, -2.145530281567620980305401403432221668847980295600748913748902e-03, 8.383488056543616046381924054554052104937784379435436426690560e-04, 6.161382204574344193703789012696411561214682388271673214197731e-04, -4.319557074261807466712901913481943478521991611607433971794602e-04, -1.060574748283803889966150803551837402553866816191659959347053e-04, 1.574795238607493590547765666590811258087715699737771458390360e-04, -5.277795493037868976293566636015627609248847457646525246271036e-06, -4.109673996391477816326502438997466532822639385119090230965252e-05, 1.074221540872195031273584409245060623104931330938273936484593e-05, 7.000078682964986734859102495210684809643657474253921074934684e-06, -3.887400161856795187587790410706550576033603097954065074023128e-06, -4.650463220640262639231145944536092973446596027469833860001618e-07, 7.939210633709952088373459255067360793370284788682979065122810e-07, -1.079004237578671411922961583845716126060658213943840375162654e-07, -8.904466370168590769052983362721567202750591914741016835071257e-08, 3.407795621290730008673832107214820587991557116806912418558069e-08, 2.169328259850323106986222296525930099935873861026310788086221e-09, -3.776010478532324328184043667556576385639846460337894963138621e-09, 6.780047245828636668305808192607091517605349478677442468580825e-10, 1.002303191046526913509281844136258004034177309673269533418644e-10, -5.840408185341171468465492447799819262905317576847426970757700e-11, 9.130510016371796243923232926650252570239054815939483900056681e-12, -5.251871224244435037810503452564279828539007071678724285717464e-13}); WaveletData const Daubechies27({6.687131385431931734918880680779563307675740731544063787599480e-05, 1.205531231673213234251999812212394463872002561229330125152073e-03, 9.952588780876619771874091297340545740163119816300838847749336e-03, 4.945259998290488004302995584228917712171023349013386944893643e-02, 1.629220275023933206396286389387812803673796872000118325233533e-01, 3.671102141253898226423388094379126394383458407087000700420400e-01, 5.538498609904800487605460395549044755068663194750017660900436e-01, 4.934061226779989979265447084358038959373468583404767251300717e-01, 1.028408550618229112710739475157388764479351682549490307668477e-01, -2.897168033145948463175311101489473923261698802610323264603418e-01, -2.482645819032605667810198368127693701263349361209208170092197e-01, 1.148230195177853576326445213787661879970642975306605349249036e-01, 2.272732884141708265275037216925482827043581894357907763081103e-01, -3.878641863180231062443346843661817078060143110529946543683356e-02, -1.780317409590085821070366277249759321269342801053489323888575e-01, 1.579939746024048431173907799261019471878724997312653292884660e-02, 1.311979717171553289711406975836688896451835867594492827800969e-01, -1.406275155580876537026622167053147161846397735962817855782362e-02, -9.102290652956591798241345515773322449830692586525337562864481e-02, 1.731101826549371089085675445961947677452358872325373949295769e-02, 5.796940573471798814748840657698008349462526768238833307489106e-02, -1.851249356199807710545837861298826718763077900221574749342712e-02, -3.273906663102087145481936428049519742538150452785563039743756e-02, 1.614696692239566682272152627542980896527822528487665111124260e-02, 1.566559564892457873003263983940819950829497022298967052103291e-02, -1.157718645897628140054089958116866381056430680879332334217267e-02, -5.862096345462925972966025215266179082657169806555503857975278e-03, 6.856635609684880675273184141746359000591385833807880272568038e-03, 1.342626877303679609082208800217479591902967766971379107017011e-03, -3.332854469520006162763300141047111065412307706449049389557931e-03, 1.457529625931728587128588244152604734177322144376309490881599e-04, 1.301177450244135139135787970279897042994109161268159963884641e-03, -3.418351226915427611946547437228006377896519777431057005796358e-04, -3.879018574101327604369144470124819695479087900682219330965466e-04, 2.019719879690326857104208791272390315160018069955787875123234e-04, 7.660058387068576876674274961751262847965101108848090019821555e-05, -7.711145517797584208411720507329584053382646435270054267102827e-05, -3.517483614907445391752737841583832374184046409747387149129674e-06, 2.063442647736885318487206413360228908558806028468062177953960e-05, -3.901164070638425528170558032557368703418425915665413541985623e-06, -3.657500908187104997045760131046655906827644494899206692043298e-06, 1.634369624725637835424610743915128591988676092276368687669255e-06, 3.050880686251999094242671997731089918322345713516567387655763e-07, -3.472468147394389269364673179891460601330730511237974736379548e-07, 3.286558968055159530983261866450459360074591641809187825408848e-08, 4.026255052866908637178682747490340533992340623231336911661711e-08, -1.321332273990056558848617809101876846857728483295631388083263e-08, -1.309465606856955151282041809232358209226373823424148862843577e-09, 1.521614984778521740775073159445241799352681846880808663329946e-09, -2.415526928011130660506395791946234018673860470542996426005750e-10, -4.374986224293654395069947682013996351823060759948583134078918e-11, 2.213662088067662485181472969374945928903854605356443772873438e-11, -3.295790122476585807069953975043096139541415768606924980926275e-12, 1.828188352882424933624530026056448539377272017834175009418822e-13}); WaveletData const Daubechies28({4.710807775014051101066545468288837625869263629358873937759173e-05, 8.794985159843870273564636742144073059158975665525081816488582e-04, 7.542650377646859177160195786201116927568410621050693986450538e-03, 3.909260811540534426092083794403768111329778710541126982205076e-02, 1.351379142536410450770749411679708279921694061092200363031937e-01, 3.225633612855224257318486139030596702170126503618082416187649e-01, 5.249982316303355562348293243640252929543774162151269406404636e-01, 5.305162934414858075256978195354516449402692654391295761050628e-01, 2.001761440459844380384404537971725815970574972480152145882083e-01, -2.304989540475825257279397658067038304888129374484095837624889e-01, -3.013278095326417816909366061441334075444383937588485826752087e-01, 3.285787916338710468450547883547348694255260871071954509422161e-02, 2.458081513737595535752949960866466132239832334168533456626848e-01, 3.690688531571127205290633425993077868843846977265847006108551e-02, -1.828773307329849166920408764650763092868965221608724574218473e-01, -4.683823374455167616514752420549419665215987106243491879971921e-02, 1.346275679102260877490923315484152662987698625205479167761416e-01, 3.447863127509970524678534595639646616244376966117385829345554e-02, -9.768535580565244174963692133038973587005628990493154911133358e-02, -1.734192283130589908795581592406238282930530566316914040035812e-02, 6.774789550190933956165341752699717255041141690153626336867769e-02, 3.448018955540951137600471926079622335842207388713342609755316e-03, -4.333336861608628393863254980828284403766309203453808666888800e-02, 4.431732910062988320487418656322338284504389482966303454010563e-03, 2.468806001015186586264188361362046240243934625858343309818244e-02, -6.815549764552309639259447104811254179605050667281644254737890e-03, -1.206359196821849005842466619530619474644989878503490321948471e-02, 5.838816627748944864497370576838809711476027837762897602935327e-03, 4.784863112454241718009916669120329848973107781600157214960003e-03, -3.725461247074254799171427871442937099025589672466088044410521e-03, -1.360373845639692436577650137133777929659265166644839235882291e-03, 1.875998668202795626152766912508562385106168761893900192731562e-03, 1.415672393140464257573780581396205840941849282748250523509874e-04, -7.486749559114629991320679819683227355746847370960399216568306e-04, 1.154656063658921251969297916771881248142872975490882572741198e-04, 2.295790982233456202366621544054366855729175050420515776344878e-04, -8.903901490044488099517361247378396756893227855233897357882978e-05, -4.907713416190250858324783990436748073854807494400738311968278e-05, 3.641401211050802781223450761733180188911730291497201507086247e-05, 4.638664981394294654002871426476885751050837817671843706915388e-06, -1.004326041333422601781848560432120920634648692782357855473103e-05, 1.247900317574834146052381692752796047052443265982232422642017e-06, 1.840363734517769191684379309039277810350620305330900536404818e-06, -6.670215479954892588747450458085225880096882699397256774967304e-07, -1.757461173209842779903676264971918635870906983281392939812547e-07, 1.490660013535362170989340065033061951960933954388633507264360e-07, -8.262387315626556965966429243600984899650039704831080988658278e-09, -1.784138690875710077191713941441263246560738410213624546116655e-08, 5.044047056383436444631252840057862002264087720676808580373667e-09, 6.944540328946226952976704718677697525410051405055662575530111e-10, -6.077041247229010224760245305596307803830053533836849384680534e-10, 8.492220011056382105461206077240377024404404638947591299761197e-11, 1.867367263783390418963879146175452376940453585791428841004699e-11, -8.365490471258800799349289794397908900767054085216008197372193e-12, 1.188850533405901520842321749021089497203940688882364518455403e-12, -6.367772354714857335632692092267254266368934590973693820942617e-14}); WaveletData const Daubechies29({3.318966279841524761813546359818075441349169975922439988843475e-05, 6.409516803044434540833706729120596322083061716935004987374676e-04, 5.702126517773375434760843998623507494914551464968126455168657e-03, 3.077358022140837676716707336516751814713312018344719150923618e-02, 1.113701169517405304762186166370327770191325772342190715118617e-01, 2.806534559709829376968881262770480606500920092398534229615289e-01, 4.897588047621993143592705932993573539235839610055331620240518e-01, 5.513744327583751951223746071670135992466984391233429663886536e-01, 2.891052383358291634605691113586264061513180158354460952469246e-01, -1.540287344599000542466293779503370141731339982919280951230240e-01, -3.300409489175880520295083779487012611959310539629627124613719e-01, -5.570680007294085781514541931715795784309410235726214400350351e-02, 2.361052361530259415983110734054626770649468357328362426830433e-01, 1.124191748731883764769740670535880543076817816861518667898467e-01, -1.608779885941877360771615465531852333085159940159968393590303e-01, -1.078459499387214201077881957354707913786241153934264316589273e-01, 1.144722958938182579734135930060053286267822797640393386903440e-01, 8.322074716244975790297348835032537357891920536002627784941129e-02, -8.512549261563550232832311331420804581881235448862834507281486e-02, -5.502748952532572320924541450626650067707344725344841099873446e-02, 6.347916458421186633577789314698972361081611994794140119302163e-02, 3.053154327270413646637328212093941030592133225231728964047047e-02, -4.518798127778834515979704475304405691390090327474972089790857e-02, -1.291714255426679462966473962555410660387671182428076570686472e-02, 2.947043187174764111028122319949903667638786379520519899154373e-02, 2.648327307678167915542397563479749119673768286990136051577167e-03, -1.704122457360668969234196743407615179099529206118693044741086e-02, 1.737880332720511164430027824345354801611373419264590068097416e-03, 8.469725493560752287772961661104710791306496373354237126998903e-03, -2.550807127789472659145072247724735637183590942511858255354005e-03, -3.473798989681100630649790255076233970957721666820195620598374e-03, 1.877120925723650133179338154344873477230567340668548016358682e-03, 1.087053942226062966738944397844498417945523630053411148182206e-03, -1.000778327085680541055696707760062870925897014530348262794137e-03, -2.000711363076779808296301110796026470163110202848894744316755e-04, 4.111283454742767033424740543004041500054889660665367490129376e-04, -2.292018041214499897382298271438084577065170236103859181134525e-05, -1.293044840080720609161466939678226852440475312744714379499074e-04, 3.645026068562774967665464216602750761690984830805534178557146e-05, 2.913344750169041218495787251929571015775436967652945386217480e-05, -1.657328395306616289863396387854880512976861409870690029695161e-05, -3.593644804025187638066915189731950450034629392522542962477168e-06, 4.750609246452552850197117564759363194953518317428400241629683e-06, -3.029054592052818286474228294307141792053791695855058563299597e-07, -8.975701750636280734511651941681818767895052287332471537510510e-07, 2.633898386997696553900967704111473475368019612368922599394214e-07, 9.387197411095863026484410601284876812292554863800653292318725e-08, -6.286156922010786166768503252870590953166867739448102804392389e-08, 1.076591906619196137385201975028785139607670319821266803566785e-09, 7.768978854770062238895964639391324551611701293594055935346266e-09, -1.893995386171984147774611076618946011337498790609031626697228e-09, -3.426800863263089001811012278889864200550342566386405676893537e-10, 2.407099453509342962399811991929330725186626582891090462239366e-10, -2.940589250764532582888473974638273664244682541297835986306504e-11, -7.832509733627817032356556582819494794884131433810848844709881e-12, 3.152762413370310423797539876893861621418382024668704492620948e-12, -4.285654870068344101898185073376307686875386259541180967347399e-13, 2.219191311588302960934661700068023727737812918006011019184982e-14}); WaveletData const Daubechies30({2.338616172731421471474407279894891960011661146356580425400538e-05, 4.666379504285509336662000111055365140848987563882199035322085e-04, 4.300797165048069510045016757402827408493482974782286966500398e-03, 2.413083267158837895194919987958311943976725005113561262334092e-02, 9.123830406701570679321575555085899708564500191080751595642650e-02, 2.420206709402140994467599658342919512318194032687898436229538e-01, 4.504878218533178366981351802898336415314944375740699506554771e-01, 5.575722329128364304078082520999850413492571645754785374629734e-01, 3.662426833716279793144871151369089533016299234992584741629624e-01, -6.618367077593731501909741041813726474911212544474895441395148e-02, -3.329669750208556069196849320598850505877494561268613506392514e-01, -1.419685133300829310219026267403758254954270602825020111483505e-01, 1.994621215806643032428990062111230223523226088131364328774921e-01, 1.778298732448367361280250921330425046260289700971176750362566e-01, -1.145582194327077814891518778613672243404957549114393749173137e-01, -1.572368179599938126878197378886501553251711910617673398124611e-01, 7.277865897036442699893544326605244235248713804556715604416632e-02, 1.227477460450093778691578797698150091624353365248212907325446e-01, -5.380646545825707676022015051837304300338645984615639237930800e-02, -8.765869003638366048026572053699028353846982304851342479893827e-02, 4.380166467141773250305407710250135373016604593736480428415303e-02, 5.671236574473569492590636983030617493807140224924978946302257e-02, -3.567339749675960965780819743176056734137251336781389369397564e-02, -3.226375891935220815954913483392725682165778426411705216010280e-02, 2.707861959529418272206848318420006522973840949600186710327776e-02, 1.528796076985739546052896626042375110302102640936712142026221e-02, -1.839974386811734118728169880549148389603890445324127330811811e-02, -5.296859666131086629169938675330494864053932988161015674773617e-03, 1.091563165830488927536881480211929049886878831313700460017968e-02, 6.196717564977244383592534999284255315694546230739551683085460e-04, -5.530730148192003288871383856487027893918513053091795443517653e-03, 8.433845866620933982126003584365932145598126087481400294999080e-04, 2.324520094060099304385756339638431339131122661576649123053845e-03, -8.609276968110423879660725173525347077801305237644122054954659e-04, -7.678782504380918697963922441514742758516706160788123977340073e-04, 5.050948239033467796256544554086554367969638627715114003635557e-04, 1.724825842351709725545759714374272164367933578194910678479473e-04, -2.161718301169633804271038862087964094429005266172702380483361e-04, -8.548305467584070994787824796256108217987765582429940610377190e-06, 6.982008370808327851082027193100914402221658444151889697045071e-05, -1.339716863293971629296314599448901465078920406443516550195793e-05, -1.636152478725426488654528710478856195004608401773950511915162e-05, 7.252145535890469015723401169934327900622894130695550273452916e-06, 2.327549098493686509557358103785598216688723737824121617676858e-06, -2.187267676996166416699555236143059249832615777542412142603694e-06, 1.099474338526203304286307383463498542376432972308342428764576e-08, 4.261662326011572446469849114416378817419458434583398455985144e-07, -1.000414682354500898864979332965559934104686157639553850670490e-07, -4.764379965139453357729154748688006975561934425368712852985388e-08, 2.605442754977625431940885841950955928085338672381046225838880e-08, 5.553397861397053982967618072672572206490972606026556946910028e-10, -3.331105680467578245901976412732595596538702049437802824373020e-09, 6.984862691832182584221096665570313611280449991512869846064780e-10, 1.613622978270904360610418704685783656905979134344922647926295e-10, -9.461387997276802120884525814092001871993910062127702293573920e-11, 1.000105131393171192746337860330428369495110180346654025287492e-11, 3.239428638532286114355931428908079297696045600279108835760520e-12, -1.185237592101582328254231496310584611948560976394420324137742e-12, 1.543997570847620046003616417646988780670333040868954794039905e-13, -7.737942630954405708679963277418806436871098329050829841696327e-15}); WaveletData const Daubechies31({1.648013386456140748122177817418358316441195236228590958603489e-05, 3.394122037769956699157160165352942212213928231154233571163033e-04, 3.236884068627721221829662672296912258338131668810067169630813e-03, 1.885369161298591269159568944275763468999829139547989648553486e-02, 7.433609301164788697908776495388047669378919816041031344650271e-02, 2.070128744852353286198055444111916450619762837756134323019573e-01, 4.091922000374278563928213235836188963704298775635493549519369e-01, 5.511398409142754983590484577074663132074992263886810324421617e-01, 4.294688082061372955430413148799008354573408538414331312236645e-01, 2.716921249736946422305354732634261873401679092095992827198308e-02, -3.109551183195075186926560285811004715398678229333522634202008e-01, -2.179784855235633521693544507220105631639547435903112747133934e-01, 1.401782887652732681656253206993073895422881511380152633441096e-01, 2.249667114737370933697297905066886078307490136415302624018330e-01, -4.992634916046823977000579399730138693074543903234092797936484e-02, -1.869623608957154494374577196258383009208655076187653847079167e-01, 1.543698842948893409652995335281236231845293548571166883219023e-02, 1.450895009319931981518942907854879059128872873116921504156674e-01, -8.139832273469236863527708715566588550006680549152344840146851e-03, -1.076127733234956326668605511648013952380301953590447106075614e-01, 1.094129745236496925725237900637802669504835743555466811796369e-02, 7.535361174328140695528289751109133941376701984419452638686226e-02, -1.488002661810482202699555987503429289100801979910046913257306e-02, -4.861907546485433003537603385831190109391263542044516048871113e-02, 1.615417156598591113619453864586701665635869166193865651960591e-02, 2.804761936675616906861927211659154977049392281479113764697785e-02, -1.427627527776351943309800140756746087215016194775579070599004e-02, -1.390055293926652880755898888934447671732373519028670201124816e-02, 1.051763948737184089128633441244991643331033825102031908858652e-02, 5.516163573310992566561289762241160214476622662764637181816550e-03, -6.520852375874612553325469682628530079210293774541131381751695e-03, -1.428264223218909891400516038687842292177211292295049238921068e-03, 3.393066776715931928419358796960612411097347419792355896915546e-03, -6.397901106014600492881202314307290077992972755016494062875201e-05, -1.459041741985160943114515221598080223845239255190055621901681e-03, 3.431398296904734438118401084929505912208229684629857530009147e-04, 4.998816175637222614896912406679513231966722440032799024979502e-04, -2.396583469402949615285646688069476140260781708006174912535660e-04, -1.243411617250228669409179807383399199879641177993453588807726e-04, 1.089584350416766882738651833752634206358441308880869184416670e-04, 1.501335727444532997071651937630983442758297688087711521441229e-05, -3.631255157860086164261313773172162991107348698083164489165837e-05, 4.034520235184278839752741499546098778993926344831736074409765e-06, 8.795301342692987765440618030678349427367022581211855857458220e-06, -3.035142365891509630069007852947057220760887215249503512783023e-06, -1.369060230942940782050489751987123955074404782177163471279285e-06, 9.810015422044371573950976088058064384946146188110905321673802e-07, 5.327250656974915426977440959783080593776012130063170688309127e-08, -1.975925129170206248152121156696590501303803187231928513867046e-07, 3.616826517331004805247567218405798591329788122337274956172315e-08, 2.328309713821409644308538888589329921141948539678106680777082e-08, -1.061529602150252306500404266150823962402673780484965538270541e-08, -6.474311687959861398702581539341954438747926255671605657095807e-10, 1.408568151025177427076547804944585301332087108125727813194374e-09, -2.524043954153353306183643702933218308617979467184848456565837e-10, -7.348930032486263904766913919653624379586487437915175106407348e-11, 3.692108808871129411604189196259677640440919369478263728899602e-11, -3.327008967125979929910636246337150851642079794871116041187279e-12, -1.324334917243963163878274345609465717294426628053460151843705e-12, 4.445467096291932163298411852093011459626037560439178917611592e-13, -5.559442050579014337641375730083534521513818164827556763756543e-14, 2.699382879762665647295493928801387173921314576598505507855504e-15}); WaveletData const Daubechies32({1.161463302135014885567464100760659332951431420121048996305591e-05, 2.466566906380903352739104211274667134470169443886449124673996e-04, 2.431261919572266100780423071905958127811969678055971488060574e-03, 1.468104638141913563547809006402194831107662001343421893488086e-02, 6.025749912033537081745451975527967031851677384078997261920024e-02, 1.757507836394388988189299915753348505208376399651864661397588e-01, 3.675096285973496361995340339143234125206079560406868595968025e-01, 5.343179193409538322901117858552186425529774700290587495921679e-01, 4.778091637339484033555130814414794130354053753675509287934741e-01, 1.206305382656178269538098710665261299391507308342013788891222e-01, -2.666981814766755535489784087869865024226542605534080371507405e-01, -2.774215815584272153338153320303401666681294506143291967655666e-01, 6.471335480551623831000090095167664918448659157720155321560811e-02, 2.483106423568801736064852157222867588791898170114101300999760e-01, 2.466244483969740441701479334808723214802614938081258920635302e-02, -1.921023447085468984341365278247990525863123891147783426068990e-01, -4.899511718467173853355943225576377418394280156945986899417475e-02, 1.452320794752866460838830744051944832326998342053148426312341e-01, 4.440490819993974022640619534046603571086531544468421519143629e-02, -1.094561131160893831027722774343269232755171130623890041619420e-01, -2.962787250844770491204452379051215505049068645551070779367843e-02, 8.087414063848395744090831590426327690818854671836423275412813e-02, 1.410615151610660772869738802931740150275269382463799031013905e-02, -5.692631406247843550478416271158537960555270097953330567652364e-02, -2.380264464932573834443178362086503847328134994591954135879789e-03, 3.705145792354468010437633458013030898015496905609424004450953e-02, -4.145907660827218781460700428862611061267328108653649653634276e-03, -2.166282283639119347634778516947485598599029367518033869601702e-02, 6.167527310685675112579059689520105004744367282412921739811164e-03, 1.101740071540688116532806119564345712473051769079712407908648e-02, -5.411568257275791208581502410752383050600045942275647685361370e-03, -4.649216751184411528658094984504900172989190128905887602541396e-03, 3.627224640687864960122122984391704782343548385375321260251988e-03, 1.468955100468467772528811782840480639166582822577191079260543e-03, -1.964740555821778254183647540656746450092725858126595984907304e-03, -2.211678729579097916278097586914956834196749138610403102772710e-04, 8.673058518450555343925662389563539890596549655683386287799624e-04, -1.024537310607396186949656796812972062290796122915930356634122e-04, -3.059654423826911750479261161552574500739091332121504634422577e-04, 1.053915461739828114700905192091104141076083602686374410146603e-04, 8.103678329134838389828091896334156224227821362491626044950428e-05, -5.259809282684322782648914338377962890245975842272425408122506e-05, -1.294045779405512723950480259110995722517019870286295908085366e-05, 1.824268401980691220603850117995712615809177092802967489081228e-05, -6.361781532260254953363913076575914206506177493714496098327288e-07, -4.558309576264423135123964145585288808181431652781253437738445e-06, 1.202889036321620990296134494079846952404216422923750605507047e-06, 7.560047625595947819392627283726711361273296630256477108501994e-07, -4.285970693151457255418342315045357407199066350632593899896712e-07, -5.003361868748230293692887222336390314786090450819216035110269e-08, 8.965966311957728376981484572655177545054433542721057470726361e-08, -1.219924359483373093110396748985081720383992859961285213840740e-08, -1.104383021722648979552131128575075255513372249283096583736746e-08, 4.250422311980592983740943309197245384991941251563471671065543e-09, 4.384387799940474369553236949848427579687147486892033587998023e-10, -5.881091462634605628881794361152305108432139465417759716875076e-10, 8.904723796221605490455387579189371137903330749397374037644960e-11, 3.263270741332907875981844980104948375955551273115386408552080e-11, -1.430918765169202320188022211739750594608742928641485026836608e-11, 1.075610653501062115165734990153347111902874668945095034791947e-12, 5.361482229611801638107331379599434078296259332654994508124989e-13, -1.663800489433402369889818192962259823988673359967722467427927e-13, 2.000715303810524954375796020597627467104635766752154321244151e-14, -9.421019139535078421314655362291088223782497046057523323473331e-16}); WaveletData const Daubechies33({8.186358314175091939858945975190102731733968885547217619434602e-06, 1.791016153702791479424389068736094134247294413108336017758506e-04, 1.822709435164084208084617771787691709255513374281497713580568e-03, 1.139594337458160925830840619716397130445853638888472948832932e-02, 4.861466653171619508385707681587366397164931431125053574327899e-02, 1.481863131800528081784673514426737436792606299953305691300616e-01, 3.267181301177075783930752787756046348844272437670999719562429e-01, 5.093761725149396552227892926384090200953139820961482931291482e-01, 5.112547705832674655425831875568453973369927971748064975152374e-01, 2.095823507130554216526494469993023406452629154801126958766008e-01, -2.042026223985421049629055102642279430174095014493415546881477e-01, -3.159974107665602561905181464284910961862968513875028980451424e-01, -1.927833943695275915600583425408664108893845271616240406358226e-02, 2.454206121192791114179964351253140999836791489738418857473689e-01, 9.985155868033815698139640215477639365289384281516885362929979e-02, -1.714280990518593279308738113273443832545615219650436927029674e-01, -1.108441331167107910806084983056783194189909198734302929909672e-01, 1.219678564037346149389134584371009777591763921148126952722200e-01, 9.478808805061595889263191779090571160237408179346345390888721e-02, -9.114696835133148913093153757138373418923462847746880902676089e-02, -7.030248505405615921453280814171665167171986608963193275084895e-02, 7.019114394099653254998935842432841393915841096633514680190145e-02, 4.573456189389667743139040427641638967843459421665709740086516e-02, -5.347125133582228919431110824663168583260050383336359554980188e-02, -2.524858297747649929258392207837724793937727346177294684700378e-02, 3.868706076024496481748675031852528047303323816250150793091832e-02, 1.070326582001954942654534968137727769698168853186071888736311e-02, -2.572876175473297336123211392278301875687760837710204579628265e-02, -2.167758617353607324783298657172830203896433848418061622436727e-03, 1.531695411585766548347442266431874060229304787191589430967538e-02, -1.594288782414604768637856446111392724059836934455189837500244e-03, -7.953540387057939240459305406538116220678495240302592677582773e-03, 2.389062408165908575935815973439728988151836094753689966108405e-03, 3.480800953405711999411461002429227385937942254778524257436278e-03, -1.860718214455795912074482150710567824317228203897000129729967e-03, -1.204309257604658876916644980097327372892008586047095719636829e-03, 1.074380696351291355073899234941719080473877020595209197706651e-03, 2.727305847336937211749282358350196461733595290569540045817329e-04, -4.908329007590351474487792254066540683724948757382104652497458e-04, 4.393166251766185755059005296958129844094063524324718175254673e-06, 1.780431898251245351831728023200069586928513661382622116969992e-04, -4.160438516273709306234368807933932360567787692918883118883736e-05, -4.929564423417301834310231482621574127409950921583062559483686e-05, 2.423335398816890365621188379922041046073808819182024026589770e-05, 9.070805757828453800203677464921508178468256685438211818575040e-06, -8.866121366757736169176034432364298134186929098274651022820760e-06, -3.607516102879771631230351118595069330196155459105589342866625e-07, 2.288371276141527305481395545993763010565968667577768164201792e-06, -4.426923407952870147984002129341809185622768353983550670755106e-07, -3.985791291985944076942626511739220753169387460984290019185514e-07, 1.822443332571053437467128998002798233969112236553215291639303e-07, 3.377972703730854377516206663481869099376154259897212784144779e-08, -3.987838198518880722819502850814936369197384392561970319349663e-08, 3.672863576838181340505563759379169099717712645283448779390320e-09, 5.111211857347453839549366593998758891130921028374576213256027e-09, -1.671392677251932495173219614104411841891545601521784559793012e-09, -2.496402105246193648073519269370197331176405371538404298745013e-10, 2.426833102305682309891302883361232297664099485514601790344279e-10, -3.049574453945863430361296931455141500128170151643206937547928e-11, -1.420236859889936792437077844940412749343225644487770840543290e-11, 5.509414720765524548752673631197714447818740985929081064907524e-12, -3.343481218953278765982532722689984725170758193566174566492199e-13, -2.152488386833302618520603545685994753329478275805993737095214e-13, 6.214740247174398315576214699577230693021307854673557214652751e-14, -7.196510545363322414033654470779070592316600780697558361083151e-15, 3.289373678416306368625564108782095644036415401902518812978798e-16}); WaveletData const Daubechies34({5.770510632730285627466067796809329117324708919047900817738025e-06, 1.299476200679530037833484815390569400369432658207722720405084e-04, 1.364061390059049998200014449396877439591680435610837369411339e-03, 8.819889403884978803182764563095879335330977939541630862804757e-03, 3.904884135178594138905026219591569204043816577941517019631916e-02, 1.241524821113768081954449898210969172708199672428635378051285e-01, 2.877650592337145629334256618087718872558560120999651277991839e-01, 4.784787462793710621468610706120519466268010329031345843336104e-01, 5.305550996564631773133260223990794445605699030503652382795600e-01, 2.903663295072749510455945186199530115755664977934564128822650e-01, -1.282468421744371672912377747048558427612774932943748628650824e-01, -3.315253015083869417715548463087537345035828886426345397256876e-01, -1.038919155156404718287260506925867970596448618647006698388596e-01, 2.169072201874275950610018667099322465619408030256534197819784e-01, 1.666017504122074437311574334509261366682993700573488534577890e-01, -1.273373582238011562843862636988693890108793629966541695807247e-01, -1.609249271778668063014799490429649196614628857267382976958607e-01, 7.799184693794810738265349531832015087096882277333968473726399e-02, 1.341259602711361284802399913977387999358280900708582462625539e-01, -5.448296806413904636632671383140642554265865948686157271017286e-02, -1.029475969928140852342073823689090498245496056845473569066667e-01, 4.357609464963129726428486610925800727137724136370669421246609e-02, 7.318523543679560555546221335452045680757998947493883124934567e-02, -3.701283841786244960356402125554190040750079009127461655784927e-02, -4.743855964527776247220681410983851377889756018716427358008296e-02, 3.073974657395934459931226513844134346305562928466993208164603e-02, 2.722835075635419610095839895805858855202745897718117731496534e-02, -2.367173792282636485046786438094940427456079528043555566867110e-02, -1.314398001665716086105827506126287041342680578404007359439612e-02, 1.640937419986519252112261495537409592363156309874473310057471e-02, 4.713649260999809905918876125437488856235874027077755004539205e-03, -1.004550670836151917439146861146431000364858401181337134891421e-02, -6.194748845153872839014356621835501857322345445234809347431098e-04, 5.334950768759936032170270195983921511565539100791906952901398e-03, -7.692127975067836975989490900561029844887285335804349474993607e-04, -2.399453943537055863933124827688081952701780599883067560501870e-03, 8.589959874363661955444898475746536583497522107459291718900058e-04, 8.751999064078688732610570055224339733760304773327228476255647e-04, -5.527355762144197975516415296735124460550632283763688359649888e-04, -2.326732140233531635428863212833942245597361085708567528230733e-04, 2.650772397558057819755811309071002543822145660933016957735937e-04, 2.660050018453441903046828468025589086403126180798464347801678e-05, -9.914697770780134603580350758869378471802751837608461971022567e-05, 1.353117227249649581251887376414486225127346352042209141315562e-05, 2.844951419697807376503080001943765930601242225183893658540032e-05, -1.057657494257950623848316304755218120233253479317574337409622e-05, -5.710826510998303938275050074333400305512451419983646591762318e-06, 4.169871758547028398316761659984928804362023643629741358799744e-06, 4.979718101421307748081857636471761057429219265531618602960147e-07, -1.116306534817008428597995070751765080383261658112656948526954e-06, 1.448195708333185127061180618150009526758658641231104901703561e-07, 2.025990666667859216690536885693725545344933235432307649205497e-07, -7.526701740412589411177481797841044281662555785969415398369019e-08, -1.990346501531736915866180448337614967570744211158241514589121e-08, 1.740423332936068076497051274445147160190783847854409836489662e-08, -8.665744261368722215864741166245385888818567571145958531936939e-10, -2.316501946995482751582294240136010067415084499025753117941001e-09, 6.446378210323402313101214894500231181606520211579581132442548e-10, 1.300410318609415248880403259300467720631189120978928377152233e-10, -9.904774537632409015479530333979124540183199174591377762845227e-11, 1.004208735461769864836516428998306778031143650101842361622330e-11, 6.080125354000167254059025929915591291115751734288584563131636e-12, -2.107879108915301546285370395443778864676275235126044599683271e-12, 9.799451158211597727901178520526388692140586041163624252991805e-14, 8.579194051799733179793112298652600511486581216528683482143106e-14, -2.317083703906408481078257081903089523234020423092175261925515e-14, 2.587338381935699555813538163144986688834142571207152879144731e-15, -1.148944754480590128244815794312606245147888158018823490936280e-16}); WaveletData const Daubechies35({4.067934061148559026665247110206084571051201477121972612218005e-06, 9.421469475576740631603027533116630224451049736050903361458759e-05, 1.019122680375098109319314672751485080202557607467199213778085e-03, 6.807292884319132011971333979015625113494050642797397817625326e-03, 3.123628851149071453063391210769353068187088999495893257051179e-02, 1.034044558614783789938787754929279183985553322796063517049140e-01, 2.513073789944933128513251971488905042866779761014740192816902e-01, 4.435927392240354378183910489448494594782039032807956294826105e-01, 5.370084275091661028670690231716974547580034932361053607723887e-01, 3.603456405180473278744458573988718422538114217890792270621563e-01, -4.388388187393404111343479394097224312100349011932028865098625e-02, -3.238228649121161212147302807993176715625480327235512530593160e-01, -1.817869767667278325788350264528191676841493369460849123538616e-01, 1.660413574907809195438433327470947940538097914525298064477785e-01, 2.172992893210892977675493456199559114036326358517672106972956e-01, -6.526287131067753892154895911331108284007380738865652420304233e-02, -1.919195892985939528760786800798636198516495957924798820500876e-01, 1.930954466601835091947734585938109944647435243484967057775110e-02, 1.552924803962371144206753760712566993987319378965231186477630e-01, -4.752680834111350445288110998030979143710864689041902167119118e-03, -1.205855226433935545076589480704957722635324456812322150437989e-01, 4.734229172641948763293980314992213293971770695480616789828384e-03, 8.991354757072954417865374195261962983644048998218233900481856e-02, -9.318558949903924837875002823617504227246562152671894579504378e-03, -6.335603744044346612098887534020545705731671718057964802006671e-02, 1.322854958503655524455929847605110719648746890497356808289302e-02, 4.125469306470509212749750814299126656151504805845417994651417e-02, -1.436683978422007182104025173214012797788904894291716373493525e-02, -2.416949780166026740294880681731084091264533168816746227537030e-02, 1.276645671565674419403918018742432714973656598227939824940035e-02, 1.228943600811871086161967625814297050611100200023898377949151e-02, -9.577797899235709998147309703713518608283233882793489733491642e-03, -5.085991649233429881797636583578921194675393807761154549733547e-03, 6.137754586740521089596801883631921221145712545042519987641234e-03, 1.428088794070762107355585870669842132609159040625895090070111e-03, -3.357644380922383229567732565298665639037348585961127075507937e-03, 7.615969435172736546769649923895317451534703066016116257300160e-06, 1.549637469702362975561719246539787717204438637997824935787688e-03, -3.346692164250854961608526121524596908041109918361306282201310e-04, -5.864810318991817532175809224131456738367101035694188223408841e-04, 2.648328819961289039302810122699710966048565368047575218693134e-04, 1.700012283661249043584690194716767771204207742625746308522935e-04, -1.365883072261161602559926714744746422567509177443594045709653e-04, -2.976995962848509743944225866488519668585242655980656646544319e-05, 5.304143122913310222538317980686374696005605533475685587486683e-05, -2.437001526827789860990429478540556752694389693432668831073769e-06, -1.572442077270281693663288966405861215692805972737981986121447e-05, 4.308047861716731191350493437937513220737450410132878032163179e-06, 3.353345862871309889390877168046133657377105681618708355266688e-06, -1.895929617693153288493891051875444439753318548105998166574535e-06, -3.903931733287306166657519468494511920760767388397825775326745e-07, 5.302368616904760917074352633915743250769600635829229600812520e-07, -3.700308378205124537986402644918879149894035910106489082512364e-08, -9.990396944534900755781728477561240762191443422318249128866740e-08, 3.008188650719066928230268918661718274504955045022550217051301e-08, 1.084902733789934825266560240100449884702749303326571747323086e-08, -7.458116552893037631192407611262788593505988638365840409367117e-09, 5.897951310384361575470355861162022501172491937837712969865619e-11, 1.030823345485433383811700481488557422005210168069163779730908e-09, -2.433545573751672936168877250405940817227367937230289801251648e-10, -6.407938256501889018430608323235974406219193176918284664973727e-11, 4.000536627253744510742788201354093006471710416671002244302586e-11, -3.125639357108557540598098228678150768528121565391376265627294e-12, -2.567065476155081449204643852428401530283519685638256074752850e-12, 8.015088533687900921948605418789324826115616416343391081288979e-13, -2.597954328893848084315198205094389145706680129208998638802995e-14, -3.397720856796267431956783825659069596940335130100871912329556e-14, 8.624037434720089202680337663692777682810714650060805832406135e-15, -9.298012529324185420921555664719863501848315099116725184370339e-16, 4.014628712333488654318569164614220308046021091178184654250982e-17}); WaveletData const Daubechies36({2.867925182755946334630479473029238615535511775894262711054705e-06, 6.826028678546358691748629102209605362240344266505035981791715e-05, 7.602151099668488285869792677106082100141275054892389379198545e-04, 5.240297377409884366201603524392995696042174937194435235003941e-03, 2.489056564482796484885927333959115579403023347044729739255255e-02, 8.565209259526409083864716995521111486437594750377856524772704e-02, 2.177569530979008149637945915719999746248969705650625533415876e-01, 4.064336977082553467407793990250384445903151630768558142125382e-01, 5.322668952607286914777444748641462027213554723153906901129337e-01, 4.178753356009697863620634559374236455222275302996931178265919e-01, 4.397519752934862993862182898358763783110745559238982179690132e-02, -2.944210395891145711100715969898758940722458887377844633443675e-01, -2.468070369781255270524798278622698446566520718230313889086016e-01, 9.811420416311477050518401371401568038943437322299913514049728e-02, 2.465372776089742110529709111809595434656418762898152706621356e-01, 7.278515095792229009687682299460382878643139026668958884429641e-03, -1.993372056086496198603363400094784142714162256792182570541036e-01, -4.586140074639271639145126228774831743002971373998329604574394e-02, 1.541062366276428841776316300420654875883842819413623395358262e-01, 5.027618007353842862036816972809884096761706036019748316890913e-02, -1.188037543101356316801816931383547446073152951044444224449501e-01, -3.988085357551317584091699967924044034100374257075864260934102e-02, 9.115678225801654406336059281306715151058903055370522031843771e-02, 2.503872144956848989919484296709846860569180993040383621980546e-02, -6.820901663681751124880436344265538690580358108714540763125119e-02, -1.131910031681742794381808082173695022123056280821611354577883e-02, 4.851308354780908538616267662315735632292989749013261207046367e-02, 1.424972661765391603147802607378542396323429657660009755652404e-03, -3.198072067763969654470293513742344601172739688274251641873778e-02, 3.984040198717004857397179486790082321314291366656151213429068e-03, 1.906359478062535932877576164368198274858108513696832728889209e-02, -5.657813245058818380424016973516714570499161434975761798379020e-03, -9.990263473281372348001743806489172665465685056975652497503772e-03, 5.022989106665829004699819220796538830393945994687289792465541e-03, 4.413484835350575251918616780287775585471012556848037301025999e-03, -3.484541445404883311209541395428535732697661971818727286003028e-03, -1.503074066296643749549363655363411879858070202740814054964603e-03, 1.990793771851737270404293245701878186600899439513475823305914e-03, 2.776812795712026068152384207605140383490242756921936501940389e-04, -9.463403823261101964604918059447913047725482130063492242779878e-04, 8.614565758992702032613879159402330909634737204578606399403107e-05, 3.693507284967510502620040341882236687749563414433432842567511e-04, -1.155118895843527096848376999413102395191976350936666573818799e-04, -1.131899468084665671727391922924411467938450743565106978099456e-04, 6.694741196930590257104231749283786251555566773398199990337698e-05, 2.375106683660860777161950832380341362257503761490580896617678e-05, -2.731390824654337912922346414722045404779935825834384250023192e-05, -1.183471059985615942783182762352360917304348034947412986608322e-06, 8.372218198160788432628056043217491552198857358432112275253310e-06, -1.586145782434577495502614631566211839722879492827911790709498e-06, -1.870811602859180713762972281154953528056257451900381097476968e-06, 8.311421279707778528163597405935375886855029592150424544500718e-07, 2.548423522556577831218519052844387478819866531902854523544709e-07, -2.455377658434232699135878286794578515387138194247693201846263e-07, 2.753249073339512254085076456700241929492720457889076058451072e-09, 4.799043465450992009934526867650497683545716858606119786327559e-08, -1.156093688817008406756913949175208452083765368825442482226093e-08, -5.612784343327791397474114357094368557982413895802980814813369e-09, 3.138841695782424018351567952158415003571380699236147752239001e-09, 1.090815553713751810964713058800448676068475673611349566405716e-10, -4.512545778563249634425200856088490195004077806062978067796020e-10, 8.962418203859611987065968320295929679774693465791367610044773e-11, 3.037429098112535221800013609576297196061786927734556635696416e-11, -1.599716689261357143200396922409448515398648489795044468046420e-11, 8.876846287217374213524399682895564055949886050748321818411161e-13, 1.070969357114017002424433471621197579059927261727846375968378e-12, -3.029285026974877268896134589769473854669758797446795757329862e-13, 5.542263182639804235231685861028995158694397223907295269180336e-15, 1.338071386299105896025578761458472955294763310766371178363783e-14, -3.204628543401749860439316638848579711789176444320134355253750e-15, 3.339971984818693213132578777712503670014459411167839211495237e-16, -1.403274175373190617489823209168013922564353495443487431242610e-17}); WaveletData const Daubechies37({2.022060862498392121815038335333633351464174415618614893795880e-06, 4.942343750628132004714286117434454499485737947791397867195910e-05, 5.662418377066724013768394373249439163518654840493603575144737e-04, 4.024140368257286770702140124893772447952256842478891548092703e-03, 1.976228615387959153244055502205017461538589475705618414896893e-02, 7.058482597718160832030361890793007659963483925312132741868671e-02, 1.873263318620649448028843491747601576761901656888288838192023e-01, 3.684409724003061409445838616964941132670287724754729425204047e-01, 5.181670408556228873104519667534437205387109579265718071174178e-01, 4.622075536616057145505448401528172070050768534504278694229363e-01, 1.308789632330201726057701201017649601034381070893275586898075e-01, -2.461804297610834132869018581145720710365433914584680691693717e-01, -2.943759152626617722808219575932673733674290772235644691367427e-01, 1.967150045235938977077768648740052380288156507222647187301894e-02, 2.515232543602686933435224095078166291442923992611593827552710e-01, 8.180602838721862339029076982652411696000045533716726027662147e-02, -1.819622917786080007408824256525225216444443143868752611284260e-01, -1.084517138233017845554078812341876568514835176341639783558543e-01, 1.299296469598537527842528895259188653120602318620944502979726e-01, 1.017802968388141797470948228505865617480048287983176581607964e-01, -9.660754061668439030915405045955772715988585374771282291315496e-02, -8.233021190655740867404073660920379414988302492018783774702028e-02, 7.504761994836017933579005072594245435071674452882148228583865e-02, 5.956741087152995245435589042520108066877114768216272503684398e-02, -5.925681563265897095153806724965924334077555174281436189512239e-02, -3.825382947938424882011108885090442116802994193611884738133373e-02, 4.580794415126833246633256156110381805848138158784734496981778e-02, 2.097280059259754883313769469036393294461497749083921162354229e-02, -3.352358406410096994358662875913243067234786296009238949920582e-02, -8.833493890410232394064187990625563257107429109130726291528648e-03, 2.261865154459947356571431658958802912061105608212828675323452e-02, 1.690472383484423743663952859090705636512807161536954018400081e-03, -1.376398196289478433857985486097070339786225136728067000591187e-02, 1.519305778833399218481261844599507408563295102235964076544334e-03, 7.387757452855583640107787619408806919082115520707105052944171e-03, -2.248053187003824706127276829147166466869908326245810952521710e-03, -3.394523276408398601988475786247462646314228994098320665709345e-03, 1.816871343801423525477184531347879515909226877688306010517914e-03, 1.263934258117477182626760951047019242187910977671449470318766e-03, -1.111484865318630197259018233162929628309920117691177260742614e-03, -3.280788470880198419407186455190899535706232295554613820907245e-04, 5.490532773373631230219769273898345809368332716288071475378651e-04, 1.534439023195503211083338679106161291342621676983096723309776e-05, -2.208944032455493852493630802748509781675182699536797043565515e-04, 4.336726125945695214852398433524024058216834313839357806404424e-05, 7.055138782065465075838703109997365141906130284669094131032488e-05, -3.098662927619930052417611453170793938796310141219293329658062e-05, -1.639162496160583099236044020495877311072716199713679670940295e-05, 1.354327718416781810683349121150634031343717637827354228989989e-05, 1.849945003115590390789683032647334516600314304175482456338006e-06, -4.309941556597092389020622638271988877959028012481278949268461e-06, 4.854731396996411681769911684430785681028852413859386141424939e-07, 1.002121399297177629772998172241869405763288457224082581829033e-06, -3.494948603445727645895194867933547164628229076947330682199174e-07, -1.509885388671583553484927666148474078148724554849968758642331e-07, 1.109031232216439389999036327867142640916239658806376290861690e-07, 5.350657515461434290618742656970344024396382191417247602674540e-09, -2.252193836724805775389816424695618411834716065179297102428180e-08, 4.224485706362419268050011630338101126995607958955688879525896e-09, 2.793974465953982659829387370821677112004867350709951380622807e-09, -1.297205001469435139867686007585972538983682739297235604327668e-09, -1.031411129096974965677950646498153071722880698222864687038596e-10, 1.946164894082315021308714557636277980079559327508927751052218e-10, -3.203398244123241367987902201268363088933939831689591684670080e-11, -1.398415715537641487959551682557483348661602836709278513081908e-11, 6.334955440973913249611879065201632922100533284261000819747915e-12, -2.096363194234800541614775742755555713279549381264881030843258e-13, -4.421612409872105367333572734854401373201808896976552663098518e-13, 1.138052830921439682522395208295427884729893377395129205716662e-13, -4.518889607463726394454509623712773172513778367070839294449849e-16, -5.243025691884205832260354503748325334301994904062750850180233e-15, 1.189012387508252879928637969242590755033933791160383262132698e-15, -1.199280335852879554967035114674445327319437557227036460257649e-16, 4.906615064935203694857690087429901193139905690549533773201453e-18}); WaveletData const Daubechies38({1.425776641674131672055420247567865803211784397464191115245081e-06, 3.576251994264023012742569014888876217958307227940126418281357e-05, 4.211702664727116432247014444906469155300573201130549739553848e-04, 3.083088119253751774288740090262741910177322520624582862578292e-03, 1.563724934757215617277490102724080070486270026632620664785632e-02, 5.788994361285925649727664279317241952513246287766481213301801e-02, 1.600719935641106973482800861166599685169395465055048951307626e-01, 3.307757814110146511493637534404611754800768677041577030757306e-01, 4.965911753117180976599171147718708939352414838951726087564419e-01, 4.933560785171007975728485346997317064969513623594359091115804e-01, 2.130505713555785138286743353458562451255624665951160445122307e-01, -1.828676677083358907975548507946239135218223185041410632924815e-01, -3.216756378089978628483471725406916361929841940528189059002548e-01, -6.226650604782432226643360160478765847565862101045597180310490e-02, 2.321259638353531085028708104285994998671615563662858079262996e-01, 1.499851196187170199586403453788927307298226028262603028635758e-01, -1.417956859730596216710053144522330276392591055375830654519080e-01, -1.599125651582443618288533214523534937804208844386102639177693e-01, 8.563812155615105741612217814369165313487129645536001850276987e-02, 1.414147340733826800884683119379170594092606174915755283496153e-01, -5.658645863072738145681787657843320646815509410635114234947902e-02, -1.147311707107443752394144019458942779715665489230169950201022e-01, 4.309589543304764288137871223616030624246568683595408792078602e-02, 8.720439826203975011910714164154456762073786124233088471855868e-02, -3.660510340287429567372071039506772372567938710943432838908247e-02, -6.176620870841315993604736705613246241897497782373337911398117e-02, 3.198987753153780630818381136366859026137035450576631134176875e-02, 4.005498110511594820952087086241114309038577379366732959648548e-02, -2.689149388089451438550851767715967313417890393287236700072071e-02, -2.311413402054931680856913553585621248925303865540203357180768e-02, 2.090464525565524340215982365351342094670261491526831672682244e-02, 1.129049727868596484270081487761544232851115891449843967151657e-02, -1.470188206539868213708986402816605045648481224662435114088245e-02, -4.131306656031089274123231103326745723188134548520938157995702e-03, 9.214785032197180512031534870181734003522861645903894504302286e-03, 5.625715748403532005741565594881148757066703437214522101740941e-04, -5.071314509218348093935061417505663002006821323958752649640329e-03, 7.169821821064019257784165364894915621888541496773370435889585e-04, 2.400697781890973183892306914082592143984140550210130139535193e-03, -8.448626665537775009068937851465856973251363010924003314643612e-04, -9.424614077227377964015942271780098283910230639908018778588910e-04, 5.810759750532863662020321063678196633409555706981476723988312e-04, 2.817639250380670746018048967535608190123523180612961062603672e-04, -3.031020460726611993600629020329784682496477106470427787747855e-04, -4.555682696668420274688683005987764360677217149927938344795290e-05, 1.262043350166170705382346537131817701361522387904917335958705e-04, -1.155409103833717192628479047983460953381959342642374175822863e-05, -4.175141648540397797296325065775711309197411926289412468280801e-05, 1.334176149921350382547503457286060922218070031330137601427324e-05, 1.037359184045599795632258335010065103524959844966094870217687e-05, -6.456730428469619160379910439617575420986972394137121953806236e-06, -1.550844350118602575853380148525912999401292473185534395740371e-06, 2.149960269939665207789548199790770596890252405076394885606038e-06, -8.487087586072593071869805266089426629606479876982221840833098e-08, -5.187733738874144426008474683378542368066310000602823096009187e-07, 1.396377545508355481227961581059961184519872502493462010264633e-07, 8.400351046895965526933587176781279507953080669259318722910523e-08, -4.884757937459286762082185411608763964041010392101914854918157e-08, -5.424274800287298511126684174854414928447521710664476410973981e-09, 1.034704539274858480924046490952803937328239537222908159451039e-08, -1.436329487795135706854539856979275911183628476521636251660849e-09, -1.349197753983448821850381770889786301246741304307934955997111e-09, 5.261132557357598494535766638772624572100332209198979659077082e-10, 6.732336490189308685740626964182623159759767536724844030164551e-11, -8.278256522538134727330692938158991115335384611795874767521731e-11, 1.101692934599454551150832622160224231280195362919498540913658e-11, 6.291537317039508581580913620859140835852886308989584198166174e-12, -2.484789237563642857043361214502760723611468591833262675852242e-12, 2.626496504065252070488282876470525379851429538389481576454618e-14, 1.808661236274530582267084846343959377085922019067808145635263e-13, -4.249817819571463006966616371554206572863122562744916796556474e-14, -4.563397162127373109101691643047923747796563449194075621854491e-16, 2.045099676788988907802272564402310095398641092819367167252952e-15, -4.405307042483461342449027139838301611006835285455050155842865e-16, 4.304596839558790016251867477122791508849697688058169053134463e-17, -1.716152451088744188732404281737964277713026087224248235541071e-18}); WaveletData const &daubechies_data(t_uint n) { WaveletData const *result = nullptr; switch(n) { case 1: result = &Daubechies1; break; case 2: result = &Daubechies2; break; case 3: result = &Daubechies3; break; case 4: result = &Daubechies4; break; case 5: result = &Daubechies5; break; case 6: result = &Daubechies6; break; case 7: result = &Daubechies7; break; case 8: result = &Daubechies8; break; case 9: result = &Daubechies9; break; case 10: result = &Daubechies10; break; case 11: result = &Daubechies11; break; case 12: result = &Daubechies12; break; case 13: result = &Daubechies13; break; case 14: result = &Daubechies14; break; case 15: result = &Daubechies15; break; case 16: result = &Daubechies16; break; case 17: result = &Daubechies17; break; case 18: result = &Daubechies18; break; case 19: result = &Daubechies19; break; case 20: result = &Daubechies20; break; case 21: result = &Daubechies21; break; case 22: result = &Daubechies22; break; case 23: result = &Daubechies23; break; case 24: result = &Daubechies24; break; case 25: result = &Daubechies25; break; case 26: result = &Daubechies26; break; case 27: result = &Daubechies27; break; case 28: result = &Daubechies28; break; case 29: result = &Daubechies29; break; case 30: result = &Daubechies30; break; case 31: result = &Daubechies31; break; case 32: result = &Daubechies32; break; case 33: result = &Daubechies33; break; case 34: result = &Daubechies34; break; case 35: result = &Daubechies35; break; case 36: result = &Daubechies36; break; case 37: result = &Daubechies37; break; case 38: result = &Daubechies38; break; default: throw std::out_of_range("Daubechies coefficient not implemented for given index"); break; } return *result; } } } sopt-2.0.0/cpp/sopt/wavelets/wavelet_data.h000066400000000000000000000022311277570055300207210ustar00rootroot00000000000000#ifndef SOPT_WAVELET_WAVELET_DATA_H #define SOPT_WAVELET_WAVELET_DATA_H #include "sopt/config.h" #include "sopt/types.h" #include "sopt/wavelets/innards.impl.h" namespace sopt { namespace wavelets { //! Holds wavelets coefficients struct WaveletData { //! Type of the underlying scalar typedef t_real t_scalar; //! Type of the underlying vector typedef Array t_vector; //! Wavelet coefficient per-se t_vector const coefficients; //! Holds filters for direct transform struct DirectFilter { //! Low-pass filter for direct transform t_vector low; //! High-pass filter for direct transform t_vector high; } const direct_filter; //! Holds filters for indirect transform struct { //! High-pass filter for direct transform t_vector low_even; t_vector low_odd; t_vector high_even; t_vector high_odd; } const indirect_filter; //! Constructs from initializers WaveletData(std::initializer_list const &coefs); //! Constructs from vector WaveletData(t_vector const &coefs); }; //! Factory function returning specific daubechie wavelet data WaveletData const &daubechies_data(t_uint); } } #endif sopt-2.0.0/cpp/sopt/wavelets/wavelets.cc000066400000000000000000000012541277570055300202550ustar00rootroot00000000000000#include "sopt/wavelets/wavelets.h" #include "sopt/config.h" #include #include "sopt/logging.h" namespace sopt { namespace wavelets { Wavelet factory(std::string name, t_uint nlevels) { if(name == "dirac" or name == "Dirac") { SOPT_MEDIUM_LOG("Creating Dirac Wavelet"); return Wavelet(daubechies_data(1), 0); } if(name.substr(0, 2) == "DB" or name.substr(0, 2) == "db") { std::istringstream sstr(name.substr(2, name.size() - 2)); t_uint l(0); sstr >> l; SOPT_MEDIUM_LOG("Creating Daubechies Wavelet {}, level {}", l, nlevels); return Wavelet(daubechies_data(l), nlevels); } // Unknown input wavelet throw std::exception(); } } } sopt-2.0.0/cpp/sopt/wavelets/wavelets.h000066400000000000000000000157211277570055300201230ustar00rootroot00000000000000#ifndef SOPT_WAVELETS_WAVELETS_H #define SOPT_WAVELETS_WAVELETS_H #include "sopt/config.h" #include "sopt/types.h" #include "sopt/wavelets/direct.h" #include "sopt/wavelets/indirect.h" #include "sopt/wavelets/wavelet_data.h" namespace sopt { namespace wavelets { // Advance declaration so we can define the subsequent friend function class Wavelet; //! \brief Creates a wavelet transform object Wavelet factory(std::string name = "DB1", t_uint nlevels = 1); //! Performs direct and indirect wavelet transforms class Wavelet : public WaveletData { friend Wavelet factory(std::string name, t_uint nlevels); protected: //! Should be called through factory function Wavelet(WaveletData const &c, t_uint nlevels) : WaveletData(c), levels_(nlevels) {} public: //! Destructor virtual ~Wavelet() {} // Temporary macros that checks constraints on input #define SOPT_WAVELET_MACRO_MULTIPLE(NAME) \ if((NAME.rows() == 1 or NAME.cols() == 1)) { \ if(NAME.size() % (1 << levels()) != 0) \ throw std::length_error("Size of " #NAME " must number a multiple of 2^levels or 1"); \ } else if(NAME.rows() != 1 and NAME.rows() % (1 << levels()) != 0) \ throw std::length_error("Rows of " #NAME " must number a multiple of 2^levels or 1"); \ else if(NAME.cols() % (1 << levels()) != 0) \ throw std::length_error("Columns of " #NAME " must number a multiple of 2^levels"); #define SOPT_WAVELET_MACRO_EQUAL_SIZE(A, B) \ if(A.rows() != B.rows() or A.cols() != B.cols()) \ A.derived().resize(B.rows(), B.cols()); \ if(A.rows() != B.rows() or A.cols() != B.cols()) \ throw std::length_error("Incorrect size for output matrix(or could not resize)") //! \brief Direct transform //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the number of levels. Can be a matrix (2d-transform) or a //! column vector (1-d transform). //! \return wavelet coefficients //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template auto direct(Eigen::ArrayBase const &signal) const -> decltype(direct_transform(signal, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(signal); return direct_transform(signal, levels(), *this); } //! \brief Direct transform //! \param[inout] coefficients: Output wavelet coefficients. Must be of the same size and type //! as the input. //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the number of levels. Can be a matrix (2d-transform) or a //! column vector //! (1-d transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template auto direct(Eigen::ArrayBase &coefficients, Eigen::ArrayBase const &signal) const -> decltype(direct_transform(coefficients, signal, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(signal); SOPT_WAVELET_MACRO_EQUAL_SIZE(coefficients, signal); return direct_transform(coefficients, signal, levels(), *this); } //! \brief Direct transform //! \param[inout] coefficients: Output wavelet coefficients. Must be of the same size and type //! as the input. //! \param[in] signal: computes wavelet coefficients for this signal. Its size must be a //! multiple of $2^l$ where $l$ is the number of levels. Can be a matrix (2d-transform) or a //! column vector //! (1-d transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. This version //! allows non-constant Eigen expressions to be passe on without the ugly `const_cast` of the //! cannonical approach. template auto direct(Eigen::ArrayBase &&coefficients, Eigen::ArrayBase const &signal) const -> decltype(direct_transform(coefficients, signal, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(signal); SOPT_WAVELET_MACRO_EQUAL_SIZE(coefficients, signal); return direct_transform(coefficients, signal, levels(), *this); } //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! transform). //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template auto indirect(Eigen::ArrayBase const &coefficients) const -> decltype(indirect_transform(coefficients, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(coefficients); return indirect_transform(coefficients, levels(), *this); } //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! \param[inout] signal: Reconstructed signal. Must be of the same size and type as the input. //! \details Supports 1 and 2 dimensional tranforms for real and complex data. template auto indirect(Eigen::ArrayBase const &coefficients, Eigen::ArrayBase &signal) const -> decltype(indirect_transform(coefficients, signal, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(coefficients); SOPT_WAVELET_MACRO_EQUAL_SIZE(signal, coefficients); return indirect_transform(coefficients, signal, levels(), *this); } //! \brief Indirect transform //! \param[in] coefficients: Input wavelet coefficients. Its size must be a multiple of $2^l$ //! where $l$ is the number of levels. Can be a matrix (2d-transform) or a column vector (1-d //! \param[inout] signal: Reconstructed signal. Must be of the same size and type as the input. //! \details Supports 1 and 2 dimensional tranforms for real and complex data. This version //! allows non-constant Eigen expressions to be passe on without the ugly `const_cast` of the //! cannonical approach. template auto indirect(Eigen::ArrayBase const &coeffs, Eigen::ArrayBase &&signal) const -> decltype(indirect_transform(coeffs, signal, 1, *this)) { SOPT_WAVELET_MACRO_MULTIPLE(coeffs); SOPT_WAVELET_MACRO_EQUAL_SIZE(signal, coeffs); return indirect_transform(coeffs, signal, levels(), *this); } #undef SOPT_WAVELET_MACRO_MULTIPLE #undef SOPT_WAVELET_MACRO_EQUAL_SIZE //! Number of levels over which to do transform t_uint levels() const { return levels_; } //! Sets number of levels over which to do transform void levels(t_uint l) { levels_ = l; } protected: //! Number of levels in the wavelet t_uint levels_; }; } } #endif sopt-2.0.0/cpp/sopt/wrapper.h000066400000000000000000000114441277570055300161150ustar00rootroot00000000000000#ifndef SOPT_WRAP #define SOPT_WRAP #include #include #include "sopt/config.h" #include "sopt/exception.h" #include "sopt/types.h" #include "sopt/maths.h" namespace sopt { namespace details { //! Expression referencing the result of a function call template class AppliedFunction : public Eigen::ReturnByValue> { public: typedef typename DERIVED::PlainObject PlainObject; typedef typename DERIVED::Index Index; AppliedFunction(FUNCTION const &func, DERIVED const &x, Index rows) : func(func), x(x), rows_(rows) {} AppliedFunction(FUNCTION const &func, DERIVED const &x) : func(func), x(x), rows_(x.rows()) {} AppliedFunction(AppliedFunction const &c) : func(c.func), x(c.x), rows_(c.rows_) {} AppliedFunction(AppliedFunction &&c) : func(std::move(c.func)), x(c.x), rows_(c.rows_) {} template void evalTo(DESTINATION &destination) const { func(destination, x); } Index rows() const { return rows_; } Index cols() const { return x.cols(); } private: FUNCTION const func; DERIVED const &x; Index const rows_; }; //! \brief Wraps an std::function to return an expression //! \details This makes writing the application of a function more beautiful on the eye. //! A function call `func(output, input)` can be made to look like `output = func(input)` or `output //! = func * input`. template class WrapFunction { public: //! Type of function wrapped here typedef OperatorFunction t_Function; //! Initializes the wrapper //! \param[in] func: function to wrap //! \param[in] sizes: three integer vector (a, b, c) //! if N is the size of the input, then (N * a) / b + c is the output //! b cannot be zero. WrapFunction(t_Function const &func, std::array sizes = {{1, 1, 0}}) : func(func), sizes_(sizes) { // cannot devide by zero assert(sizes_[1] != 0); } WrapFunction(WrapFunction const &c) : func(c.func), sizes_(c.sizes_) {} WrapFunction(WrapFunction const &&c) : func(std::move(c.func)), sizes_(std::move(c.sizes_)) {} void operator=(WrapFunction const &c) { func = c.func; sizes_ = c.sizes_; } void operator=(WrapFunction &&c) { func = std::move(c.func); sizes_ = std::move(c.sizes_); } //! Function application form template AppliedFunction> operator()(Eigen::ArrayBase const &x) const { return AppliedFunction>(func, x, rows(x)); } //! Multiplication application form template AppliedFunction> operator*(Eigen::ArrayBase const &x) const { return AppliedFunction>(func, x, rows(x)); } //! Function application form template AppliedFunction> operator()(Eigen::MatrixBase const &x) const { return AppliedFunction>(func, x, rows(x)); } //! Multiplication application form template AppliedFunction> operator*(Eigen::MatrixBase const &x) const { return AppliedFunction>(func, x, rows(x)); } //! \brief Defines relation-ship between input and output sizes //! \details An integer tuple (a, b, c) where, if N is the size of the input, then //! \f$(N * a) / b + c\f$ is the output. \f$b\f$ cannot be zero. //! In the simplest case where this objects wraps a square matrix, then the sizes are (1, 1, 0). //! If this objects wraps a rectangular matrix which halves the number of elements, then the //! sizes would be (1, 2, 0). std::array const &sizes() const { return sizes_; } //! Output vector size for a input with `xsize` elements template typename std::enable_if::value, T>::type rows(T xsize) const { auto const result = (static_cast(xsize) * sizes_[0]) / sizes_[1] + sizes_[2]; assert(result > 0); return static_cast(result); } protected: template t_uint rows(Eigen::DenseBase const &x) const { return rows(x.size()); } private: //! Reference function t_Function func; //! Ratio between input and output size std::array sizes_; }; //! Helper function to wrap functor into expression-able object template WrapFunction wrap(OperatorFunction const &func, std::array sizes = {{1, 1, 0}}) { return WrapFunction(func, sizes); } } } namespace Eigen { namespace internal { template struct traits> { typedef typename VECTOR::PlainObject ReturnType; }; } } #endif sopt-2.0.0/cpp/tests/000077500000000000000000000000001277570055300144355ustar00rootroot00000000000000sopt-2.0.0/cpp/tests/CMakeLists.txt000066400000000000000000000022101277570055300171700ustar00rootroot00000000000000if(logging) add_library(common_catch_main_object OBJECT "common_catch_main.cc") if(SPDLOG_INCLUDE_DIR) target_include_directories(common_catch_main_object SYSTEM PUBLIC ${SPDLOG_INCLUDE_DIR}) endif() if(CATCH_INCLUDE_DIR) target_include_directories(common_catch_main_object SYSTEM PUBLIC ${CATCH_INCLUDE_DIR}) endif() target_include_directories(common_catch_main_object PUBLIC "${PROJECT_BINARY_DIR}/include/" "${CMAKE_CURRENT_SOURCE_DIR}/.." ) add_dependencies(common_catch_main_object lookup_dependencies) endif() add_catch_test(wavelets LIBRARIES sopt) add_catch_test(sara LIBRARIES sopt) add_catch_test(maths LIBRARIES sopt) add_catch_test(wrapper LIBRARIES sopt) add_catch_test(conjugate_gradient LIBRARIES sopt) add_catch_test(linear_transform LIBRARIES sopt) add_catch_test(sdmm LIBRARIES sopt) add_catch_test(sdmm_warm_start LIBRARIES sopt) add_catch_test(proximal LIBRARIES sopt) add_catch_test_with_seed(seeded_proximal test_proximal 1449580491) add_catch_test(padmm LIBRARIES sopt) add_catch_test(padmm_warm_start LIBRARIES sopt) add_catch_test(reweighted LIBRARIES sopt) add_catch_test(power_method LIBRARIES sopt) sopt-2.0.0/cpp/tests/common_catch_main.cc000066400000000000000000000011011277570055300203730ustar00rootroot00000000000000#define CATCH_CONFIG_RUNNER #include "sopt/config.h" #include #include #include #include "sopt/logging.h" std::unique_ptr mersenne(new std::mt19937_64(0)); int main(int argc, char const *argv[]) { Catch::Session session; // There must be exactly once instance int returnCode = session.applyCommandLine(argc, argv); if(returnCode != 0) // Indicates a command line error return returnCode; mersenne.reset(new std::mt19937_64(session.configData().rngSeed)); sopt::logging::initialize(); return session.run(); } sopt-2.0.0/cpp/tests/conjugate_gradient.cc000066400000000000000000000025601277570055300206030ustar00rootroot00000000000000#include #include "catch.hpp" #include "sopt/conjugate_gradient.h" TEST_CASE("Conjugate gradient", "[cg]") { using namespace sopt; ConjugateGradient const cg(std::numeric_limits::max(), 1e-12); SECTION("Real valued") { auto const A = Image<>::Random(10, 10).eval(); auto const AtA = (A.transpose().matrix() * A.matrix()).eval(); auto const expected = Array<>::Random(A.rows()).eval(); auto const actual = cg(AtA, (A.transpose().matrix() * expected.matrix()).eval()); CHECK(actual.niters > 0); CHECK(actual.residual == Approx(0)); CAPTURE(actual.residual); CAPTURE((A.matrix() * actual.result).transpose()); CAPTURE(expected.transpose()); CHECK((A.matrix() * actual.result).isApprox(expected.matrix(), 1e-6)); } SECTION("Complex valued") { auto const A = Image::Random(10, 10).eval(); auto const AhA = (A.conjugate().transpose().matrix() * A.matrix()).eval(); auto const expected = Array::Random(A.rows()).eval(); auto const actual = cg(AhA, (A.conjugate().transpose().matrix() * expected.matrix()).eval()); CHECK(actual.niters > 0); CHECK(actual.residual == Approx(0)); CAPTURE(actual.residual); CAPTURE((A.matrix() * actual.result).transpose()); CAPTURE(expected.transpose()); CHECK((A.matrix() * actual.result).isApprox(expected.matrix(), 1e-6)); } } sopt-2.0.0/cpp/tests/linear_transform.cc000066400000000000000000000050251277570055300203130ustar00rootroot00000000000000#include #include #include #include "sopt/linear_transform.h" TEST_CASE("Linear Transforms", "[ops]") { using namespace sopt; typedef int SCALAR; typedef Array t_Vector; typedef Image t_Matrix; auto const N = 10; SECTION("Functions") { auto direct = [](t_Vector &out, t_Vector const &input) { out = input * 2 - 1; }; auto indirect = [](t_Vector &out, t_Vector const &input) { out = input * 4 - 1; }; t_Vector const x = t_Vector::Random(2 * N) * 5; auto op = sopt::linear_transform(direct, indirect); CHECK((op * x).eval().cols() == x.cols()); CHECK((op * x).eval().rows() == x.rows()); CHECK((op * x).cols() == x.cols()); CHECK((op * x).rows() == x.rows()); CHECK((op * x).matrix() == (2 * x - 1).matrix()); CHECK((op.adjoint() * x).matrix() == (4 * x - 1).matrix()); } SECTION("Matrix") { t_Matrix const L = t_Matrix::Random(N, N); t_Vector const x = t_Vector::Random(N) * 5; auto op = sopt::linear_transform(L.matrix()); CHECK((op * x.matrix()).eval().cols() == x.cols()); CHECK((op * x.matrix()).eval().rows() == x.rows()); CHECK((op * x.matrix()).cols() == x.cols()); CHECK((op * x.matrix()).rows() == x.rows()); CHECK(op * x.matrix() == L.matrix() * x.matrix()); CHECK(op.adjoint() * x.matrix() == L.conjugate().transpose().matrix() * x.matrix()); } SECTION("Rectangular matrix") { t_Matrix const L = t_Matrix::Random(N, 2 * N); t_Vector const x = t_Vector::Random(2 * N) * 5; auto op = sopt::linear_transform(L.matrix()); CHECK((op * x.matrix()).eval().cols() == 1); CHECK((op * x.matrix()).eval().rows() == N); CHECK((op * x.matrix()).cols() == 1); CHECK((op * x.matrix()).rows() == N); CHECK(op * x.matrix() == L.matrix() * x.matrix()); CHECK(op.adjoint() * x.head(N).matrix() == L.conjugate().transpose().matrix() * x.head(N).matrix()); } } TEST_CASE("Array of Linear transforms", "[ops]") { using namespace sopt; typedef int SCALAR; typedef Vector t_Vector; typedef Matrix t_Matrix; auto const N = 10; t_Vector const x = t_Vector::Random(N) * 5; std::vector Ls{t_Matrix::Random(N, N), t_Matrix::Random(N, N)}; std::vector> ops; for(auto const &matrix : Ls) ops.emplace_back(sopt::linear_transform(matrix)); for(decltype(Ls)::size_type i(0); i < ops.size(); ++i) { CHECK(ops[i] * x == Ls[i] * x); CHECK(ops[i].adjoint() * x == Ls[i].conjugate().transpose() * x); } } sopt-2.0.0/cpp/tests/maths.cc000066400000000000000000000136441277570055300160700ustar00rootroot00000000000000#include #include #include #include #include "sopt/maths.h" #include "sopt/relative_variation.h" #include "sopt/sampling.h" #include "sopt/types.h" TEST_CASE("Projector on positive quadrant", "[utility][project]") { using namespace sopt; SECTION("Real matrix") { Image<> input = Image<>::Ones(5, 5) + Image<>::Random(5, 5) * 0.55; input(1, 1) *= -1; input(3, 2) *= -1; auto const expr = positive_quadrant(input); CAPTURE(input); CAPTURE(expr); CHECK(expr(1, 1) == Approx(0)); CHECK(expr(3, 2) == Approx(0)); auto value = expr.eval(); CHECK(value(1, 1) == Approx(0)); CHECK(value(3, 2) == Approx(0)); value(1, 1) = input(1, 1); value(3, 2) = input(3, 2); CHECK(value.isApprox(input)); } SECTION("Complex matrix") { Image input = Image::Ones(5, 5) + Image::Random(5, 5) * 0.55; input.real()(1, 1) *= -1; input.real()(3, 2) *= -1; auto const expr = positive_quadrant(input); CAPTURE(input); CAPTURE(expr); CHECK(expr.imag().isApprox(Image<>::Zero(5, 5))); auto value = expr.eval(); CHECK(value.real()(1, 1) == Approx(0)); CHECK(value.real()(3, 2) == Approx(0)); value(1, 1) = input.real()(1, 1); value(3, 2) = input.real()(3, 2); CHECK(value.real().isApprox(input.real())); CHECK(value.imag().isApprox(0e0 * input.real())); } } TEST_CASE("Weighted l1 norm", "[utility][l1]") { sopt::Array<> weight(4); weight << 1, 2, 3, 4; SECTION("Real valued") { sopt::Array<> input(4); input << 5, -6, 7, -8; CHECK(sopt::l1_norm(input, weight) == Approx(5 + 12 + 21 + 32)); } SECTION("Complex valued") { sopt::t_complex const i(0, 1); sopt::Array input(4); input << 5. + 5. * i, 6. + 6. * i, 7. + 7. * i, 8. + 8. * i; CHECK(sopt::l1_norm(input, weight) == Approx(std::sqrt(2) * (5 + 12 + 21 + 32))); } } TEST_CASE("Soft threshhold", "[utility][threshhold]") { sopt::Array<> input(6); input << 1e1, 2e1, 3e1, 4e1, 1e4, 2e4; SECTION("Single-valued threshhold") { // check thresshold CHECK(sopt::soft_threshhold(input, 1.1e1)(0) == Approx(0)); CHECK(not(sopt::soft_threshhold(input, 1.1e1)(1) == Approx(0))); // check linearity auto a = sopt::soft_threshhold(input, 9e0)(0); auto b = sopt::soft_threshhold(input, 4.5e0)(0); auto c = sopt::soft_threshhold(input, 2.25e0)(0); CAPTURE(b - a); CAPTURE(c - b); CHECK((b - a) == Approx(2 * (c - b))); } SECTION("Multi-values threshhold") { using namespace sopt; Array<> threshhold(6); input[2] *= -1; threshhold << 1.1e1, 1.1e1, 1e0, 4.5, 2.25, 2.26; SECTION("Real input") { Array<> const actual = soft_threshhold(input, threshhold); CHECK(actual(0) == 0e0); CHECK(actual(1) == input(1) - threshhold(1)); CHECK(actual(2) == input(2) + threshhold(2)); CHECK(actual(3) == input(3) - threshhold(3)); CHECK_THROWS_AS(soft_threshhold(input, threshhold.head(2)), sopt::Exception); } SECTION("Complex input") { Array const actual = soft_threshhold(input.cast(), threshhold); CHECK(actual(0) == 0e0); CHECK(actual(1) == input(1) - threshhold(1)); CHECK(actual(2) == input(2) + threshhold(2)); CHECK(actual(3) == input(3) - threshhold(3)); CHECK_THROWS_AS(soft_threshhold(input, threshhold.head(2)), sopt::Exception); } } } TEST_CASE("Sampling", "[utility][sampling]") { typedef sopt::Vector t_Vector; t_Vector const input = t_Vector::Random(12); sopt::Sampling const sampling(12, {1, 3, 6, 5}); t_Vector down = t_Vector::Zero(4); sampling(down, input); CHECK(down.size() == 4); CHECK(down(0) == input(1)); CHECK(down(1) == input(3)); CHECK(down(2) == input(6)); CHECK(down(3) == input(5)); t_Vector up = t_Vector::Zero(input.size()); sampling.adjoint(up, down); CHECK(up(1) == input(1)); CHECK(up(3) == input(3)); CHECK(up(6) == input(6)); CHECK(up(5) == input(5)); up(1) = 0; up(3) = 0; up(6) = 0; up(5) = 0; CHECK(up == t_Vector::Zero(up.size())); } TEST_CASE("Relative variation", "[utility][convergence]") { sopt::RelativeVariation relvar(1e-8); sopt::Array<> input = sopt::Array<>::Random(6); CHECK(not relvar(input)); CHECK(relvar(input)); CHECK(relvar(input + relvar.epsilon() * 0.5 / 6. * sopt::Array<>::Random(6))); CHECK(not relvar(input + relvar.epsilon() * 1.1 * sopt::Array<>::Ones(6))); } TEST_CASE("Standard deviation", "[utility]") { sopt::Array input = sopt::Array::Random(6) + 1e0; sopt::t_complex mean = input.mean(); sopt::t_real stddev = 0e0; for(sopt::Vector<>::Index i(0); i < input.size(); ++i) stddev += std::real(std::conj(input(i) - mean) * (input(i) - mean)); stddev = std::sqrt(stddev) / std::sqrt(sopt::t_real(input.size())); CHECK(std::abs(sopt::standard_deviation(input) - stddev) < 1e-8); CHECK(std::abs(sopt::standard_deviation(input.matrix()) - stddev) < 1e-8); } // Checks type traits work static_assert(not sopt::details::HasValueType::value, ""); static_assert(not sopt::details::HasValueType>::value, ""); static_assert(sopt::details::HasValueType>::value, ""); static_assert(sopt::details::HasValueType::Scalar>::value, ""); static_assert(std::is_same::type, sopt::t_real>::value, ""); static_assert(std::is_same::type, sopt::t_real>::value, ""); static_assert(sopt::is_complex>::value, "Testing is_complex"); static_assert(sopt::is_complex>::value, "Testing is_complex"); static_assert(not sopt::is_complex::value, "Testing is_complex"); static_assert(not sopt::is_complex>::value, "Testing is_complex"); static_assert(not sopt::is_complex>>::value, "Testing is_complex"); sopt-2.0.0/cpp/tests/padmm.cc000066400000000000000000000106551277570055300160510ustar00rootroot00000000000000#include #include #include #include "sopt/imaging_padmm.h" #include "sopt/padmm.h" #include "sopt/proximal.h" #include "sopt/types.h" sopt::t_int random_integer(sopt::t_int min, sopt::t_int max) { extern std::unique_ptr mersenne; std::uniform_int_distribution uniform_dist(min, max); return uniform_dist(*mersenne); }; typedef sopt::t_real Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; auto const N = 5; TEST_CASE("Proximal ADMM with ||x - x0||_2 functions", "[padmm][integration]") { using namespace sopt; t_Vector const target0 = t_Vector::Random(N); t_Vector const target1 = t_Vector::Random(N) * 4; auto const g0 = proximal::translate(proximal::EuclidianNorm(), -target0); auto const g1 = proximal::translate(proximal::EuclidianNorm(), -target1); t_Matrix const mId = -t_Matrix::Identity(N, N); t_Vector const translation = t_Vector::Ones(N) * 5; auto const padmm = algorithm::ProximalADMM(g0, g1, t_Vector::Zero(N)) .Phi(mId) .itermax(3000) .gamma(0.01); auto const result = padmm(); t_Vector const segment = (target1 - target0).normalized(); t_real const alpha = (result.x - target0).transpose() * segment; CHECK((target1 - target0).transpose() * segment >= alpha); CHECK(alpha >= 0e0); CAPTURE(segment.transpose()); CAPTURE((result.x - target0).transpose()); CAPTURE((result.x - target1).transpose()); CHECK((result.x - target0 - alpha * segment).stableNorm() < 1e-8); } template struct is_imaging_proximal_ref : public std::is_same &, T> {}; TEST_CASE("Check type returned on setting variables") { // Yeah, could be static asserts using namespace sopt; using namespace sopt::algorithm; ImagingProximalADMM admm(Vector::Zero(0)); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::value); CHECK(is_imaging_proximal_ref::Zero(0)))>::value); typedef ConvergenceFunction ConvFunc; CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); typedef LinearTransform> LinTrans; CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); CHECK(is_imaging_proximal_ref()))>::value); } sopt-2.0.0/cpp/tests/padmm_warm_start.cc000066400000000000000000000037421277570055300203130ustar00rootroot00000000000000#include #include #include #include "sopt/padmm.h" #include "sopt/proximal.h" #include "sopt/types.h" typedef sopt::t_real Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; auto const N = 30; SCENARIO("ProximalADMM with warm start", "[padmm][integration]") { using namespace sopt; GIVEN("A ProximalADMM instance with its input") { t_Vector const target0 = t_Vector::Random(N); t_Vector const target1 = t_Vector::Random(N) * 4; auto const g0 = proximal::translate(proximal::EuclidianNorm(), -target0); auto const g1 = proximal::translate(proximal::EuclidianNorm(), -target1); t_Matrix const mId = -t_Matrix::Identity(N, N); auto convergence = [&target1, &target0](t_Vector const &x) -> bool { t_Vector const segment = (target1 - target0).normalized(); t_real const alpha = (x - target0).transpose() * segment; SOPT_TRACE(" {} {}", alpha, (x - target0 - alpha * segment).stableNorm()); return alpha >= 0e0 and (target1 - target0).transpose() * segment >= alpha and (x - target0 - alpha * segment).stableNorm() < 1e-8; }; auto padmm = algorithm::ProximalADMM(g0, g1, t_Vector::Zero(N)) .Phi(mId) .itermax(3000) .gamma(0.5) .is_converged(convergence); WHEN("the algorithms runs") { auto const full = padmm(); THEN("it converges") { CHECK(full.niters > 20); CHECK(full.good); } WHEN("It is set to stop before convergence") { auto const first_half = padmm.itermax(full.niters - 5)(); THEN("It is not converged") { CHECK(not first_half.good); } WHEN("A warm restart is attempted") { auto const second_half = padmm.itermax(5000)(first_half); THEN("The warm restart is validated by the fast convergence") { CHECK(second_half.niters < 10); } } } } } } sopt-2.0.0/cpp/tests/power_method.cc000066400000000000000000000027151277570055300174450ustar00rootroot00000000000000#include #include #include #include "catch.hpp" #include "sopt/power_method.h" TEST_CASE("Power Method") { using namespace sopt; typedef t_real Scalar; auto const N = 10; Eigen::EigenSolver> es; Matrix A = Matrix::Random(N, N); es.compute(A.adjoint() * A, true); auto const eigenvalues = es.eigenvalues(); auto const eigenvectors = es.eigenvectors(); Eigen::DenseIndex index; (eigenvalues.transpose() * eigenvalues).real().maxCoeff(&index); auto const eigenvalue = eigenvalues(index); Vector const eigenvector = eigenvectors.col(index); // Create input vector close to solution Vector const input = eigenvector * 1e-4 + Vector::Random(N); auto const pm = algorithm::PowerMethod().tolerance(1e-12); SECTION("AtA") { auto const lt = linear_transform(A.cast()); auto const result = pm.AtA(lt, input); CHECK(result.good); CAPTURE(eigenvalue); CAPTURE(result.magnitude); CAPTURE(result.eigenvector.transpose() * eigenvector); CHECK(std::abs(result.magnitude - std::abs(eigenvalue)) < 1e-8); } SECTION("A") { auto const result = pm((A.adjoint() * A).cast(), input); CHECK(result.good); CAPTURE(eigenvalue); CAPTURE(result.magnitude); CAPTURE(result.eigenvector.transpose() * eigenvector); CHECK(std::abs(result.magnitude - std::abs(eigenvalue)) < 1e-8); } } sopt-2.0.0/cpp/tests/proximal.cc000066400000000000000000000243361277570055300166070ustar00rootroot00000000000000#include #include #include #include #include "sopt/l1_proximal.h" #include "sopt/proximal.h" #include "sopt/types.h" template sopt::Matrix concatenated_permutations(sopt::t_uint i, sopt::t_uint j) { extern std::unique_ptr mersenne; std::vector cols(j); std::iota(cols.begin(), cols.end(), 0); std::shuffle(cols.begin(), cols.end(), *mersenne); assert(j % i == 0); auto const N = j / i; auto const elem = 1e0 / std::sqrt(static_cast::type>(N)); sopt::Matrix result = sopt::Matrix::Zero(i, cols.size()); for(typename sopt::Matrix::Index k(0); k < result.cols(); ++k) result(cols[k] / N, k) = elem; return result; } TEST_CASE("L2Ball", "[proximal]") { using namespace sopt; proximal::L2Ball ball(0.5); Vector out; Vector x(5); x << 1, 2, 3, 4, 5; out = ball(0, x); CHECK(x.isApprox(out / 0.5 * x.stableNorm())); ball.epsilon(x.stableNorm() * 1.001); out = ball(0, x); CHECK(x.isApprox(out)); } TEST_CASE("WeightedL2Ball", "[proximal]") { using namespace sopt; Vector const weights = 0.01 * Vector::Random(5).array() + 1e0; Vector x(5); x << 1, 2, 3, 4, 5; proximal::WeightedL2Ball wball(0.5, weights); proximal::L2Ball ball(0.5); Vector const expected = ball((x.array() * weights.array()).matrix()).array() / weights.array(); Vector const actual = wball(x); CHECK(actual.isApprox(expected)); wball.epsilon((x.array() * weights.array()).matrix().stableNorm() * 1.001); CHECK(x.isApprox(wball(x))); } TEST_CASE("Euclidian norm", "[proximal]") { using namespace sopt; proximal::EuclidianNorm eucl; Vector out(5); Vector x(5); x << 1, 2, 3, 4, 5; eucl(out, x.stableNorm() * 1.001, x); CHECK(out.isApprox(Vector::Zero(x.size()))); out = eucl(0.1, x); CHECK(out.isApprox(x * (1e0 - 0.1 / x.stableNorm()))); } TEST_CASE("Translation", "[proximal]") { using namespace sopt; Vector out(5); Vector x(5); x << 1, 2, 3, 4, 5; proximal::L2Ball ball(5000); // Pass in a reference, so we can modify ball.epsilon later in the test. auto const translated = proximal::translate(std::ref(ball), -x * 0.5); translated(out, 0, x); CHECK(out.isApprox(x)); ball.epsilon(0.125); out = translated(0, x); Vector expected = ball(1, x * 0.5) + x * 0.5; CHECK(out.isApprox(expected)); } TEST_CASE("Tight-Frame L1 proximal", "[l1][proximal]") { using namespace sopt; auto l1 = proximal::L1TightFrame(); auto check_is_minimum = [&l1](Vector const &x, t_real gamma = 1e0) { typedef t_complex Scalar; Vector const p = l1(gamma, x); auto const mini = l1.objective(x, p, gamma); auto const eps = 1e-4; for(Vector::Index i(0); i < p.size(); ++i) { for(auto const dir : {Scalar(eps, 0), Scalar(0, eps), Scalar(-eps, 0), Scalar(0, -eps)}) { Vector p_plus = p; p_plus[i] += dir; CHECK(l1.objective(x, p_plus, gamma) >= mini); } } }; Vector const input = Vector::Random(8); // no weights SECTION("Scalar weights") { CHECK(l1(1, input).isApprox(proximal::l1_norm(1, input))); CHECK(l1(0.3, input).isApprox(proximal::l1_norm(0.3, input))); check_is_minimum(input, 0.664); } // with weights == 1 SECTION("vector weights") { l1.weights(Vector::Ones(input.size())); CHECK(l1(1, input).isApprox(proximal::l1_norm(1, input))); CHECK(l1(0.2, input).isApprox(proximal::l1_norm(0.2, input))); check_is_minimum(input, 0.664); } SECTION("vector weights with random values") { l1.weights(Vector::Random(input.size()).array().abs().matrix()); check_is_minimum(input, 0.235); } SECTION("Psi is a concatenation of permutations") { auto const psi = concatenated_permutations(input.size(), input.size() * 10); l1.Psi(psi).weights(1e0); check_is_minimum(input, 0.235); } SECTION("Weights cannot be negative") { CHECK_THROWS_AS(l1.weights(-1e0), Exception); Vector weights = Vector::Random(5).array().abs().matrix(); weights[2] = -1; CHECK_THROWS_AS(l1.weights(weights), Exception); } } TEST_CASE("L1 proximal utilities", "[l1][utilities]") { using namespace sopt; typedef t_complex Scalar; SECTION("Mixing") { auto const input = Vector::Random(10).eval(); Vector output; SECTION("No Mixing") { proximal::L1::NoMixing()(output, 2.1 * input, 0); CHECK(output.isApprox(2.1 * input)); proximal::L1::NoMixing()(output, 4.1 * input, 10); CHECK(output.isApprox(4.1 * input)); } SECTION("Fista Mixing") { proximal::L1::FistaMixing fista; // step zero: no mixing yet fista(output, 2.1 * input, 0); CHECK(output.isApprox(2.1 * input)); // step one: first mixing fista(output, 3.1 * input, 1); auto const alpha = (fista.next(1) - 1) / fista.next(fista.next(1)); Vector const first = (1e0 + alpha) * 3.1 * input - alpha * 2.1 * input; CHECK(output.isApprox(first)); // step two: second mixing fista(output, 4.1 * input, 1); auto const beta = (fista.next(fista.next(1)) - 1) / fista.next(fista.next(fista.next(1))); Vector const second = (1e0 + alpha) * 4.1 * input - alpha * first; CHECK(output.isApprox(second)); } } SECTION("Breaker") { proximal::L1::Breaker breaker(2e0); SECTION("Finds convergence") { std::vector objectives = {1.0, 0.9, 0.5, 0.6, 0.4, 0.4 + 0.41 * 1e-8, 0.3, 0.3 + 0.29 * 1e-8}; for(size_t i(0); i < objectives.size() - 1; ++i) { CHECK(not breaker(objectives[i])); CHECK(breaker.current() == Approx(objectives[i]).epsilon(1e-12)); } CHECK(breaker(objectives.back())); CHECK(not breaker.two_cycle()); CHECK(breaker.converged()); } SECTION("Find cycle") { std::vector objectives = {1.0, 0.9, 0.5, 0.6, 0.4, 0.3, 0.4, 0.3}; for(size_t i(0); i < objectives.size() - 1; ++i) { CHECK(not breaker(objectives[i])); CHECK(breaker.current() == Approx(objectives[i]).epsilon(1e-12)); } CHECK(breaker(objectives.back())); CHECK(breaker.two_cycle()); CHECK(not breaker.converged()); } } } TEST_CASE("L1 proximal", "[l1][proximal]") { using namespace sopt; typedef t_complex Scalar; auto l1 = proximal::L1().tolerance(1e-10); Vector const input = Vector::Random(4); SECTION("Check against tight-frame") { l1.fista_mixing(false); SECTION("Scalar weights") { auto const result = l1(1, input); CHECK(result.good); CHECK(result.niters > 0); CHECK(l1.itermax() == 0); CHECK(result.proximal.isApprox(proximal::L1TightFrame()(1, input))); } SECTION("Vector weights and more complex Psi") { auto const Psi = concatenated_permutations(input.size(), input.size() * 10); auto const weights = Vector::Random(Psi.cols()).array().abs().matrix().eval(); auto const gamma = 1e-1 / Psi.array().abs().sum(); l1.Psi(Psi).weights(weights).tolerance(1e-12); auto const result = l1(gamma, input); CHECK(result.good); CHECK(result.niters > 0); auto const expected = l1.tight_frame(gamma, input).eval(); CHECK(result.objective == Approx(l1.objective(input, expected, gamma))); CAPTURE((result.proximal - expected).array().abs().transpose()); CHECK(result.proximal.isApprox(expected)); } } SECTION("General case") { auto check_is_minimum = [&l1, &input](t_real gamma, Vector const &proximal) { // returns false if did not converge. // Looks like computing the proximal does not always work... auto const mini = l1.objective(input, proximal, gamma); auto const eps = 1e-4; // check alongst specific directions for(Vector::Index i(0); i < proximal.size(); ++i) { for(auto const dir : {Scalar(eps, 0), Scalar(0, eps), Scalar(-eps, 0), Scalar(0, -eps)}) { Vector p_plus = proximal; p_plus[i] += dir; if(l1.positivity_constraint()) p_plus = sopt::positive_quadrant(p_plus); else if(l1.real_constraint()) p_plus = p_plus.real().cast(); auto const rel_var = std::abs((l1.objective(input, p_plus, gamma) - mini) / mini); CHECK((l1.objective(input, p_plus, gamma) > mini or rel_var < l1.tolerance() * 10)); } } // check alongst non-specific directions for(size_t i(0); i < 10; ++i) { Vector p_plus = proximal + proximal.Random(proximal.size()) * eps; if(l1.positivity_constraint()) p_plus = sopt::positive_quadrant(p_plus); else if(l1.real_constraint()) p_plus = p_plus.real().cast(); auto const rel_var = std::abs((l1.objective(input, p_plus, gamma) - mini) / mini); CHECK((l1.objective(input, p_plus, gamma) > mini or rel_var < l1.tolerance() * 10)); } }; auto const Psi = Matrix::Random(input.size(), input.size() * 10).eval(); auto const weights = Vector::Random(Psi.cols()).array().abs().matrix().eval(); auto const gamma = 1e-1 / Psi.array().abs().sum(); l1.Psi(Psi).weights(weights).fista_mixing(true).tolerance(1e-10).itermax(5000); SECTION("No constraints") { CHECK(not l1.positivity_constraint()); CHECK(not l1.real_constraint()); auto const result = l1(gamma, input); CHECK(result.good); check_is_minimum(gamma, result.proximal); } SECTION("Positivity constraints") { l1.positivity_constraint(true); CHECK(l1.positivity_constraint()); CHECK(not l1.real_constraint()); auto const result = l1(gamma, input); CHECK(result.good); check_is_minimum(gamma, result.proximal); } SECTION("Real constraints") { l1.real_constraint(true); CHECK(l1.real_constraint()); CHECK(not l1.positivity_constraint()); auto const result = l1(gamma, input); CHECK(result.good); check_is_minimum(gamma, result.proximal); } } } sopt-2.0.0/cpp/tests/reweighted.cc000066400000000000000000000074601277570055300171020ustar00rootroot00000000000000#include #include #include #include "sopt/imaging_padmm.h" #include "sopt/reweighted.h" using namespace sopt; //! \brief Minimum set of functions and typedefs needed by reweighting //! \details The attributes are public and static so we can access them during the tests. struct DummyAlgorithm { typedef t_real Scalar; typedef Vector t_Vector; typedef ConvergenceFunction t_IsConverged; struct DiagnosticAndResult { //! Expected by reweighted algorithm static t_Vector x; }; DiagnosticAndResult operator()(t_Vector const &x) const { ++called_with_x; DiagnosticAndResult::x = x.array() + 0.1; return {}; } DiagnosticAndResult operator()(DiagnosticAndResult const &warm) const { ++called_with_warm; DiagnosticAndResult::x = warm.x.array() + 0.1; return {}; } //! Applies Ψ^T * x static t_Vector reweightee(DummyAlgorithm const &, t_Vector const &x) { ++DummyAlgorithm::called_reweightee; return x * 2; } //! sets the weights static void set_weights(DummyAlgorithm &, t_Vector const &weights) { ++DummyAlgorithm::called_weights; DummyAlgorithm::weights = weights; } static t_Vector weights; static int called_with_x; static int called_with_warm; static int called_reweightee; static int called_weights; }; int DummyAlgorithm::called_with_x = 0; int DummyAlgorithm::called_with_warm = 0; int DummyAlgorithm::called_reweightee = 0; int DummyAlgorithm::called_weights = 0; DummyAlgorithm::t_Vector DummyAlgorithm::DiagnosticAndResult::x; DummyAlgorithm::t_Vector DummyAlgorithm::weights; TEST_CASE("L0-Approximation") { auto const N = 6; DummyAlgorithm::t_Vector const input = DummyAlgorithm::t_Vector::Random(N); auto l0algo = algorithm::reweighted(DummyAlgorithm(), DummyAlgorithm::set_weights, DummyAlgorithm::reweightee); DummyAlgorithm::called_with_x = 0; DummyAlgorithm::called_with_warm = 0; DummyAlgorithm::called_reweightee = 0; DummyAlgorithm::called_weights = 0; DummyAlgorithm::DiagnosticAndResult::x = DummyAlgorithm::t_Vector::Zero(0); DummyAlgorithm::weights = DummyAlgorithm::t_Vector::Zero(0); GIVEN("The maximum number of iteration is zero") { l0algo.itermax(0); WHEN("The reweighting algorithm is called") { auto const result = l0algo(input); THEN("The algorithm exited at the first iteration") { CHECK(result.niters == 0); CHECK(result.good == true); } THEN("The weights is set to 1") { CHECK(result.weights.size() == 1); CHECK(std::abs(result.weights(0) - 1) < 1e-12); } THEN("The inner algorithm was called once") { CHECK(DummyAlgorithm::called_with_x == 1); CHECK(DummyAlgorithm::called_with_warm == 0); CHECK(result.algo.x.array().isApprox(input.array() + 0.1)); } } } GIVEN("The maximum number of iterations is one") { l0algo.itermax(1); WHEN("The reweighting algorithm is called") { auto const result = l0algo(input); THEN("The algorithm exited at the second iteration") { CHECK(result.niters == 1); CHECK(result.good == true); } THEN("The weights are not one") { CHECK(result.weights.size() == input.size()); // standard deviation of Ψ^T x, with x the output of the first call to the inner algorithm Vector<> const PsiT_x = DummyAlgorithm::reweightee({}, input.array() + 0.1); auto delta = standard_deviation(PsiT_x); CHECK(result.weights.array().isApprox(delta / (delta + PsiT_x.array().abs()))); } THEN("The inner algorithm was called twice") { CHECK(DummyAlgorithm::called_with_x == 1); CHECK(DummyAlgorithm::called_with_warm == 1); CHECK(result.algo.x.array().isApprox(input.array() + 0.2)); } } } } sopt-2.0.0/cpp/tests/sara.cc000066400000000000000000000070171277570055300156770ustar00rootroot00000000000000#include #include #include #include #include "sopt/wavelets.h" #include "sopt/wavelets/sara.h" sopt::t_int random_integer(sopt::t_int min, sopt::t_int max) { extern std::unique_ptr mersenne; std::uniform_int_distribution uniform_dist(min, max); return uniform_dist(*mersenne); }; TEST_CASE("Check SARA implementation mechanically", "[wavelet]") { using namespace sopt::wavelets; using namespace sopt; typedef std::tuple t_i; SARA const sara{t_i{std::string{"DB3"}, 1u}, t_i{std::string{"DB1"}, 2u}, t_i{std::string{"DB1"}, 3u}}; SECTION("Construction and vector functionality") { CHECK(sara.size() == 3); CHECK(sara[0].levels() == 1); CHECK(sara[1].levels() == 2); CHECK(sara[2].levels() == 3); CHECK(sara.max_levels() == 3); CHECK(sara[0].coefficients.isApprox(factory("DB3", 1).coefficients)); CHECK(sara[1].coefficients.isApprox(factory("DB1", 1).coefficients)); CHECK(sara[2].coefficients.isApprox(factory("DB1", 1).coefficients)); } Image<> input = Image<>::Random((1u << sara.max_levels()) * 3, (1u << sara.max_levels())); Image<> coeffs; sara.direct(coeffs, input); SECTION("Direct transform") { Image<> const first = sara[0].direct(input) / std::sqrt(sara.size()); Image<> const second = sara[1].direct(input) / std::sqrt(sara.size()); Image<> const third = sara[2].direct(input) / std::sqrt(sara.size()); auto const N = input.cols(); CAPTURE(coeffs.leftCols(N)); CAPTURE(first); CHECK(coeffs.leftCols(N).isApprox(first)); CHECK(coeffs.leftCols(2 * N).rightCols(N).isApprox(second)); CHECK(coeffs.rightCols(N).isApprox(third)); } SECTION("Indirect transform") { auto const output = sara.indirect(coeffs); CHECK(output.isApprox(input)); } } TEST_CASE("Linear-transform wrapper", "[wavelet]") { using namespace sopt::wavelets; using namespace sopt; SARA const sara{std::make_tuple(std::string{"DB3"}, 1u), std::make_tuple(std::string{"DB1"}, 2u), std::make_tuple(std::string{"DB1"}, 3u)}; auto const rows = 256, cols = 256; auto const Psi = linear_transform(sara, rows, cols); SECTION("Indirect transform") { Image<> const image = Image<>::Random(rows, cols); Image<> const expected = sara.direct(image); // The linear transform expects a column vector as input auto const as_vector = Vector<>::Map(image.data(), image.size()); // And it returns a column vector as well Vector<> const actual = Psi.adjoint() * as_vector; CHECK(actual.size() == expected.size()); auto const coeffs = Image<>::Map(actual.data(), image.rows(), image.cols() * sara.size()); CHECK(expected.rows() == coeffs.rows()); CHECK(expected.cols() == coeffs.cols()); CHECK(coeffs.isApprox(expected, 1e-8)); } SECTION("direct transform") { Image<> const coeffs = Image<>::Random(rows, cols * sara.size()); Image<> const expected = sara.indirect(coeffs); // The linear transform expects a column vector as input auto const as_vector = Vector<>::Map(coeffs.data(), coeffs.size()); // And it returns a column vector as well Vector<> const actual = Psi * as_vector; CHECK(actual.size() == expected.size()); CHECK(coeffs.cols() % sara.size() == 0); auto const image = Image<>::Map(actual.data(), coeffs.rows(), coeffs.cols() / sara.size()); CHECK(expected.rows() == image.rows()); CHECK(expected.cols() == image.cols()); CHECK(image.isApprox(expected, 1e-8)); } } sopt-2.0.0/cpp/tests/sdmm.cc000066400000000000000000000214551277570055300157130ustar00rootroot00000000000000#include #include #include #include "sopt/proximal.h" #include "sopt/sdmm.h" #include "sopt/types.h" sopt::t_int random_integer(sopt::t_int min, sopt::t_int max) { extern std::unique_ptr mersenne; std::uniform_int_distribution uniform_dist(min, max); return uniform_dist(*mersenne); }; typedef sopt::t_real Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; auto const N = 4; // Makes members public so we can test one at a time class IntrospectSDMM : public sopt::algorithm::SDMM { public: using sopt::algorithm::SDMM::initialization; using sopt::algorithm::SDMM::solve_for_xn; using sopt::algorithm::SDMM::update_directions; using sopt::algorithm::SDMM::t_Vectors; using sopt::algorithm::SDMM::t_Vector; }; TEST_CASE("Proximal translation", "[proximal]") { using namespace sopt; t_Vector const translation = t_Vector::Ones(N) * 5; auto const g = proximal::EuclidianNorm(); auto const gT = proximal::translate(g, -translation); t_Vector const input = t_Vector::Random(N).array() + 1e0; CHECK(g(0.1, input).isApprox((1e0 - 0.1 / input.stableNorm()) * input)); auto const gamma = input.stableNorm() * 0.5; CHECK(g(gamma, input).isApprox((1e0 - gamma / input.stableNorm()) * input)); CHECK(g(gamma * 2 + 1, input).isApprox(input.Zero(N))); CHECK(gT(0.1, input) .isApprox((1e0 - 0.1 / (input - translation).stableNorm()) * (input - translation) + translation)); } // Iterate through algorithm for special case where the L_i are identies and the objective functions // are simple euclidian norms TEST_CASE("Introspect SDMM with L_i = Identity and Euclidian objectives", "[sdmm]") { using namespace sopt; t_Matrix const Id = t_Matrix::Identity(N, N).eval(); t_Vector const target0 = t_Vector::Zero(N); t_Vector const target1 = t_Vector::Random(N); auto const g0 = proximal::translate(proximal::EuclidianNorm(), -target0); auto const g1 = proximal::translate(proximal::EuclidianNorm(), -target1); t_Vector const input = 10 * t_Vector::Random(N); IntrospectSDMM sdmm = IntrospectSDMM(); sdmm.itermax(10) .gamma(0.01) .conjugate_gradient(std::numeric_limits::max(), 1e-12) .append(g0, Id) .append(g1, Id); SECTION("Step by Step") { INFO("Initialization"); t_Vector out = input; IntrospectSDMM::t_Vectors y(sdmm.transforms().size(), t_Vector::Zero(out.size())); IntrospectSDMM::t_Vectors z(sdmm.transforms().size(), t_Vector::Zero(out.size())); sdmm.initialization(y, z, out); CHECK(y[0].isApprox(input)); CHECK(y[1].isApprox(input)); INFO("\nThen solve for conjugate gradient"); auto const diagnostic0 = sdmm.solve_for_xn(out, y, z); CHECK(diagnostic0.good); CAPTURE(out.transpose()); CAPTURE(input.transpose()); CAPTURE(0.5 * (y[0] + y[1]).transpose()); CHECK(out.isApprox(0.5 * (y[0] + y[1]), 1e-8)); CHECK(out.isApprox(input, 1e-8)); INFO("\nWe move on to first iteration!"); INFO("- updates y and z"); sdmm.update_directions(y, z, out); CHECK(y[0].isApprox(g0(sdmm.gamma(), input))); CHECK(y[1].isApprox(g1(sdmm.gamma(), input))); CHECK(z[0].isApprox(input - y[0])); CHECK(z[1].isApprox(input - y[1])); INFO("- solve for conjugate gradient"); auto const diagnostic1 = sdmm.solve_for_xn(out, y, z); CHECK(diagnostic1.good); CAPTURE(out.transpose()); CAPTURE((0.5 * (y[0] - z[0] + y[1] - z[1])).transpose()); CHECK(out.isApprox(0.5 * (y[0] - z[0] + y[1] - z[1]))); t_Vector const x1 = g0(sdmm.gamma(), input) + g1(sdmm.gamma(), input) - input; CHECK(out.isApprox(x1)); INFO("\nWe move on to second iteration!"); INFO("- updates y and z"); sdmm.update_directions(y, z, out); CHECK(y[0].isApprox(g0(sdmm.gamma(), g1(sdmm.gamma(), input)))); CHECK(y[1].isApprox(g1(sdmm.gamma(), g0(sdmm.gamma(), input)))); CHECK(z[0].isApprox(g1(sdmm.gamma(), input) - y[0])); CHECK(z[1].isApprox(g0(sdmm.gamma(), input) - y[1])); INFO("- solve for conjugate gradient"); auto const diagnostic2 = sdmm.solve_for_xn(out, y, z); CHECK(diagnostic2.good); CHECK(out.isApprox(0.5 * (y[0] - z[0] + y[1] - z[1]))); t_Vector const x2 = g0(sdmm.gamma(), g1(sdmm.gamma(), input)) + g1(sdmm.gamma(), g0(sdmm.gamma(), input)) - 0.5 * g1(sdmm.gamma(), input) - 0.5 * g0(sdmm.gamma(), input); CHECK(out.isApprox(x2)); } SECTION("Iteration by Iteration") { t_Vector out; SECTION("First Iteration") { sdmm.itermax(1); auto const diagnostic = sdmm(out, input); CHECK(not diagnostic.good); CHECK(diagnostic.niters == 1); CHECK(out.isApprox(g0(sdmm.gamma(), input) + g1(sdmm.gamma(), input) - input)); } SECTION("Second Iteration") { sdmm.itermax(2); auto const diagnostic = sdmm(out, input); CHECK(not diagnostic.good); CHECK(diagnostic.niters == 2); t_Vector const x2 = g0(sdmm.gamma(), g1(sdmm.gamma(), input)) + g1(sdmm.gamma(), g0(sdmm.gamma(), input)) - 0.5 * g1(sdmm.gamma(), input) - 0.5 * g0(sdmm.gamma(), input); CHECK(out.isApprox(x2)); } SECTION("Nth Iterations") { sdmm.gamma(1); for(t_uint itermax(0); itermax < 10; ++itermax) { t_Vector x = input; t_Vector y[2] = {x, x}; t_Vector z[2] = {t_Vector::Zero(N).eval(), t_Vector::Zero(N).eval()}; for(t_uint i(0); i < itermax; ++i) { y[0] = g0(sdmm.gamma(), x + z[0]); y[1] = g1(sdmm.gamma(), x + z[1]); z[0] += x - g0(sdmm.gamma(), x + z[0]); z[1] += x - g1(sdmm.gamma(), x + z[1]); x = 0.5 * (y[0] - z[0] + y[1] - z[1]); } sdmm.itermax(itermax); auto const diagnostic = sdmm(out, input); CHECK(out.isApprox(x, 1e-8)); CHECK(not diagnostic.good); CHECK(diagnostic.niters == itermax); } } } } TEST_CASE("SDMM with ||x - x0||_2 functions", "[sdmm][integration]") { using namespace sopt; t_Matrix const Id = t_Matrix::Identity(N, N).eval(); t_Vector const target0 = t_Vector::Random(N); t_Vector target1 = t_Vector::Random(N) * 4; // for(t_uint i(0); i < N; ++i) target1(i) = i + 1; auto sdmm = algorithm::SDMM() .itermax(5000) .gamma(1) .conjugate_gradient(std::numeric_limits::max(), 1e-12) .append(proximal::translate(proximal::EuclidianNorm(), -target0), Id) .append(proximal::translate(proximal::EuclidianNorm(), -target1), Id); t_Vector result; SECTION("Just two operators") { auto const diagnostic = sdmm(result, t_Vector::Random(N)); CHECK(not diagnostic.good); CHECK(diagnostic.niters == sdmm.itermax()); t_Vector const segment = (target1 - target0).normalized(); t_real const alpha = (result - target0).transpose() * segment; CAPTURE(target0.transpose()); CAPTURE(target1.transpose()); CHECK((target1 - target0).transpose() * segment >= alpha); CHECK(alpha >= 0e0); CHECK((result - target0 - alpha * segment).stableNorm() < 1e-8); } SECTION("Three operators") { t_Vector const target2 = t_Vector::Random(N) * 8; sdmm.append(proximal::translate(proximal::EuclidianNorm(), -target2), Id); auto const diagnostic = sdmm(result, t_Vector::Random(N)); CHECK(not diagnostic.good); CHECK(diagnostic.niters == sdmm.itermax()); CAPTURE(result.transpose()); auto const func = [&target0, &target1, &target2](t_Vector const &x) { return (x - target0).stableNorm() + (x - target1).stableNorm() + (x - target2).stableNorm(); }; for(int i(0); i < N; ++i) { t_Vector epsilon = t_Vector::Zero(N); epsilon(i) = 1e-6; CHECK(func(result) < func(result + epsilon)); CHECK(func(result) < func(result - epsilon)); } } SECTION("With different L") { t_Matrix const L0 = t_Matrix::Random(N, N) * 2; t_Matrix const L1 = t_Matrix::Random(N, N) * 4; REQUIRE(std::abs((L0.transpose() * L0 + L1.transpose() * L1).determinant()) > 1e-8); sdmm.itermax(300); sdmm.transforms(0) = linear_transform(L0); sdmm.transforms(1) = linear_transform(L1); auto const diagnostic = sdmm(result, t_Vector::Random(N)); CHECK(not diagnostic.good); CHECK(diagnostic.niters == sdmm.itermax()); CAPTURE(result.transpose()); auto const func = [&target0, &target1, &L0, &L1](t_Vector const &x) { return (L0 * x - target0).stableNorm() + (L1 * x - target1).stableNorm(); }; for(int i(0); i < N; ++i) { t_Vector epsilon = t_Vector::Zero(N); epsilon(i) = 1e-4; CAPTURE(epsilon.transpose()); CHECK(func(result) <= func(result + epsilon)); CHECK(func(result) <= func(result - epsilon)); } } } sopt-2.0.0/cpp/tests/sdmm_warm_start.cc000066400000000000000000000037251277570055300201560ustar00rootroot00000000000000#include #include #include #include "sopt/proximal.h" #include "sopt/sdmm.h" #include "sopt/types.h" typedef sopt::t_real Scalar; typedef sopt::Vector t_Vector; typedef sopt::Matrix t_Matrix; auto const N = 30; SCENARIO("SDMM with warm start", "[sdmm][integration]") { using namespace sopt; GIVEN("An SDMM instance with its input") { t_Matrix const Id = t_Matrix::Identity(N, N).eval(); t_Vector const target0 = t_Vector::Random(N); t_Vector target1 = t_Vector::Random(N) * 4; auto convergence = [&target1, &target0](t_Vector const &x) -> bool { t_Vector const segment = (target1 - target0).normalized(); t_real const alpha = (x - target0).transpose() * segment; return alpha >= 0e0 and (target1 - target0).transpose() * segment >= alpha and (x - target0 - alpha * segment).stableNorm() < 1e-8; }; auto sdmm = algorithm::SDMM() .is_converged(convergence) .itermax(5000) .gamma(1) .conjugate_gradient(std::numeric_limits::max(), 1e-12) .append(proximal::translate(proximal::EuclidianNorm(), -target0), Id) .append(proximal::translate(proximal::EuclidianNorm(), -target1), Id); t_Vector input = t_Vector::Random(N); WHEN("the algorithms runs") { auto const full = sdmm(input); THEN("it converges") { CHECK(full.niters > 20); CHECK(full.good); } WHEN("It is set to stop before convergence") { auto const first_half = sdmm.itermax(full.niters - 5)(input); THEN("It is not converged") { CHECK(not first_half.good); } WHEN("A warm restart is attempted") { auto const second_half = sdmm.itermax(5000)(first_half); THEN("The warm restart is validated by the fast convergence") { CHECK(second_half.niters < 10); } } } } } } sopt-2.0.0/cpp/tests/wavelets.cc000066400000000000000000000271451277570055300166070ustar00rootroot00000000000000#include #include #include "sopt/types.h" #include "sopt/wavelets/direct.h" #include "sopt/wavelets/indirect.h" #include "sopt/wavelets/wavelet_data.h" #include "sopt/wavelets/wavelets.h" typedef sopt::Array t_iVector; t_iVector even(t_iVector const &x) { t_iVector result((x.size() + 1) / 2); for(t_iVector::Index i(0); i < x.size(); i += 2) result(i / 2) = x(i); return result; }; t_iVector odd(t_iVector const &x) { t_iVector result(x.size() / 2); for(t_iVector::Index i(1); i < x.size(); i += 2) result(i / 2) = x(i); return result; }; template Eigen::Array upsample(Eigen::ArrayBase const &input) { typedef Eigen::Array Matrix; Matrix result(input.size() * 2); for(t_iVector::Index i(0); i < input.size(); ++i) { result(2 * i) = input(i); result(2 * i + 1) = 0; } return result; }; sopt::t_int random_integer(sopt::t_int min, sopt::t_int max) { extern std::unique_ptr mersenne; std::uniform_int_distribution uniform_dist(min, max); return uniform_dist(*mersenne); }; t_iVector random_ivector(sopt::t_int size, sopt::t_int min, sopt::t_int max) { extern std::unique_ptr mersenne; t_iVector result(size); std::uniform_int_distribution uniform_dist(min, max); for(t_iVector::Index i(0); i < result.size(); ++i) result(i) = uniform_dist(*mersenne); return result; }; // Checks round trip operation template void check_round_trip(Eigen::ArrayBase const &input_, sopt::t_uint db, sopt::t_uint nlevels = 1) { auto const input = input_.eval(); auto const &dbwave = sopt::wavelets::daubechies_data(db); auto const transform = sopt::wavelets::direct_transform(input, nlevels, dbwave); auto const actual = sopt::wavelets::indirect_transform(transform, nlevels, dbwave); CAPTURE(actual); CAPTURE(input); CAPTURE(transform); CHECK(input.isApprox(actual, 1e-14)); CHECK(not transform.isApprox(sopt::wavelets::direct_transform(input, nlevels - 1, dbwave), 1e-4)); } TEST_CASE("Wavelet transform innards with integer data", "[wavelet]") { using namespace sopt::wavelets; t_iVector small(3); small << 1, 2, 3; t_iVector large(6); large << 4, 5, 6, 7, 8, 9; SECTION("Periodic scalar product") { // no wrapping CHECK(periodic_scalar_product(large, small, 0) == 1 * 4 + 2 * 5 + 3 * 6); CHECK(periodic_scalar_product(large, small, 1) == 1 * 5 + 2 * 6 + 3 * 7); CHECK(periodic_scalar_product(large, small, 3) == 1 * 7 + 2 * 8 + 3 * 9); // with wrapping CHECK(periodic_scalar_product(large, small, 4) == 1 * 8 + 2 * 9 + 3 * 4); // with wrapping and expression CHECK(periodic_scalar_product(large, small.reverse(), 4) == 3 * 8 + 2 * 9 + 1 * 4); // wrapping works with offset as well CHECK(periodic_scalar_product(large, small, 4 + large.size()) == 1 * 8 + 2 * 9 + 3 * 4); CHECK(periodic_scalar_product(large, small, 4 - 3 * large.size()) == 1 * 8 + 2 * 9 + 3 * 4); // signal smaller than filter CHECK(periodic_scalar_product(small, large.head(4), 1) == 4 * 2 + 5 * 3 + 6 * 1 + 7 * 2); } SECTION("Convolve") { t_iVector result(large.size()); convolve(result, large, small); CHECK(result(0) == 1 * 4 + 2 * 5 + 3 * 6); CHECK(result(1) == 1 * 5 + 2 * 6 + 3 * 7); CHECK(result(3) == 1 * 7 + 2 * 8 + 3 * 9); CHECK(result(4) == 1 * 8 + 2 * 9 + 3 * 4); } SECTION("Convolve and sum") { t_iVector result(large.size()); t_iVector noOffset(large.size()); // Check that if high pass is zero, then this is an offseted convolution convolve_sum(result, large, small, large, 0 * small); convolve(noOffset, large, small); CHECK(result(small.size() - 1) == noOffset(0)); CHECK(result(0) == noOffset(result.size() - small.size() + 1)); // Check same for low pass convolve_sum(result, large, 0 * small, large, small); CHECK(result(small.size() - 1) == noOffset(0)); CHECK(result(0) == noOffset(result.size() - small.size() + 1)); // Check symmetry relationships auto const trial = [&small, &large](int a, int b, int c, int d) { t_iVector result(large.size()); convolve_sum(result, a * large, b * small, c * large, d * small); return result; }; // should all be ok as long as arguments sum: (a * b) + (c * d) == (a' * b') + (c' * d') CHECK((trial(0, 1, 3, 1) == trial(0, 1, 1, 3)).all()); CHECK((trial(5, 1, 3, 1) == trial(3, 1, 5, 1)).all()); CHECK((trial(1, 5, 3, 1) == trial(3, 1, 5, 1)).all()); CHECK((trial(1, 3, 5, 1) == trial(3, 1, 5, 1)).all()); CHECK((trial(1, 3, 1, 5) == trial(3, 1, 5, 1)).all()); CHECK((trial(1, 0, 4, 2) == trial(3, 1, 5, 1)).all()); CHECK((trial(1, -1, 1, 1) == trial(0, 1, 0, 1)).all()); CHECK((trial(4, -3, 2, 6) == trial(0, 1, 0, 1)).all()); } SECTION("Convolve and Down-sample simultaneously") { t_iVector expected(large.size()); convolve(expected, large, small); t_iVector actual(large.size() / 2); down_convolve(actual, large, small); for(size_t i(0); i < static_cast(actual.size()); ++i) CHECK(expected(i * 2) == actual(i)); } SECTION("Convolve output to expression") { t_iVector actual(large.size() * 2); t_iVector expected(large.size()); convolve(actual.head(large.size()), large, small); convolve(expected, large, small); CHECK((actual.head(large.size()) == expected).all()); } SECTION("Copy does copy") { auto result = copy(large); CHECK(large.data() != result.data()); auto actual = copy(large.head(3)); CHECK(large.data() != actual.data()); CHECK(large.data() == large.head(3).data()); } SECTION("Convolve, Sum and Up-sample simultaneously") { for(sopt::t_int i(0); i < 100; ++i) { auto const Ncoeffs = random_integer(2, 10) * 2; auto const Nfilters = random_integer(2, 5); auto const Nhead = Ncoeffs / 2; auto const Ntail = Ncoeffs - Nhead; auto const coeffs = random_ivector(Ncoeffs, -10, 10); auto const low = random_ivector(Nfilters, -10, 10); auto const high = random_ivector(Nfilters, -10, 10); t_iVector actual(Ncoeffs), expected(Ncoeffs); // does all in go, more complicated but compuationally less intensive up_convolve_sum(actual, coeffs, even(low), odd(low), even(high), odd(high)); // first up-samples, then does convolve: conceptually simpler but does unnecessary operations convolve_sum(expected, upsample(coeffs.head(Nhead)), low, upsample(coeffs.tail(Ntail)), high); CHECK((actual == expected).all()); } } } TEST_CASE("1D wavelet transform with floating point data", "[wavelet]") { using namespace sopt; using namespace sopt::wavelets; Image<> const data = Image<>::Random(16, 16); auto const &wavelet = daubechies_data(4); // Condition on input fixture data REQUIRE((data.rows() % 2 == 0 and (data.cols() == 1 or data.cols() % 2 == 0))); SECTION("Direct transform == two downsample + convolution") { auto const actual = direct_transform(data.row(0), 1, wavelet); Array<> high(data.cols() / 2), low(data.cols() / 2); down_convolve(high, data.row(0), wavelet.direct_filter.high); down_convolve(low, data.row(0), wavelet.direct_filter.low); CHECK(low.transpose().isApprox(actual.head(data.row(0).size() / 2))); CHECK(high.transpose().isApprox(actual.tail(data.row(0).size() / 2))); } SECTION("Indirect transform == two upsample + convolution") { auto const actual = indirect_transform(data.row(0).transpose(), 1, wavelet); auto const low = upsample(data.row(0).transpose().head(data.rows() / 2)); auto const high = upsample(data.row(0).transpose().tail(data.rows() / 2)); auto expected = copy(data.row(0).transpose()); convolve_sum(expected, low, wavelet.direct_filter.low.reverse(), high, wavelet.direct_filter.high.reverse()); CAPTURE(expected.transpose()); CAPTURE(actual.transpose()); CHECK(expected.isApprox(actual)); } SECTION("Round-trip test for single level") { for(t_int i(0); i < 20; ++i) { check_round_trip(Array<>::Random(random_integer(2, 100) * 2), random_integer(1, 38), 1); } } SECTION("Round-trip test for two levels") { check_round_trip(Array<>::Random(8), 1, 2); check_round_trip(Array<>::Random(8), 2, 2); check_round_trip(Array<>::Random(16), 4, 2); check_round_trip(Array<>::Random(52), 10, 2); } t_uint nlevels = 5; SECTION("Round-trip test for multiple levels") { for(t_int i(0); i < 10; ++i) { auto const n = random_integer(2, nlevels); check_round_trip(Array<>::Random(random_integer(2, 100) * (1u << n)), random_integer(1, 38), n); } } } TEST_CASE("1D wavelet transform with complex data", "[wavelet]") { using namespace sopt; using namespace sopt::wavelets; SECTION("Round-trip test for complex data") { auto input = Array::Random(random_integer(2, 100) * 2).eval(); auto const &dbwave = daubechies_data(random_integer(1, 38)); auto const actual = indirect_transform(direct_transform(input, 1, dbwave), 1, dbwave); CHECK(input.isApprox(actual, 1e-14)); CHECK(not input.isApprox(direct_transform(input, 1, dbwave), 1e-4)); } } TEST_CASE("2D wavelet transform with real data", "[wavelet]") { using namespace sopt; using namespace sopt::wavelets; SECTION("Single level round-trip test for square matrix") { auto N = random_integer(2, 100) * 2; check_round_trip(Image<>::Random(N, N), random_integer(1, 38), 1); } SECTION("Single level round-trip test for non-square matrix") { auto Nx = random_integer(2, 5) * 2; auto Ny = Nx + 5 * 2; check_round_trip(Image<>::Random(Nx, Ny), random_integer(1, 38), 1); } SECTION("Round-trip test for multiple levels") { for(t_int i(0); i < 10; ++i) { auto const n = random_integer(2, 5); auto const Nx = random_integer(2, 5) * (1u << n); auto const Ny = random_integer(2, 5) * (1u << n); check_round_trip(Image<>::Random(Nx, Ny), random_integer(1, 38), n); } } } TEST_CASE("Functor implementation", "[wavelet]") { using namespace sopt; auto const wavelet = wavelets::factory("DB3", 4); auto const input = Image::Random(256, 128).eval(); SECTION("Normal instances") { auto const transform = wavelet.direct(input); CHECK(transform.isApprox(wavelets::direct_transform(input, wavelet.levels(), wavelet))); CHECK(input.isApprox(wavelet.indirect(transform))); } SECTION("Expression instances") { Image output(2, input.cols()); wavelet.direct(output.row(0).transpose(), input.row(0).transpose()); wavelet.indirect(output.row(0).transpose(), output.row(1).transpose()); CHECK(input.row(0).isApprox(output.row(1))); } } TEST_CASE("Automatic input resizing", "[wavelet]") { using namespace sopt; auto const wavelet = wavelets::factory("DB3", 4); auto const input = Image::Random(256, 128).eval(); Image output(1, 1); wavelet.direct(output, input); CHECK(output.rows() == input.rows()); CHECK(output.cols() == input.cols()); output.resize(1, 1); wavelet.indirect(input, output); CHECK(output.rows() == input.rows()); CHECK(output.cols() == input.cols()); } TEST_CASE("Dirac wavelets") { using namespace sopt; auto const wavelet = wavelets::factory("Dirac"); Image const input = Image::Random(256, 128); Image output(1, 1); wavelet.direct(output, input); CHECK(output.isApprox(input)); output = Image::Zero(1, 1); wavelet.indirect(input, output); CHECK(output.isApprox(input)); } sopt-2.0.0/cpp/tests/wrapper.cc000066400000000000000000000032111277570055300164210ustar00rootroot00000000000000#include #include #include "sopt/wrapper.h" TEST_CASE("Function wrappers", "[utility]") { using namespace sopt; typedef Array t_Array; typedef t_Array &t_RefArray; typedef t_Array const t_ConstRefArray; SECTION("Square function") { auto func = [](t_RefArray output, t_ConstRefArray const &input) { output = input * 2 + 1; }; t_Array const x = t_Array::Random(5); auto const A = details::wrap(func); // Expected result t_Array const expected = (x * 2 + 1).eval(); CHECK((A * x).matrix() == expected.matrix()); CHECK(A(x).matrix() == expected.matrix()); } SECTION("Rectangular function") { auto func = [](t_RefArray output, t_ConstRefArray const &input) { output = input.head(input.size() / 2) * 2 + 1; }; t_Array const x = t_Array::Random(5); auto const A = details::wrap(func, {{1, 2, 0}}); // Expected result t_Array const expected = (x.head(x.size() / 2) * 2 + 1).eval(); CHECK((A * x).cols() == 1); CHECK((A * x).rows() == 2); CHECK((A * x).matrix() == expected.matrix()); CHECK(A(x).matrix() == expected.matrix()); } SECTION("Fixed output-size functions") { auto func = [](t_RefArray output, t_ConstRefArray const &input) { output = input.head(3) * 2 + 1; }; t_Array const x = t_Array::Random(5); auto const A = details::wrap(func, {{0, 1, 3}}); // Expected result t_Array const expected = (x.head(3) * 2 + 1).eval(); CHECK((A * x).cols() == 1); CHECK((A * x).rows() == 3); CHECK((A * x).matrix() == expected.matrix()); CHECK(A(x).matrix() == expected.matrix()); } } sopt-2.0.0/cpp/tools_for_tests/000077500000000000000000000000001277570055300165235ustar00rootroot00000000000000sopt-2.0.0/cpp/tools_for_tests/CMakeLists.txt000066400000000000000000000017711277570055300212710ustar00rootroot00000000000000add_library(tools_for_tests STATIC tiffwrappers.cc tiffwrappers.h) target_link_libraries(tools_for_tests ${TIFF_LIBRARY}) target_include_directories(tools_for_tests PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/.." "${PROJECT_BINARY_DIR}/include/" ) target_include_directories(tools_for_tests SYSTEM PUBLIC ${TIFF_INCLUDE_DIR}) if(SPDLOG_INCLUDE_DIR) target_include_directories(tools_for_tests SYSTEM PUBLIC ${SPDLOG_INCLUDE_DIR}) endif() if(EIGEN3_INCLUDE_DIR) target_include_directories(tools_for_tests SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR}) endif() add_dependencies(tools_for_tests lookup_dependencies) # Simple manual tester of read/write tiff add_executable(copy_tiff copy_tiff.cc) target_link_libraries(copy_tiff tools_for_tests sopt) configure_file("directories.in.h" "${PROJECT_BINARY_DIR}/include/tools_for_tests/directories.h") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/outputs") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/outputs/sdmm") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/outputs/sdmm/regressions") sopt-2.0.0/cpp/tools_for_tests/cdata.h000066400000000000000000000022131277570055300177460ustar00rootroot00000000000000#ifndef SOPT_TOOLS_FOR_TESTS_CDATA #define SOPT_TOOLS_FOR_TESTS_CDATA #include "sopt/config.h" #include #include "sopt/linear_transform.h" namespace sopt { // Wraps calls to sampling and wavelets to C style template struct CData { typedef Eigen::Matrix t_Vector; typename t_Vector::Index nin, nout; sopt::LinearTransform const &transform; t_uint direct_calls, adjoint_calls; }; template void direct_transform(void *out, void *in, void **data) { CData const &cdata = *(CData *)data; typedef Eigen::Matrix t_Vector; t_Vector const eval = cdata.transform * t_Vector::Map((T *)in, cdata.nin); ++(((CData *)data)->direct_calls); t_Vector::Map((T *)out, cdata.nout) = eval; } template void adjoint_transform(void *out, void *in, void **data) { CData const &cdata = *(CData *)data; typedef Eigen::Matrix t_Vector; t_Vector const eval = cdata.transform.adjoint() * t_Vector::Map((T *)in, cdata.nout); ++(((CData *)data)->adjoint_calls); t_Vector::Map((T *)out, cdata.nin) = eval; } } /* sopt */ #endif sopt-2.0.0/cpp/tools_for_tests/copy_tiff.cc000066400000000000000000000016611277570055300210200ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include // \min_{x} ||\Psi^\dagger x||_1 \quad \mbox{s.t.} \quad ||y - x||_2 < \epsilon and x \geq 0 int main(int argc, char const **argv) { if(argc != 3) { std::cout << "Expects two arguments:\n" "- path to the image to clean (or name of standard SOPT image)\n" "- path to output image\n"; exit(0); } // Initializes and sets logger (if compiled with logging) // See set_level function for levels. sopt::logging::initialize(); // Read input file auto const image = sopt::notinstalled::read_standard_tiff(argv[1]); sopt::utilities::write_tiff(image, argv[2]); auto const reread = sopt::utilities::read_tiff(argv[2]); return 0; } sopt-2.0.0/cpp/tools_for_tests/directories.in.h000066400000000000000000000006041277570055300216150ustar00rootroot00000000000000#ifndef SOPT_DATA_DIR_H #define SOPT_DATA_DIR_H #include "sopt/config.h" #include namespace sopt { namespace notinstalled { //! Holds images and such inline std::string data_directory() { return "@PROJECT_SOURCE_DIR@/images"; } //! Output artefacts from tests inline std::string output_directory() { return "@PROJECT_BINARY_DIR@/outputs"; } } } /* sopt::notinstalled */ #endif sopt-2.0.0/cpp/tools_for_tests/inpainting.h000066400000000000000000000027651277570055300210460ustar00rootroot00000000000000#ifndef SOPT_TOOLS_FOR_TESTS_INPAINTING_H #define SOPT_TOOLS_FOR_TESTS_INPAINTING_H #include "sopt/config.h" #include #include #include namespace sopt { template Vector target(sopt::LinearTransform> const &sampling, sopt::Image const &image) { return sampling * Vector::Map(image.data(), image.size()); } template typename real_type::type sigma(sopt::LinearTransform> const &sampling, sopt::Image const &image) { auto const snr = 30.0; auto const y0 = target(sampling, image); return y0.stableNorm() / std::sqrt(y0.size()) * std::pow(10.0, -(snr / 20.0)); } template Vector dirty(sopt::LinearTransform> const &sampling, sopt::Image const &image, RANDOM &mersenne) { // values near the mean are the most likely // standard deviation affects the dispersion of generated values from the mean auto const y0 = target(sampling, image); std::normal_distribution<> gaussian_dist(0, sigma(sampling, image)); Vector y(y0.size()); for(t_int i = 0; i < y0.size(); i++) y(i) = y0(i) + gaussian_dist(mersenne); return y; } template typename real_type::type epsilon(sopt::LinearTransform> const &sampling, sopt::Image const &image) { auto const y0 = target(sampling, image); auto const nmeasure = y0.size(); return std::sqrt(nmeasure + 2 * std::sqrt(nmeasure)) * sigma(sampling, image); } } /* sopt */ #endif sopt-2.0.0/cpp/tools_for_tests/tiffwrappers.cc000066400000000000000000000007521277570055300215520ustar00rootroot00000000000000#include #include "sopt/types.h" #include "sopt/utilities.h" #include "tools_for_tests/directories.h" #include "tools_for_tests/tiffwrappers.h" namespace sopt { namespace notinstalled { Image<> read_standard_tiff(std::string const &name) { std::string const stdname = sopt::notinstalled::data_directory() + "/" + name + ".tiff"; bool const is_std = std::ifstream(stdname).good(); return sopt::utilities::read_tiff(is_std ? stdname : name); } } } /* sopt::notinstalled */ sopt-2.0.0/cpp/tools_for_tests/tiffwrappers.h000066400000000000000000000005051277570055300214100ustar00rootroot00000000000000#ifndef SOPT_TIFF_WRAPPER_H #define SOPT_TIFF_WRAPPER_H #include "sopt/config.h" #include #include "sopt/types.h" namespace sopt { namespace notinstalled { //! Reads tiff image from sopt data directory if it exists sopt::Image<> read_standard_tiff(std::string const &name); } } /* sopt::notinstalled */ #endif sopt-2.0.0/images/000077500000000000000000000000001277570055300137565ustar00rootroot00000000000000sopt-2.0.0/images/M31T.tiff000066400000000000000000000406141277570055300153210ustar00rootroot00000000000000II*@         *    !!#%" "  "&+-.-(&  & "&))*,0322/,)" * !&).2323243/,+*&"! ,  "%*/4654100,'&&#    # %+/21/,)*)%"%"  , $&$##%),-)($#$#$%&%$"    !#"!*#%)('%!##%()*++(#  < !#! $()*'())+,+-//-'  H  %# "(,.-.00/0.+-//.(" (  ''$!!%*.35244322-+ ,*'##&()'"   H #)+)&$$%*/48=;877531.,*)&%#!  !%*-22,&$%$! G "%*..+)(*.3:>CFB@=;631/-+)&#  "$&),1781)'%&$ 1  $&(-0/.-.17>DHOPMIEA:520//-'"!!#(/471*$ "#"   $''(.0026:AGKQXXURMF>732121)!#*/,&!"   E!&)')*(,06;@FILRVXXUMF>621154," #$  R "')()%#(06:>?@CFJMOJE@71/0596.'    3 #'*)&"!%-25531368;<::60./6>A;2*"     /"&()&#! #),,*'&(*,.--/,*08@HH?3*"   W!!!!&''(&#!"%&$"!#%'(''(&*9ADGE=2)"     #&# "$#%$%(%$""%$#  #%&'+&.?>;>=6.($   #%(&$!!$%'('%##$%#%$(*(&"#%&()"180031,*'$""    C!&('#!"$&)+(%$##"!$(032-)&# "$%&)**),*$&)''&%#%#!"   , "&'# "%(,+(&&$!!'/:?>830*&%$$%&')(&# #$"  #    @ #%# #&+-+*)'%""&/;=?=72/"-,1796/(" $),&    ].676=Oamv}qWB78;>:40--.+,05771)!  !%&()& E  $#  !19;H^x|q^I9,(*.-)-/5<@B?90)$!"$&%#"!    !""#   (7BEA:1(! T +5:/$"%(()('*,.5@LUVOD70*(),-*%$%      g +8EOVWQG>2(  '159Hbym]K7( $%&%$%&(0;K`opgUD;536851*#$($     +7BM[lusk[F8-# 1$-19Ke}shYG3$ !%&#! %2?QlkWJB@CB?91( %)%   b %4=DOd~pVB5+" #,2Nh}gWIFGFFB9-#!'(#    Z+6:@LduWB6,%&/7?Nfz}raI3("!++$%08E\u}hTE@?AEE:/%!&(&!     f*15:E\viL;2,% +5?5'    9 !#&).4:=:4..21+   +6>CKWcluǙjI8.($"#%')*&!!$*4BRTH8)     8 "#%),0110-142+  &.6Tdg`TNNS`kmmdUI>4,*)!$(%$#$#! $4GXdgn±d?,    .+8BGHD<3//4DXfdXJA>@HNSWPG?94134,('!%'#"!> #3I]gks}Y=)    g &5CKLG=1)(,6DPVPE;547>FNME>9745;?@?4*!#"!! !" &7J\gnrwiO8&     [!.95239BPSE7-%"!"#$#"$.;GPZelkhgkl`N>/"    9*2:>BB<2%! !#.@WpoXF=4/-1:KLA8,% "&)&#"$,;KUZaijjhghfZJ;."  A  %-3577:71*#0EanUC6,)*2=;72("!#*.10+)(,9KZchmkgfcbb`TD7.%   0  (0652/--(%  %2HikN:-''-0(+%!#+2640./9JZgpvvlc[VUVSI;4/)   i !)0772*$" %3JlղY@1)'*,0.)%!"*143007DXkx|m^PIHHE<52.+$      #*/352*H %5Lj̒cE5.+,/1/*&#!  ',..-08HazlZKB><830.-+$  % %*-./-( (8LgՙfF930-.,,($"!#%')),3Fc{gWH>841.+**'     %)++*'$ E +:KbΔ`B73210.-44,%"! "%&&(/A]{ubRE=50,(%$$     !$'(('%" H&0=J[uԸV9/-/1/+3@<0&"! "%&%(.I?3)#!$%'()(),6DTdkgZOJC91)$!       &'&(('#" (  &1;DLRXbnz~oW;*%'+0,0BC<4+%()-/12/,,06>FKKFCB>5,'#    f #'%&)(#   ".=FMSY`c`_ZQC4,,/363:?;62+-29AHMKID:3-,+,.3557:80(%!      !#$')&  L %6HPTZcllcVIA:79=AFHIJF?945FLNRX[\\buwuzyoilmkbP?5+# !   F   %*/4::>BDDBK^p|~wlcahqupgb`_^YM/"    &..& !    $!'05(    * "%$%())-28?DDBA>93(    $3??5'         #$#"$#"$%(-2 320+#     )8@>4#         " "!%&(**)%   ,9>:/ C      "! !  #%#  +672%     "$%#" 3!   './'       %  #$$#     !&%     -  "$#            !  !                           %*)"   %       !!#+22+  !        1;81)$'.55-       )>IG=/'&*0/&          )=FE:+# "$"    $$  "065+!    "!   #!                                                       %%!     !&()&"      #&*+*'#   ! #'),*&!    "%'(%    "#"        !          !" #%#  ! ! "   $**%    !$%'($ #*.,$ #(*-.)%  $+/,# %+/32,+./) %*.)  '-474/4-(  &**$   (0784//10(    ! "!#'(%   (0662-*(%  !# $%!!$%#   &-21-(#   !"$ " "  "'*)&!    "!  !!                                                                                              &                                             $         * ? C@LX:Cp V1\Ep:jc!(C95FcƎg*=P$*zZ+ɺ<,&@ R&$z?+Mb3D|~<V=L7,1|ڙJmz<)k R[;P ; ; '3<ݷOKHyKM(Ӵ2ˀ<1<7yIև-[.dBVu_u<͙TG3PgڎYE~DW'#o/Mt5 7Lnwp۶QH3.{ =ֿ3]# Ir@2b*x?4"> 2** EO 5XSĻ@ᲊԶ-g껇 #6%Ni :f K?DEZ:\uMC|%?BR(ۍ1%DUFY0CO`MCnZr a? Cܘ$3JV .q(x%~ 2nCZo$;sStw0VXJ% ɿ7%XMK29boա^ن]< T,7 IԠS4=ƥ4Ԝjv؈J y )?Z|z%Ŏ7c{e %M(SݰHuB ]mJy*KD"#R? ъ28I}QQs(^xP ,წYՂ=ֳao :k2kUB|'Ej7%'ѹn JFY̌=9Er~t·>^ʸÍ(%n$DPb?(պC4~q'HI4zxd2PbefP/F,ݮ C m牺ƳZYm1RhNv+{lـsi׶ xFoŝpssV7D P1ʕ *&ND0FjV&_ݸiV+Jreg!:gt3 EYKM0/6bNo9\d`sC} ?~L{gl+wW[sLJݲaGSE 'E4TOr4y\[u\oE!>>d~ME{DӤFe ;re^nFJQ.CoXT@Dv{L]EKI*OgЧ {BFXSHTFXQ'vwj6OdLe{lD k0%@k쨼cnXL#nw0zDe8q."rꙇ CQ GaQ,勇.ud P>+sBl̄ɾ άFoe1ckMH4L ${gPct%pQ)Hd@}Ob1((eP'&RdLH#訍E'bxw+Pd fg!q+`}窒lLzz6$(HG#(BGDrBedXe%.TJ,7O.>(XؘH8`MJR瘽O'!!DGxØn(wdLŤ 8cCu% 3fÓ$8oDg bǥbvf" vb*BHɀsGDrSJ<*f(_qLB!$"nb(EXƄFot@ve4Z#nNVU4oɦ+MKQQQ(aIn&y0ʜO4Rt1kج y`hn""XTLP$LOe}MbeПtTF5-J_hbngb@!&BEJ&@Onv$zBp -KvǬzdk8{&|L 2G%^VFY!e8ADob7E:THPEM|çR2hZu(Ro HQ'yK4=I%TZޡ8,BLRiHBS Eo pgeyF}LE#LFE&OD#"jf%D}FPvF\A# b!; 0vPRgnRh:CX}YͨFwM#De@Re2b'v%o2wRrDt;Szϋ\ 4yGX]Q<%ŭć1X-$e$gP+ R$d>T "3]Qt#"*dOն(M^b?<gbBn_gw$bK@/A Fi斒K{f|z znXD@sK*& Ȩ{#Dǀwpx1pzE̜2*VYCk\1fMFkJfe{bSKXWV%SMkzP" VePtAHUC{в(k>Tf>,22kn]洊0ORNtP0orHԲRM$$Dwd$v]L Z*dLcւuO-@U6 8Lt~0:f%T~ nsM'W7rJ,"MGr\YƸZ嬛IHl<E$kk>ws):䌁#w2#q ĺIDLS3LbtwhJnNn^#c!%MFѪ#4<-aOo Qo WVǧfFČP5DFm"8OPX]Db3Ne5]ȢSG{ǼlkMn:e*=Yd~bRfZ`XxpX*# "lmxxpfQ227gtx?Kc.y]NVGrkG#'*tNf;le['\ tt:~eN[UQ9b*dL ,CX{Lbz&KbEc/cz}Pox%ꆣ6Cyk1,NLL5UeXqoǀBM&Xn$LTD >D#80NHb}P}NOM+v&sM.b4Dg_O:O&On{hF5ǩ@xt-bOaTǶ')c"G"fP%Dpeш#D@f."xH 4P%E.B a"v9YFƆlb>'=ŭfk"L&w,k##o\2A:ǽHDG(:ZummF,qDu[C5QB&O4evvPNqq$Tq$ReDxФbf&|KbDb!'ѡRf$%fvvCc6F"ejd8d,owfm<3nFQ,.X d=(Y_%C poT'IH}bJ!(hq%{јTgd 9z=G?kB:+g P;<*ŴC5Cຳ- A.El(7P, J.ck1C7Hq#EDь"0l)P27/GG5@/ o(P+ҏ[6MZ-!HS!T[*cQ2c BN3ԓ$MNQNӓóƐQciVV36c{ H0<%1\>DtЁ J>J/J[Goy(gs\=(2N&[*-pb@MC,50S}/ax ܸci`x"z!d &݂~>"!F(Eݙd) !ĴH)u48$-btoJ1C*˒{am;Sb1ɹհuWNPCdeL7m7tF yVE̞ZR~Lr};3D>-ܒ="*R<[ wЛvb+'SUBv ~JڄtWנwSi m&P_ n%Ǻ^;BɠQBtC '2(ʙKk mny; m ?tck@GhaL!@?kc̗`8$Gu@q:'Mz^RAGhT|9 V pe(3Z, {VO*1a bVLE`PG8f!6W*6Ɗ#K]X/PLq)&Sr]QK5^p$!UDUA^$ V Dư_ AGUWFĒj55ոJK/ݱ)=I=ɚ:p*5%Ƒ]1Q&8Pתgbq¡F-;YhG;[TIvX.*3TG TGzbPi <(&9gkNW \Zq=>Ŧc 5F1wKv35RBZu.&4_V}M u~2fP$PGNDȖ?I"vh?-2 ch+8hjS{K+qiNo*KZm­ǓHOT!qS %^ML!<^kN*-Yg1əb~y&K4jGId9:UFzMSD\ FΩ:i&mPp<)8\IɽnRs]|e *ꙮۈBpiTJ @!+Ƀ*u^5>n1%f:UQʦX-_%EUFrz'+LujVciq+5zDO3X9+v-X ~=!d"MԐ"KSf~Yz`,ڶWMxN^WW A.Ve_l|OrR|y]Z&7)[wͿ,bڂj -?o%ئ<`4U8LN|y A W mW|e+4h5qR"i&|^S%("Ey\5JNpS#\5jdN-lYЉ( -lǵ1#M BƑazLS$$%]#J DX5I=ȆFt k; }Rn!S QIHXΧjn'&_hO$hInVn \U +H9 Yy Nh2 Z՘'ޡhHA o ސ, bM TGQ?HRu թ 6¨Z``['#q ٘NV>!F&O-m1pLR4Ģ̣:ϭ_ ?U»D _~[RlEHL!! F$r<< D\=TItiAqr+y."HbNMa҉AMv)/oa/3yjps_K ؜TΜ17Rkm:GSa IdʮGHJ'B&_1[i!Fnɩ#3 \4o6(/7RC{4G~яțKq )[/9i-' \80$GYD(e q ' ┉b2Y#Ѩϭ1H!ȭ! '-KJ0ETu;j l4̾Kc2̱$ g

"˰IRb*`=r/Ԅ๱J”z(Ib):STŽ#<ު5-d䦘yEjPuLj+s<<6ސ9``:v{vj^=#ͳ'#Sm9kkdEGe3.JO1,PJt!UTJ"HtR,]u]V5uOSS_>7vkQRıV'yzG*ۂ<^T1, 6[9Ɲ'_ y3UL\߉}hLu=O^f," 0ɶ&ŖbfWrF9׾G(Vi@9)Ü9QU!C2]!S)fZZmy^G+%` d`-L*t])` ئT Ř4&+et d&]"l3W^0Z<+4lMڱg$[Zy6ĵ:&P&uۻy@+575 ^lY6gJrMbVmN :aLmHFai$ȩE)RäSŭe̋\rDPfOte݀E'HLG1&e3́M|/N,>FY*PO±L9ڐqmE!*YOM#(25fmqTs-`_Utsl]2WR`O&19!9-qǸ3j/P:KDv#-E+x]pB*jk.I&FɌ?*ebkbzLr93# n&6ujVq5t( ZnDށ>(2 -&"hJ&a_V\{'cW&cCM\&+S`b *fM wQOdhzlw hE;]C!09y⵬u mE$/yҽuGct6,l$>$ClQ̐ Mw#Vr21 ҴfP7*_* BaH,dDɗ&"fYNsLNR1oV2\KP^.kEE@txBhZȸ'ZpU#$KJ0fS tߥ3,9ctSPB㋪,$ʂd0bDu 4jMcjbL [C_ҍ"@&L=I^;A,"hbLV&MFS} M?l0EΫ|b\BKޣ<9&]*>ebS0ÈSrE^e`.HŠ$b$TbBQLx)\o"0o6Z̈ $lDʄO?<,c &o(&k' f@$q@>F8Ճqfo%8LlC^6(1mSݥpv?j8<>m0|b*!$[EB`KsS"9LN"TqLJ!EG0bk$3) A1B% kFsdp2&/6^vUH.߉`PKg^M"Fwr(PVG uBbHV&,k\ocBSn=O)nu&SI&RuJR7$8S"w|Ql!0* B`?r#Z-2&̲G|q"\f ,$-$Ͼ"^l2&,V%9,^r-*Eߍ߇^Hlu3"hS,nvo1%ZE#znh7M|9jV\n(m]3&OxrjVSjCrSLV1kAڙNB0+Fu tF( $hBc2l^8(m-b)$\,P PJtCBH(4$0BSbn\k-569/bWUfHB6`%D1fK=|OQI[FDZc~2:Md(rGq0"1FEU+fP>5; p`#t^t8:.elH&b%8}cB34o%ğF)ZѢ/Bx8,pBS@^ *$.#oEF4$/X$& 3"wZfOZæ\nGI.^/ ٭s 8Ţh$XÞ1b8ɌHIpFV

ikV^fC(dYrV=J0koi:&d5VYVZC@`$6 63%LLO.bℊu uce#tφIC m8R+4&-)IVc2C&3E0l¸^s#0hE ZdDb-EEbrGnQ˹fR F0VPTUSiߘ&^"v`J%W?0d"b.>p7c*dE =:4:BjC[uihV*f"bD)C|p$,$>*pV \V)eİ^&U>. "2‚!_3,ZLdq$&-ElCrDEDe9DgPBqŤSp |)(,&n)uoƼ磧JM\Vttz7LWwntY\ &LJuRߏ,,1B,9HGHtK rE"h?"V7"qƼ Vj{6u{b b4Niq ndʃS03(21 \xk.61ؾ0) 1t#bC'}(?+KdvFP1Ik*n e6\qD6'lB"^sB&po֚o%fT#bP^z6&),Ӣfk20ۖC^g$ƥJFSxԤlYy%0&kUnz+LL0? Jd&$ up yg 뺻[$ip˝cS83 8++40qN\"@{$4)?EPU?Qd]lJ%UWeIdpڎr h0SCI]D:c3*CP"Tom]IA:'2@39ÌljIpS6^P-,*V"J1g%VA+^5 NZY8&$j!ƒؘ]ԈPx!Tv9BI)pqe gZLkuJx#&rDҗ[) g%"Z٘pkO6F1̊hO)g$Y5ߎؤ"U-O"zR5/)CqkFBCK "Щʜ PODg&.N8*l9b)k+T$)llZM"J&e$Υw/mjVb4o>p2/2Afr)ynfX&6ek$b3 *ο\20A6JE"y "#+:RIlQx'`()TC\egS"Hsb]P?Aܝ^?̒~a/<30N\V?7"%YrP*iEP4Vza͝s?6;+y/-iOg#ljq"9$ҩC}~f3Qj\/?;ZV,n0Ǜ;)6=5P0k4y=oݢ??MI1ljn#B g >o 4 7#[V;K0`" 1 cG"+J7 8-KKJֹ FSK.0TY Y4Tsq=+ͳy<L7y/ !w'G϶C4Z<ʻ_[(bQ9w6D\1GոbJ%D}dfR[>CQo ǹF< ?xz)GA嚸Sqѷ,{ Lac-SsJ8rĚle,J_07*W "G')"Yaph4Val.fJiLml̯ ],L&WsM)x5`]!6dX4/3-UF<ʾW+Z"Wyv%T$":U̙hwHϫ%DkKL6xa>/̃/v(dVl6*E(~JH1x0oر6ZjRo$lZJm5\%ٿVkMj_i\>~4R%Df$ҠDb#tVm2ԺXS( N:?.̝TPEzQƈrU+&Z:`]˺ĕ0CW w^V,Y(c&CTr!IiIZ;GDa ifU]ie1%)sj"}lڇ唰6 Aw؜*%Kh!/ͪXUL rU_.tKŲL`&o [0@YnUʼc,j̉uf(VUS/CT?& s sFۡ$SK؜!}-9+}oo.MgEoϭL_hMǼ#92zO-AqZ>>4 A:>PXq\W'woWmbj_\jwYFUM7=xkQ 0$k57U k/e1kD25nw“9Id>Y}oK;e1˭I~%e)c~k}2ت6_J%TTRK7Y8!󦼹 26SO=sPweq&Tɥ7 벌kJ -+:&r:⾰jLI.`2Y90Z}0G+ 'ɠJ hbh,ۑht!'R jԺ)oli ^9 *A8Aи+KQ񖂢BѼ`C31ѻ#CED3ƁTE;XDY bҙIU2kK41R bD:L9ћ;0[*q20鞤G :;xɞbDck;iX20'$:\8B8FLȸp&ؚT0 Ydxߦ@ ) AU ^4/X'L> Ӡ;-*vzf1OGIO):y'qoz[p$ Yh%Y9Os HJS)f*tua^y A̎ڻk!)/28c-[ ᣧ)L. < ǜpJHLe;=Ɂ-H͇|?ّ̢n脮ZaKy 4 pHy ߖJ֒jy& É79^0YY9lӅᛍܿ(@-ksa, _CI$y$译Iô8!8 "Ɨ Tm 9OYRP1+L̵ɘzѝcG9PXzÍaQh?)p q*8៚ ߠvJ ruKخ>2 G(# xJQ6,!9ON@A䝱hHfiQr @ ;p `6X;B iэXؤLIδ6!>t_ѥ Uh[ƳDLB_;3CM*Ĉ=ĄF-*20񖘒QZo@()a_ 1pȬtJY䰁cԕA2pэppI`ީUW0xō{@ hW B* z)I)ɩA ] > yPA3T u\Lŗ >!8jm:)P05w@*H^}:iot9i2߬K(b"V X:9CցIqp(1\QM:ޙbމM^h6 ܐ 6[hM jmU.D%ٕԥmĜJHCPdQ񗴶 1U3o w-* u1p -_. 5<[diћqU% F y)|"ұY2‵hрp`H I G[АkΡɦT(e1K C"I$і)e鑷㈬8@ߖ- rSG)ŽJKZ+0l }0ZKR҂9@D1 a2y$k'~A~=ط[K(/i ^\qx6[^8ikC~D/V U5 H fn k\Yձ$Ke:(HUĔЁ}R]huT"dc bѠ cHm9MKԼ­dwHȕK'ԮL ፐhuޡz#- Z.m CX<0=YiJ&]ζ -+KzD^8٠Nv-4Vq/(:O |>\ ymAuYTُYXy1۸*͖L荡0\먔7vh(p.'27H sm Y2qFvѸ⛋ q"jKE[I@ܔӉfBlΌd_)&EOjt_CTH DMi8Pܼ#Ʀ j#;&a>qCeu]D:KuntPPFT*tan` jɑ0ٺ*S BwBѢ0܏1"ȷd&N;Wظ,`~z:XV `O?P|,_Z%Z?tO*OU#?UU0_lOՕ!?Ķnj .OESJAiS_%,# ^6{?ʹ70fq3Vc5D28ѽ~?:$"x6Z-$;n_Sng<&\^ss;0fLc-ͯOFzb.j?=iՠ~;#447Z A6C F+C'ʰlT⢺-d1ӭ3qd.%Ic;2)lX% rj|'F.m '3I%M7<0LS+)m?+YA% Iч[G$t#I4̜/͂Q%=2C/PӔW8 խ7VRZ&PST41,:R >OD1C?7ߎ+<6c5mRF1\%Ŋj'xe9gB)d/Wl])l8 (ťgVGMcd>_=EdJZ~ym$<  :: I"MF\TD(yjȃaU#k@'Oд8MYЕ7.I=RɊNbt.\兞flءBZ=7pt:.e! 2b&b|_[@)-FdU}rpEC,0vq? VSMo/}y!XQqٞi&cDNךV"r jCҨU0*eD t.'ڠ"jd5Թ;Vm(BڠCj^;74VD2,!ؽ٬>pnμ&beND&j~Fɂ_3dr5XH1ڗBO=ֆaZͪ?|X4x_\"+lwX"H"&C\jɽɴf`]_V[9JCz*W#us$:c^!䑲s,|zvwJx2P\qI+d1GÜ{ALEbAoJ(| պKQ' j"~B(S]9IͩfRbi]zZ!*[u]򺡵}P%~Pr)z[Yvi5iKgכtTn"J͛ fij=J SB$6ka ȊcsmLm Y%V Fb pӢj`ceQzKjU&~cfb:d*1B'>.\ p^b 7K"͖vl(!.d:,4pt!t4{ftDyk%嘍Hx >,!B$lo|C&}OFgx]fP>K<$g&f3(脰^Vn$U}R\jX"jhO앮n`bΔ%ELĩE(RQOmꆨj~GVVĀCF|(D"p0b8R( d6gJ$g&`"j#*졂FdHbZGeCyd1#m>p'<.8ңf1r5#yz`n*faiqDLQ$^EfmPLJ ؆3D}VOEX^@U0I:`H$AY}bF"9Bu'`p+eDAgd+@$(tg&ri#$42Z6"|C bAq>.&x|BF$')C\({#Bb^$ q4&3F%FoĐqZ1^CV4,MW2!l-!" ML؋@BUW# ^Z˄5E<ߣ Єg c(K|08 Ae/'ti.%DJen#&$}BXxAJN4-<ox.$p'd)nj5({)#nho#h'VfLj1&!¹dW22 (G"9`{#/hAme7r'h9cTd3MV Xڄ)@ynN &4$_S"r $Wb}A@~Cm)db4&37O%"@`F`:$fT'Ecz9v\  l!oǖtf!j؅A#ttN._$'nR&;n )B;M,`$4:mԁKZLҧԁr RnW, kQ˪lS10Bt#fhxS5<Հ!&ril*6golbl66oL9m@6;ABf'FD:I -ͯ@D )y|c4ʠe-gfV#nB*aBQ0,U#1tD5;7"!]N;7[6zU$q>Nxa0/;WYDsPrcm&"$m trai@b6"jC fbfTb [B;#zeG\(!AN$3„(pxON#j3G6#l9(Υl|a5$ۂaJR-T/Njԅ@k-U.^`OC#;xxwm6ܿK"@なxپGJb-mqntopAzhy@Ma}, xԂRCM];,sHi9TAKQ(qSZ?3rZWu= O4-h"BT;F\vl"0RX#8D¹*¤Z$2+ZB%=:ONSՀoaز|W yF1:U X"c]ykt +!摍F)b]ic\6~-gǙ : 03W)#krZ?uP5>pNOCpZoq\sg;y._DtoxgȻ\fogYq4\.⹰w:OuvhsW4o]+̢,}wXڏR*(T*,%4` uҟ$#vF *PX J)?e,;j,AE{PRt]sqFc3h?|[>iI q"e^C!B]We nFA{DjC1F -`6rE8#g)1fv~e.PAc)y͖8"` Ieܼ4Hqpأt/Z8c t'*?N(3 lY)5Oy;Q=s܊ 3NlPԈ8ࢊKMNf;?g,<@ ᳖{-^tn-,?UN;4TL>[ l}.~-f& %G,'tORi ckJTR?[DF  n:%Usj]O5ðEXP**GF"Q4)8W|phI%%\Di =5ř9#lt %Gz*NZ=#-ztRJ蔤fJS#\QxVPBr_hC|dUg ovQʥpM;$ >ES{E|㱴NQvNi 4|WPӇF$Q>LY؟@kY6&o#h!|$y$ش.6URQ,|Lފڲ»*˪MXx$)!? aN/ε5jhc ̒d}Yɓe;7׺ܨY:QZh:D|w BnZq@1Gδh[ v,O> JhY|q W(dk)v0xˢ^fz)W+\maU(xq39]|S#K6ixa‚@ֶD$6ʖjg~:,@z[7۳nʇO rA9NQءz7c3wG(dl.ʩdٻl~P-{ܢ5Z0F#<#pt7 [)קt+)QZ)Hi SĹ&drZ2:Hk Y$c{ Q+ 2h$iݿ8p2$Ru=@RR(/Q/ðӒ|iiә yf$?)QE..Ij&d%猱Iy7(*^+#Yt2œ붚(" !Z=!0*7쟛̀I Ī!>?ͪ[H=,;ļKxdᲘ ҄*+50D+(uET RT&{fTyf8h؞q $H=21jUK')ذAJ>#@z( :!º+HqtIBZZ++9dA@Xį,^8Y{ep0BQa b‰/ʃ ;Џ19y'Q0ԟ"0Dab9ݨfK (eIƤj@:SI%$H ϔ+Q\)DA^D 5"J <9qa:3^.ʙڱTQa4ͼh"U 6Z:ٓ7✜jSpIjOO ̮$jE:F{1ƿCbkɓ$;I+Ced l~ trPְ5@%T T?yK@9|A(s%0ҁ*/{ t OTu"GٰD`E'ϸHڹJᆏjFjSxiC;&b;9 `M JdzH3+a=;(7;ab3LL@!7 %⥫ǫʵ Dp~2RµO*Y10@| JJU"x٣'r}q8dg< ` IU نjLke"ƙfh%51# t$pJf%#qBDA*((i0&L ;M׈EuRh_ ғ\ӗ6M3O vB(ݜ=Z/r DS{ۏ#a]1b,n提@ҀѰX)1< ҅Oj,Yd(a9 2j 5V!à :5K+BTza!¥!5!!NJڧ eQ0s+9VrͼMR:;&)M'aќ(N\ J^ᛐOhqSc^4f(عxKg~,b~*z9 ߚ,6F[pd)KAN;j) EI&JfжY[e`\fåT%A(/kd{,ru-؝S:(͞ #;Q-QRuZb}e9d`jȗ$RI(QF[Ijگl ``I˛ٽij@ N =DATH:eyL <YG/3|JZ2)(!9@)0;j1r?Bu0Q`NZR"( 'aj G8ꐑ-iw!5QYHc ʊp(kݑZx;^=+; M zH`^(&)5iOKа}✩^:3.嬿SHD :nA1:%T% 0R؃S@X):g+("bf*u6(Tb~'8ApzJZori@OgЇI$j"9v&Y$I8z&4 HK#bBĨĝ u/pIz0јYc8k|aalE6JQ JI±)rs %8ߖ}b~YQiRjf%F;Fy-q1&K~;W).Iy Z  n*+lWm<۹੡YZ n_YU¤ Ta|Q\Z $,b Y(hp Kv& g@613 ZH9Pod9&0E%T%l?$0E_聎D_C+e3?3w:t#O_C(iJ%_څ RQ w2*kVG Y_D^GU'DN{v>ZDbf.9w=cp؃Ed?͹|N,qh4X :!F]^2kinx=w?-X]˂\A_Ǡ_47_G+>'\r'->v`3E p]?7 !\% ?D ::o;ٿܷ['bgna/Fy_}&wYMNB_Wix_\ʑU:+ H =6*\ co-a,V kQrSi Z:6ذRX Q2c4±:b2(;Q˿yJ,#, !"!: ?c .Cur]k~,eXf?h 9ސ}84wʣSj@P^!I -%},T̥pA!x" CdVV6đڃPo Ÿ@tdcPXX+/G^ VPL/AN/H"oKhlTi.Fv}H6o]7dɍ+o2cfӆFUMwNIcD|氧4!LK.m!ΨBKO*@_S>UۥV!+7s& ^ԋ}҆Qikv+[`]aA54f9m~dӠ0~PӚuW E kޠLeM^p}="a 19bL!dNY{3F5 f>3H 7lKZZ~\4v"&6ŝVwncݞBEl9)tm_,1Q:'Ih6@.-i; ̣&mOh`]>I 1.xHU|m7amHoݱDtO |B=vz4l%nR*ØezSUHMj.rn,v>ehM'QF 6#zq9.a̹5 c\-핻&N{G&U$&ADiiƔ4" poLrh p{V8:iRD^pʮ#4=3 =bל=*{P 8TgKj8iU*B!#ȵ- s7"$2utxaY `tȷDLy1YiyZM6TV7zmcwΌ"c/1Ԏ08򺮘8y$_PWI4.P~myyګ9isg25 =|Z27G_O 3\SqVGvE|1vMDG;0J?u>=trqR`Bl~U2g~ɣ;~mK>r&DmiA&_ {HV $&wܦN/$PȒMj]ԇBeN"җ(cr"N&~:@i~gFpfvcbb2dLn$0+b\),riT+r&J#) `"f$c+"rhd 1)r1 =E(q#89'4!p~pɣbwf:4JI札K<¶٤HFJ̻0Uc%&>&c4:+<(4&iqt(PiSIr'm HoC[lb4:HI,$P!F3L'D ? }͂ƀbso #srl2$ih"2Ck(mf¶f\ԇ1lIbmDi (>ɢ% ʫ6mʼe4FR&HKr i"~jt,D c#">tƁG}L\/ &ɵgiFgie@Hfr2C@%´ZCxxI,Ж9xr&ri!(yh0-+emƝjH>^i0Q"T)ɌmŎ\$ɢcbIr\ԭJi%-rEN/|Z,Q`4Ph&{i._4ig[@ZkMfzh,TMB8dDŽCP~͂ ^D@}$d[ɾXj삫F+,gh\-ܑ^8Fܬ3bR\*$mfN-+^!Dx\&hD@$lƁ8/&DitJ!O$i3uT|#%cDZE,6)l623e'&FmgF(|gXF ,b'I^7¡cc66ɺ~rN:]YSE4/.2"lJn(H)bi\PDJl-3N$ơ쥔*)Ŏbmd!MVʒL +%2NL[0\t\e|ʤ3xyn1r\>&tGLf(kLFÒĢ&3© `N0%Ok<.SH\ڍR&mJɢivnXc1(cQ*1ŐYTjORdF-M8%SDO4%D0?3(JB,jB6{l`bHsW%nmg mi,*HR,y~xKLyDHITdž*`mh+h*hDlN/2N8TvF)Tи3+'gLjZ JxX,E5+֧%h^h*\lKe"*+)j`Oem_L`||ƣ}+#FUHc*h 9),|~sb!&qGDbw^ HB2rCLqVDLqI&[\3xx(1MB c?j@'x"rrg?bd&" miE4o iOVTIs7Nbږp>!(%iSHr1.JN䲚)/E(t %\7i p'"o([)[bg/"̀fₛ`ijFYf@&LA@ C?&}HIy|( ,E)Ϝ":x" ~ixogk)f,`%b$HX%ꪚ(‚m b)j+'rkż B>ǒ4yZljy|z+M(̉D\8.@(vfCldǐ3qIy܍$lTr,(Xb0ҞctOJ0:a+c0tW}Fc^4GD)V>4G&}›M{Y$'%=mEجِF:XihrH%8/)TA'>*u*{ Tj+h5䒩b*`n%ύTyYVRBDox `m#l(-+ xmd9h(ribj Tgfgr<"`t |*ے++c*Igeؑ!SEJpE #jJF-(( 삦 bqDc"\($m*Pɣ vYOF-b۵Ŝ~s j!z)HH[x@6;ȶLwLJw㒵xdU(\' #+c̣ (x3 4KLi|Lr͢ZN\$0r| ^8Z^f'q!XCE9T+ K)`%;@>hUpIuOJ%8O{dPP',%(4ɣbYvmqFyo.\Ru%<-4,OsTI:c'kK<KfD+ic/'ja18Jb8'AMY!<-gė*jbLHu(&[&d7 #Cbm}uB_H&+ 7.^ aH6#piyK(*/"$F'qwvm0Jgh0xz'dkzpfE)Cxrn03<Ԭ"2ȓ!{rLF'엄C+2#8g9'E&@HYݱgiN$MY#DX`9'xbGo$ȓb|b<?pWBXt T?qW0?ȟW@ A']<o B?wFEDaEn!Q0!Gc ᔆ1j+I(FQÈ%!˧0l>\0 Gz!JzN,C F!qDK Z2;m+@0J8e6-7m &T,  =IpQMSÄ!`0U`2fR㹴 n#J4cf4ꜯ@ܩ0$jq$^'#5sf]ɽ2 = p?*,s PivngLS%)OS5w 'SP6Cos!q *z2=])Js?µ`{uk6*Em7%͝㶽 ԵxKjۻl_VcRxZ6馃ѻ2c qouBoVj/51eh8gIYbS/K]N@)JO;BO7EGPxN~qz0$ $$_ |p' ok"Epum|saxKn9^&~R^唢≞Bi^ +';B 4$TAF* 5]Yi03vջSn #Ρ2='Ssm@bP!b-T0έv&"<\q ⚚1!2T*^D VQ 8d,]Xbے8;t`{p.|;lu 9}Y7>ܱZMnyIM;RJY-"PiSo5@?)S4i$ | B kH Ah<߻Э=T` uD? W| SN "M϶Ta0*4—sMj #Q,$`ܼ@G4nFh,K^}!߇Q8R*<H?ąlZ)FeCSYzYfS^!'$ ) /d\11MDz>tl{ytY+'*3e0vԛlld[Ď6a1[hM1۸ ȉj ɬڄ֢o"[$q9*ۣe5-}7P޹\*D4CmO v2S\[w۲szXnZf *^R]T:>oM&քRru@VYRѓ,UNM{3WHU, * ttٶ(HogՂ }G&bN7#ՏPOe'9j}H2H;S:ZYgJқ5ܚ"Ho*,>3GS>tYjJ]hFkw'^8-*ZkB!?>lȅv,8]4|m ̓UbE$uqAKК""S<n)mmK,cdaT7PMsep޿ E t^YCAm5(=2W:NerjAа%Q H`Jާwzt <{@x?G^TzGkK`șߌ$"6o3#hj  ORU2[L l I$@ r).С[i8] 5 ݚ"Uޣ2[#S { a8h s U(IY%T' |?sۍ)y J-9qѕ!- g18,oq!r#>: *9 "=Diﻣջͼ{8A< +Cġ#s˸;M` "3 pܳȫ NG4).3﫛@!Q̉%;J M"DjsM)sϨz[햁PLѢ:Y JU4ZMr飯T~ݥ9\ [ޘZtN'L1PK.2 㥏O 'p{іqhC˥(˕ h g-ᤡ-x>h ig"U!᧔9٧!8񶰨$B葥D!䙋3y YO#0!D0*>"Y:3S  JMA'њ$P d$ J 2嗢CSժQ*ϒT իAi*:D sM^ͅU VDMK9̒;2 +l)RSM2.=[93F "2Cϕ n[xKj.!wf [xOZ1&ZeqBYY/ݜ O K0̆'SO1"6t p  qώ)K0-`Q -9:Q QBp UyR-] P࠸<~ɨJ;e t1" !˼R0[y" t3'w}WQIU'U ]LԛM(IϹ۝I?Y@!-٦/) ҧ*q=tE F(UL@ V+ĉ"< pmh; E]*DQ]]VVLKN!+l)(^EVMb*2s?2XD>SȋԝK+M*䴌K,Qњ$9oٛěCP%p(IK`OYF󢑦I#"s#opU%5Qs&m RZ/0b\"N rqԈS~g$ok[P2o!R#姉 OҡmaL(7;|5($њ"[}M+}1dE{ MMI'b!ԍ񽑺kEթ Y绢=]\` eސM=1j4q*s@^@ =d]Uhf=eNQs;r]=+s, C?' '!QM]C5}̋`(IѠ;իBZpƢD$P1"=ݤBU:Hޖ. )$P˜"Y1ttenIʈp$8-$B>QL8 Ï8ZRb`ax8"U$c5 QFP`Ѥ9k#3/hٱZ:[hjZdZa] נ˜Ϩ@lAN$$"' Oܠ;z 5 t{BU'JOI24]"*z);IMnU⹲vX@Va3oVNE]<@fn**E4M 4.+rߙ"2< 4!"T+C@U: #P(}*;'L5Ĩ"ܣ :[M' M)*ZL!(y}= j)tYbOƔkq!g#N ԥQg+[ >#O: 9τ{@xᘖ(z{-ۑ I#g;P(~@AKy[ &Y(ff[҈>/C!{虜!P~"][ޔQm7 @(yOw Vy(1w)^ .=s,Q *:*;EUwq2~NK@+!E Dk, 2rLǪv^p<qcِ< ,W5) ,R14ch4X`O]?0,D_Ov97_#'O,Z?7l=N_y?eW;)O5v?FAL?ʵ|Ŀ_P v7eOMqS1t?W _& 6<]OQj?͹7-ٰGXcS\Al_蝣O6 ׍r;i2y qíC]CN\5e}c`>|ޝDȦS_дcՌ Իi *1zN0Jh pt22LKA[ENLCj* 5$s 5A1 rAL$:Ih<Dz.P?0*0!z(IMA736ΡL9qA IQoG$ qB`YAPHZϡ4CQӀ7UX6Չև+[-u4MA|#jA-yO6MFiZ9ڕjEۇoY1]cuMC:N^hU<$nX)H$ XpB"4-5xOWc8ؗM2lL.Dxm`[ώSҜ )Gb X1 t!@,VZ]ث:䆽1T[-.jؐGD?@nD8L!HMFȨ92SݛoɈ<Ξ8Y7 77œpRf4D>foF:+rH[#PA0[Rz4u/>,B fH'1mb$I)$5II9PO>)pLIr [-ը dp_h*^ʉDX=Od{ex?)R (D U UhjYx}Uzńl!0v^d]@XPQlŰ5 ֔1\.޻Z(FHE8?|y+EqüM  ) u8jMkRDF.~ !?ow0 9v9$nyM0I4 ̌Cx9|+:!I1ԼsMź:펃5(C~yNmqn*q!ρ2W%^qD.zq+i 6D2$'uNtOe $ދi"GQCFI3pg)! nl(icp&G,>'tJVD.cb\p$FrvHN:='zh)>C䄹A'Idh&el*$J1n90>@l'Ɠvb{:n~̊*,@b\Kl 1XZEץز](P(R͢`bꌍN޸ i/`+ aQrXoReFR* ^M][̊OVphvcaIZ^M(ίRzs #fdl07Ap(# к9t@KH{GA&ˌ@gĤR\-&+28 ¦~2qHFАR'(i;x-b.g?is%$+a+2+_,"6cj̉]- I~%l @i>wP> lJCXpll3&C" .ĢVtA0G' VVl. 8#:@8 >G'/n5B~Q4CJDC:8:r:#l~lpZOxQeqZ1nR -\KcӒd س_%̯hke d ch^I҈ҍhf[[9NH A!|@(!, j& &ͦ E #rm'i XvɖC#lIZ$IG1ݎؒN+k!&n/^8\a,=+a+RHI ^FƐg*X%wFB8K_")&rt&6 'f~OBJL-g O"o,'v#(?)"Pt82kn< ,N?f/)?$~25l$w.HP1B2'Z'nZYK&*$XCW@ D1h>u҉1a/-D]J4Weh_`f=|eJQBO F h^_D[hEEwN(av=1B+QqI.Eh/&/x _&<`@Hi!݉Mw:i&zl0P4w&D@gJIlς7!$$䚓&,l#*c_ON572'9crBJG^䣾K<~N8o6l4l)g'h:w)4>5 \j40œoz&@\roq#.l87#/'x 6Ir#~Κ%d:R20K Wftt2*2-\v$W0,w76\@䄜'Kv "i$ҍae>ґ_e^`Ȫb]- FyRm\C:1ج-:[caҸpTVދدt\HtLtAKHN{T~% ._(\֞B&BK)z5@l4 qDu&jM mņOT~rNot\ЉN0@F4*b6,sJ=Ṿ?n+47UˆuBqאA9 fǢT@/)&ZG'mvvh6V6P]-9qqm?g/_&+| q a9RMTGE]>ҔB !(ɃEHEd[>VQc.QQjOMK j%ȴOK{lߢ7ZR^Kv! !D$BHl'{<1&k.~: 1͡Z8o''k֜7Wl'rvpP9/mP (G&d,0ZszԠD)!L"0CiP:B~ lɃg;,=<㮘Q"i)F$yQlqS䤧Wt IE;:V=8P< 1Aj)vu"h$sXɢG*0Cڼs}E6Ccǹ wLhc`eS:e (=ȃњ]LM@MP=]+ݒ` %\vzdȸB|^"*Obl+ͪLzrhF½tJ~@&ud<op4◎o# -gu#^:fJ]jp1GPh'm@[biz=qn:8+wc@IJ5rb:$穙s>yF*==.R9' m]ۻW} JJ<WJʿeڲ MheN‰c`%Ү2TEh a(?r( 7I?RvYE?ӗx%OEi-cQ%ʓUm3O5?E:˓uo?̸4a\S(jsdA2MrR07H):N4>O/8T@V5P|G' DƴRܵ*T&g/M:?To3нll?%s%Sd3VR5#"ֳAS5j1PCZנi.+kZ6{mYրio²ArjҸ*BM!%&`:#L hYawTҴR ~ ײFP"diu|'Gd5+f~8,rNma?G1"hg'^6d$&.¦[&Dzֶ[fYu\fe^f!}^v>g>$~d?bsOA§2|g(㠄X.5AwazVO*Au,H$X^bP qtW:hnsn3oYc%ɽ&,o4qu2:&T[UjfG6O$[sqqGYdHY" qpҕo!׼WI ۜe,0䤴+ [LY"f:̍"g4G 64:dLV,may˹ܣܟkz8LQBsyQF)]ÏI]65OtN4`EqY;A{<7qGJӞ p=y3n%mɟL6A"p"JeKu9o]T Y-ibaݖ3+%ݺY{!ոʛ[ g+{{1a3AA(e ,w&j&屙e+_ǻj/UBHڅ VƘ*OSrxwSI:8uH{D(Sl\D&,u/JzH3o\k{,8Lu[CO؈Ej,cbd2) =+M`LPVTX*E=G4U1jF !eP="M@zz8B[U)-V(d]Ku$:򠂑t-'O :gjK(EжRryc%|{2JV0+/̜ b`6oBun 3+z+0KL޲eJw/oH9wʹx. 31M7Un2q̫_Se{325ЉT*&EeI]-R)jI0cMW\VT8T53BTb ,%5ϋ(p(UP *|6,+%g|s"ŏ:L_zyBHۚVl%K*>4XGAeH N"ײPA?~}G3F)*z\aSH-^q_[]/}gހ3"(z̚_8ӈ{rdót<#q?Jv&cz/zV8Jf' 皒bf@J'*<-.b)J緫Q% %Kuqˠ0)'=.[()L*߲QJ c IA*Զ*HJ{(R2Lø=LC,37 *^ 1a"HT;)*3MČ>C;S,s;,(Za!a"y!6y<B-RJ 2(?",FIyA!b(ӣ 14S;|d  hEXpZ Ţ Z);Ö dr  * YU !ZyBa*.Z䦡ΥjW LB0Jv'#لK !9ଷX.ˏ%-f.ZIoɌa.{%z ra8K( &뙥bJ_ 9f'b<.I 0S;S%>:V -i`“DYZ),yLP̈DL(8A) ͟Z!;CkMLLԎ1N3퍺=XFSfWP,(SӋR."\A- WB 6=| "-SF"(ϱFWFǟ9⻘Ⱦʟ[,J +:y*,1b|,i5 !11"俺6%ʉ}.T t3Z=d Af._܎*cJ_?&b="bT~7ԭ/J7ZV. 1QI~JleIHz qP1rv.IiBBLL:qղS:ͳ;SXaHGˈ)˙=8ȲTQ3(=̽\Q`Ryk e Yz QE:9G6!d"ܽ)Z*L`9E  +4hcER yԡyR:1l 'kߊyd, *l?-v/}.|-/`ȁ79IZ<0IP _b_R9Z8K(%I; )0cX }Aȸ7]f%ۏ[ +zV.ͯqծzqS9j-EAZӒBȿb Yz ƫ1ƨ}R )XSÔ8tƐ;; YP<Q?'Ň}\껀绰Ȟ9, 14(ZY!Q`I<* E4S&1ӣQŰ¼ۨ𼼱C6!CQV()%1cYGa?*L81@(c qD m ] gE+-:$%b߹AZ%)1'%Kt&ķ.]y}%be8Mm'fA['5(7207[~[ qoyB-֣B][р*rT V&cy:_f$=M*Ld(0y`\ Y @ͳ>%YS,2AMLV*Kר Аᾩ&E,2ʩ1L;XZ*IAVP 9*NsD:GaVbHnhLz"} (Ui 9R}HN q^M&WJԝJ.]'H<Dx2?\0 Z9t#As.\LI&e-a}0ԟ6ع27 7is/r؉k =rJJ)}/Yqjy〓b#l?­0Hب$ZldN6"Q5 ⠋LLed ԪDH ZVѝޒA"n) E-T)&fp Z(^!4Qd,{g$o{gi6:EXtgheY`ݡe(47k*Ϡݱ?!=1"`.S,]Y 8^Z1Z)%➅9 #tH7J?rTb#w > JV[3}"}{}RV := A0v',0 Ç]br)-6dȑ-֭"? f. "-Ý9Ӣ!A MȠw y; 먥 Y ]Syԕ`E:>_Vן:gTYː9I%ͳ%: _ ۼ,, + A15qpN1D(=gtO`b:hHAD9gXp*+4%i?ΰ$8`PH1 =G_: s?ϲy4+%?!_Y;͒S>CQ_*CVO(ji?ϕwҵ":6bfe6An72=?w"_CqqNE/?w4_Q4ج`Ue=9lZu~jw$?~7#:'yE?wkw{p&t4 wAk̛*UM#4Jӱmla $9| B% ? g B3[#{✀k⤐G|| +KG.d.KKMIrDMa ++*Y@9tZ·DU.] %9'j rFK RMQNꚫMyHtN*@(5PDmEѪEKGN\B-)ƪ d32J2U ·v5AP:T2WZȳLvU荣CE._2W`C4㴄8"^T0"-c&I}%P_A9fYgRzڡd+)MԉZZ47yJjU#`?bV-Cd&p>WdH\TֵuQn I! B;kFv ȲtNIQ@yu؟whM] /~"<%xpw\yܿC4pw\qqYWݿY޽~oq>{|)_')J5Ӥ7P PJ mWKr-"n +:YMRUX->'>ڞQ )MBW$hC"3:mmX] ZW˅xv|5bZ\L)(VIL=kpηgX35* eA2,lȄf# UIdAFR!(I&dL\KnFe&jHJ5-b[E.$s)\#,eȻ{Ig.s|]~Q8LisO{{.#aм΀Q(QvFA@w9P;_P*`PQ:<7:{m` RCrjOGcoҨ $(rtkXHɌ`>Q,!Veڰ}v-%SQ.4! tL pxK)ijX5x?2LȅDׅsZXFVX\ԫGe$ūp\-Qu%ȴ/ LҺXYFxK"[iV0oǽ_=rnjBJt^dža^ -as`A}]-$L'3[(rf%aFOjȄbZ|-&F. ֚ƬΪЛrD1".)+B['kL Z-ӍPIJfFufp(prQ?hn1a1 Ah%$pD-(H>gdD8,K3=2W&kZe|plJ jP}ZeIU%x %D*?cN.oϤ[J̚ ]Hq9P* ?]B7M3NC)^fAnuyqYRw" N>}R'i 91ǰNIS1@pDf!cfۚo3SdcLy$A({K E6 J|m-,oVNZ׮+rjָ%nUr_BQ3)-D'wZOS-as_݄BI^֚;bڄ4\m\ %$lgسCC EXƴf]TܗRhFe-vPDµ"dioU&>PzH4&hMmƴSJW&i+BE*.F  .4 Lܡrj@vy{?AcLDICq&c CF E"F D0Ÿ0 頌s$hꉮ@t'q|4\uFpɺ@nwI11 ̪(npJIН,B lf&,M$!2ϐQHXzƮe"OD+xmWH?b߂^hܮERPZgXlE4P螼`"hEƸUHx\lIiqBsn"NslF])ζeFlH|Tɘ$$g~hZ]-q"mHr'(>],ޯY%zRZ7\XL% DeT$"JhF,012R5g )g&ЦNNEGnPnh?@CgDwR2Ҡ ' {,pcf6+yqx6RFZ|'|Txri/Gcphr騝 B @i+Z޺",A6ϳh kp4zVNQDObXif~P\&#XO%\Q"bxl %芲+&΄ %P#ŌBXX'?%p6lFZ"r\+.Si$g ]3:ZhֶKP<\Ό!<撂FZkMDgLP>:!DЌf !1,?Gjp6k&E|1tMpS'\/L#&=:2c qҚnB|B˄|*yҼp|젤C*Fw2It0{ 5*V̚{ #b4rgcOZqt5jTq'qqn~IGd)P`3(Vu : +Z]be~U69%ȉp78%"ixM5y&%)&܌ O%FP3T"eBitT%~DOY+Lfk.'F6xi~*f^Y{*F~kQղ+|+g%t~*YVjdGP7sP%ѳ'%4egdO%U _b&#5uQl }T>y{Sd(y5i4*], - CGwI'R 瞧0r.1,7nl/$TV35gΛnS{vNAoj ħg&Lhl26pKH$lFRd\65Sբr"fhLR+" hIBliv@W&!g\e|J%j&F'\3=h'%m@.YK_PUkVRl+ocBblgx$}-kK )%ނMK)3YςTϾM;e6ZYK(-6|\~e$#Ƅ嶇ƴi0Xkļz.ƗD2n"rH)lJInV{j6t@ʣȁjꊕ\n闸ʹ HB!G5% &rW](!Cd&\FE"2,7+m$2"*Q\bPjU`SK-jsR'M鐒FԵC&H$&]'b,H$ivlhh%bli9B!bqTʇ@)3O2(,B,ͼEa!:Fa;Ko{°-gshH9ape9lVl)L,wG&rr*`/tBt5/θ=}CB4A`@q3*rΔ~J=ɨn @[2%Lɦ/v$560 @kW,SBꎨRSE(F +e h OH(\O23;QDe@"&&ZE6$7m;b=8h%Z\Eh-8"^^*>.e<+x\a#H${rdgbhKoB,]]fh$i1EKÈ^낂e);&I$gޱ?ZT5VoDU7VoR(]fk\.{lYOQ2LiW)x~Nus#2Q3 NCwVwuw19:?C V@rXIpqD6NcvDC$#0`47 @gBq(6U\ynz5iTFјgT'5ey"&̿Uxd|H!xz)krPzZ}ˤL"hVVPREą&g"]m9Pe+ Bl]U+*<X#ZHyf{Bi-TjL(-lQ&ۨ"fʵ,&ĐÃBe(jBJ\XLhgdŢSZ"yx:D"fZM %VjU*б%ikwOW6XݘaRƁUCW.n 6,w֝I0qG#Jy{ "{zwD#PU C ucr|xt34,͙SC?= $X@4lFP`ySo̤/\MYS:͝Ylg$F`>xg`+h& ( P'&e(䵴,,eSI~"\~h_PHke"&U,&=B߂s9ϰW?Hs]?ATi?`:L 9邀6P4 3:?t٬Q-]bPQ'5?6ZVm&SCͽ$=H%xL! H`4f7B?Ѹ؄Ia#YY.7& ш%D]vCj5d?\BS|9@0?}W3'v|򗟩s}~Ќ%@Yq"' .0ð7 prq4! @B#B",G CXq>!QQG"9,B? v!fZG`vն4nNk3Xu U9x5:xd;jZ8b@?0=X ~cq .i.^{9j:~gä֫|ጮ ZM;R)g1ahӑv]6qjXe9$Dco&۟6K6~)ۚ]R|/Lu3ݓ5pG P9&>Fa] ]*ͯrY6+Bp֩gL40Иdi+Fv Q>̜-ɑAq57sc_g9(?ܗsNqÙX7݉7N̖Ս-UF_njNC^_لe%ie-uKh=|h"opg$f[LG6#Rfo7yX^p6({rэ/8NO>\2m»DQS}hN,i< PUHxaPJA? 4&Ig , ?gbdL2AC xgR5FzԴbi" OD/U^0ҕ%T!OA&$r5VtʇK&] 0"% "eu)7^@m,pWCA*ג}Mƻ֫bJk+(m$pļ&|3cb 4VpMQ؎wCiC{ _[ˏ[ &yc*d~%XEh"d%M$+e/I)>(ǣ0i2X4,E$ qjyt^;qn1a8'u#ř'~(m%4E+gɶEaόmDFRK+a1awM z/-V)yÅ_me,9 Ul-_K8MUBC%ܖ\%Gh^$%&k4[]1񫅀K Ę>ʂkUwxt!dBZ !LϨ!!EOQh`a W#Gab{–W!U-*ڴ*w]"¬|C|z/E4JxnٛQm5ҵ X>!D(aa*k ђQZ_-a%bVȒB.$=i0QIbLIqFk$ bImĮkrIs6s%֖o7z7œ*IK i}_ي"_.}k] "ُI&̭IwK 0SA ŝ;~ ;0jJ?1MA[8s+c#!"!c˧c3C j1;pa>3B2"b?3 ;!c41j!7(s4= !>)?<"!7;[Π>D@Fj{+F<⒟[%E+E144"Z3$9Zca#ؕ ##T2yƢS?Qƭì1#??wȮ qI .PH#1#~w ;H Ƹk ⚊q~jb7,PȸIG?awALBB&irAl$?_yȄ˚Ak&~9}F*4:`;!+RR!'-;!!Q<&, Ģ* Pda:i" :C[!Q#r` |bkq-̮r9giyZGgǸ,'p¶$) k N1ǒJ"*TkM(, M=a"b :?+R'ːj*(b"By ;.<CCTb S( MyD'<ǔ#"J5K = &+S45J!T9ĜdfIws= YȌ'9mhXÛwa{ B7H%!Дmb \ӶoΙ,I*h>Qv,qv;$l7ؘo !!,y-%/#Jv13;BT-`׉Vҍ"ku$ q̰ s9³0 ;*C3EAɦjT,PM:"1C"J"K4Z!TU3! GaAU+R)ӹLbL&u+ە-}ɦ*}zy£L!̦4؃jhЀizSPŮj/b;ywko:@rs -JAIz/^pЩր *E %/%~hiqԒ  \kxզ`OY:1~' y5|F j:TAĠ:*+STܠˠZM*"MSH4, ꡢ!:9!7m=QRɦ(:|1Ic[B(9*7BQ̭#IR(jѸzw ^ _7<9pV橆 ٩aO'gbPãs AӘӘjK \ &gXH"Y;#o/43 ,W%gS?c߈?əsƶ qu &'&6ok0 041l@4Ka(0CN)T9պTcƑizȐ|k ?݉ bdҼ˙% Ee<Rb1_:DOfL%]v@yᴎ,7;T&0%f3 #$0_ĢZ1pqxJG?e'&ѷm}Z). . k˛ *|f'˚_o1wڐ*̈[őh&xY7y~ t}<n^ ;NИّ7#R %_Rq0탛kq̧Q񚾸 M#~ {ؐ}. &>X!bmb[4c #"+1Ea&~) A? ; +dOR&nCI!;3k"HZϑg;aCy}I'R!s6Zk)*;rU(_pJ9lK5@駣Ajcs%-y0Fhf Z wYVwYg)B0iPN D"t%JJRLYJgI)Go#LjplPz)x=bZGjp.Η |{!;6wWy? "JjqƘqy—z/;"3BŸ! j/+$:bt*q77R@hT1!pO^m8XȊy$TӬwJHy::g]ٍsd/_x[ rw?5D?7#%_>,|OckOAylMP2UA\ RRCᔦ$! [EcVXeR[ѣKf?hZ rkl~65'Pk)bV UQ5E$>o5Ffo&r;>hS7j"C&i܋|c7Fϻ 8tHd\(uО"qt.=M*P3< S\ڽTU~(aS?R4/q wa5v}`̢3V(AcoaA.?d y .#cf,Sw=$ûO g0ڻRk*C*\slx!턵gzY ZA 8LA֚WHaMv&SoiU0&pdlhG,eŶE q|N3c|W= ?,b I;!{ ˽t.d+jJI9+!̈ v llͣar-3`+Ի|jWZj BA[Bg keoYq% pmƹE#"QAqoZp56D ,X-?@L H 4-=Ǽtcvr :ݺtI 5HG(O ~')PLHvT^CĐ{>#a @~><'lmeNCv(#_&Ƹ3]*eK$|X1QWbClDG~w$ՑDKM$6L-#*̟m0 ᳑5,0~ vQ2[([J&=1Q=[]Q\Q8v7\]#E`3Ɔ6H0Q..6՘aVJҸ+QZfל!Y5YV#z a$!, -YfB l+~з:V,bפ?50!z(u8ša"cBc HV4~JTJ@ {OkTC-9:EQT3s5,zPQ䒒vKV'ltPڧ[0]v;?)(asFͯ c&CI[>7ߍa V* /PRZvr˸,Hm6f̒Ҧ42b]$4[kNJ'#*6.i;*Ho {n(V VKoVXPm hIt-!4tڤ5Zc^((8CiIZ1kFqpj]AG\,pQ'|A[u#G 1|vg|YfPS} O+qx)3,qSmCt;Bhv7 N!DM lAUf7- R Kti;z5gu/#z$:* ':f쨎Dg@*~JgnN  6""2P r0j"Vl*bpn0"j$XEV8 CnR&-,#U "FJbdF9=e-޶8R B`P_KVFI80t*CXqnD.b"Hb؍)–fФE *ޮ)|(RqeRkVBvpiKVc Uf 碠*I ¼'mN(tԨ‡T5MJl5 Kvζ/&<9J^9.=JU.<@BsDjTxP:.8p@|cGxUJpM#zڄ'A $"$v>(BwOJ,']=>?'o27kޖ@s|A\Jv8j NX>ZMJEQ o qTx)H[+"eQ4+CTPgvzdCՓn >"l~("' X@ ywJ@xTIL 9/dΧ><ҨZw9mzNήP2>wG@wWqzkVq4*q[F-0Mz-+#'# p APs KRoc>abHlde] a"Fˆ% "6!c GL&!5k#_$65_3TipCT[.`he-%n"p6ސnv\4^(Vq4qɀߢ%\pe'Tp"X:1`Ѷ/nh!)8Fr\i fe$V, .C_[MJqWT$dFbKZW:t~9Nt #GrCqsVLuJnP[8vh*qP5w4N/~}K>Zf&w dk8acBp`n"PegAdb-%P6BEgG;"6\# c-64Rx3IATb!cU~pB8䅚af`$Vf*&+&qg Ae@fV&gQvYc1IcafReІ82"%Y*"wE:%(5ˆpǂœlpP'ngKW(▧@sy 9"~Ngzé { nC~yhN {L~l«&:.djyDxL҂(KN1$Gʤ~"D9VNcβ+7Ayf((I+*y-I@q -PavakG"жߊb"!d7"BDd6mRs(nʏEߝ],em-$GzbPRL-:\igI-" 'h(z*YD7DB6x33cXfu%LjmX)>W,խm C `5l$3z$lp'tWChl' $KlC*B(xeH6ppu'wH#J c-jCcue/L[:/LuJL[uo6/[pJy*8u,~wPJP.PoDrzwS=nGlyJL wrڀ)fƔ[hP$Ff"JpN+1,FeJҼyo!=^#}uZňϤY /0֍г%F!&1' R' VR(Ƶch!i&I`P "W$P-Pi8^1rE9;#0eMAf[X4pBB-3\e/_UT Y߀bd-|p#-6b4)B8kh$FƇp&m6*B~98v>vΣC0OE)U-?uFPSiE,˧O?֗kЏUg?W8|*E"\Wl?Ca[$mHY 1c _XI:: h4;AxdǧӉ{Po2'fAOVhyxۋou簍g5z;=_ p"@g<a'A AЀ l2±)\KSR!B0D(j7 1I o$uq" -⌣(JRʱY%Kp,FR&Lr]AS0u56MA$N7L3AMAt!QhIQԀiK2ASGQ=KRq2UgWbա6V]W5_C@M,J%b+V"-YD`$BF­.R(qHTq GU"4i+gx2T<ЀBq Pa !rVO0oUVCv I/5K-ÄBYiV;vY+-91wWNGvs]eQ:`2: V]S]j3iA2N9"&eYy4Yc?gֲ +a !J}D)vZ(a 4&~9 ItK)]˗{t:VD bԑ8iD0fRI2Vڳ.>ZqvtV< t6 uS A`<SJi Ln FbrQ,Gc0?+I*SE*/ԟrޘ`/90>g~.eX]킓 >'_M"Q`*'Co2U:~ >HT4>5), Yޚt%''G6-(.aVQGݣY`kI(Ul&P㔢ZG3pMwj95cZ̮-Kjۥaem1sKYhUYJc (nRZpcn (0նwT-KVdJyF}ڴri%h<.-t&1ҎM Kby~O`hq2S|>5X|ߦ*l26ym̬M=JYe[!hݐ]5*$2fESFݍD.tҪ0ЗRL)==: xd +=ivVYkx:M*qUd0Q&?1T農k1Tjf}W咂br(f.$My^FnJ+niXŞj)ějcoBPvG+DIn$ZG7fe0m0S2׬1rds.7mwꏻiڅ|`CtmsTˤ4u,ox-FD&wɆ}i5efHM‰[i:jB?Q&$IL:GaؓҊ6Q0MQ"Y Kd1Tv:AB*g4* p)&a̾̏Q* }T{qA*TʴjGU;>l6İk T:eZQyoh%gX/m<Ձm|؃v2K,eͭ$M K 97Ȧq&7+rQ0ay1X6{7qZ{P79{y@䚳vA@ Pݣ݊G-Bz #ZGzQ&jL&UB|'BxC y i&+;(%xL2S P%3ɔ 7P"$ø9%30*) "{04:)# T" SS0*C "60a <⨟ Y6j[23*# 3!3 " ോ":2z3Z"B)4;%#M |31wpR.`&GjQ5 wY7*/s9 lwA@#w9I9:Aˏ{鬜IL"ASk Kzy{7r~:BxUXJlK B1;)!'IЋ6.(Ï `Qx٫ ٬@LXОx8)DV)4:$ƹҫf Co# 2*B*=5m<"3y+*Zʑ"3 *A0!kR53PdH=OaN u*Ma:"mF#aI3B L !ыqФ(1:= Ƞ#\zBGraD1Qj6j@q#~@ BQ9k y9?j:s-Az8p ٪K 5 zjрP  j@o}6K VRSyۥ-9I]ӛvxDBa Ca ܔH1:FKӬ K=;f) TI>!Y#!2:!EI2'E12 [_cٓ"*K*Tސ##Q;F d=qN`Nula-KE*U+]VIA#M=x 6t 2Lv<, SS(D[kqPQJ 9@|T3 T@Q&&p`YI-{ M/ψ xpR01pсr5[RZ(ZS;p 9$HI6x›~aK"2W7X0DX @xt } ;8B脚͔ Z^Iرh/Ru9&Taw(%5Ȩ1M̎K S&`[8ىr$t hq PQ1AJ3]lOĦ*$20R<aӼM5 xݝdȧT9`̬L i6mb3hO=;CZ*B e#dqd9im^q 35:I8珦dr> ´J+&s4cX++Ѫ 6߻B0֑)f#&>b*JTؾit"K Gw Z̯K-E4rAt4R 4M,|~i1=@(MU]XL7 M may.I0 0Bu]y |$CQ,-S\+rs:gk9"^RH#a"~ؙ7/7'rmmXQR ~| S &y齪_& ޜZ\Сm.jX k:C 鮝1҅8{~8= GR̽`CY?6jKS؆j0AfzV=ٲ==;"zOa"K*VC%ؙC6 fEcK8H }( ɡuV2EDY*C.9u YV<*B*3 "**C2fEeY2 3S#KS_#o=sF|h,*~]b*#"*;qo(2(A_C M$8,?2wTHK_y#3ft9O_Ch-%?ҔZeK%7"Fku% ?_+z?wE_i*G_ELjF?X%lNk2u?9&Di0uuE"XC=F1{1 E:n!Γ֜q|@1H1X&oq /.%0I123\4CY-NG: < 4,PD3F).RTX?PH^ﺐ]}o u=2,3/B܁{pn3{46"O2UVDg?C{&u !dY'Cz!d]3iJle.Rd-Id{e5(/vDZ^S޼~b 9:+N܍^w=1Xk Yn<0&d4- 1 .r0m'13G`PFn$4hF8]LӾG0ι]A3Nxoh]?{onQKl@ I:\Xԥ$thclu=/@W F@~n{-,r⒑u KrI| th];'ϒ=et2P+Kε 7ԼoZ .`^[HzUO =Ec#6~BJW"YlmrYuH~D"[VaA˃K#zIø:t?h;KY(qoW[']m g bF1v|`"-鹊,^5&Ɩf#oNW+g&(70;$sV"( W`LgN7Βl%1m vvS^2RGu.ԣ'zR&i4\/>IK\ rV"]--4c`0G|eWIɿWiΙa6%Y:LΝl {i)#tΜ֫] ޜM16DlzcoK0F4i¨t`uf*'gZhd,tMF4)Ftz\|\p04H3DVuC"vIKv6$J(|"h?DzE~|\>L("Zf$~$9fIG \?ȧgzHhv,n>'gD"Vp0L'd]\~D~24{Ct*(n"d\ov,ɀt"FvpQSش+2B+%9d'%N(-& k.E,SNc(ƌj₴1F(jBJjNmG'F&rmz:^S?j?ʘH-",bܓLvf3bBɘMaB!$6,h˶&04ktLF /.fc.8Ed,|3oK/f2"wGpoGtv"jKzgHIGPpP~#B$b&K#PBVCV20JLj((#'p8-foC#tEЄEz:3RG9841"oDIPS!uu"C\EnҾG$.& J3G"zfؙ5&tDH{<|buz>RHhBkBvƉH%|Rk&(҅vP uHv\N2^&*C,B~倄>^W;AbFqnQDtKǦv^j{ftK7H阃gE2'qV3C:mIC4f'vv."V9,foG'Cn9ZĄ2rbt"c#%&npw3Ijzc7"dV~ %gP{$VHJtx:HNhNB=/Pz#A.uDR< q4<7E#=Fu H4Hou )T JgDC\̂ {'H2@0CtH.h&D3v`$zo;SbtG00jF-ghp#|~%8Ӥ+2*%Z(jVc:Em g`xPT(N(,V~; "V(NIJ"6$,tFp((TJ'ijas`VW`iig"iq0)F9BdztFH/$oreUn4pB/:"~vi@RIL'l'?;ftIG &0d4bigA-~d-(#\{'QDPmDlH+7WBV~IK.#FdfKVbxg{ x.2YuJC'oeD֏W{.(&&ei&oHn{lVEc:"Ny `밖l12b̖f%Fnq3#tWTHg|Q#CJ,%6p0_'C!l3V\/\Bz7P93VwdW/fp'HqGpX/iuVH<~%981`Pj<*$?RBcUx*2",V{ K9#.tWHu<.#FH$KgSLKu#uLD뇷 czoD\t'pD, m4Hf,d\EpVGusǠ4g"s M'hbWgCr bnH(v*{2(8(Ƥ~zhƵ e9((N)Ar2h\(OxDhITjn'E',qq2g|vH 6v* Ɩ1;a igH9vHHh"3IM&ςޙTF,:8ՐgB.63 ,tw2v8Q:c;hk0B'x"AF.'Dd#D@ueaPu:.CȸkHcrPؔK:G'x`6[B•V ?Vf-VC'IR m;]"V݈#ICIP{i6*~n7L&<H{FDu>pC:B]hubn #-!boS"ֿ+BtVtfرH#+-"gjj;UpYqZUO%3Ž^`~-5x+Bjz7K&H{Cb+1 $Җ3IvEvª*밬8+Z$P*fi[ oO&&if^lqd4E"At"dv^BGhq%xL%ÞG"++10&8bdŽJ)QM'p{hH?iJ6d+&-0Ĝn;P4-e#t*dIB5؅!n#BnzzGpfnpu44wWr3T o,&ll1"wC>vwc< KuFvmbbhƴ ō=k qC/gC@p]%]@lVmYu\)d&k2x k" b´;ć(8C*ׇVI[Ww^&jƢv(74 wR8Ic Ƀ]7)U& R@P/.,!Ofd/tB̚$v>.0'f zMp7 gEд2y6}~$H)K̄K["D*L{$?n~guvb"#-'֙Q'>DɭP4%n/g#D%Oւd`vB?$rl0RGef?F";ggR`/lb'cH.@z18RKnj^""-Ǫ1RHdJ8QV{fa[QK3 ҥ߹OKB"C'x?ΰWsa70=FH ?2WBPLJys1\?SvM4q1G?H7 =^a2#_al;,9B:kq"3BBGQeQ~BZ~aUj*rWK0Kf4zA'tII+9]׃@ 5dW2r=|Gcγ}jsM?k?^gg~f??7@(R(22/匇:Ț, 6?{,Dx?ȳ8;Cnpm4+iRXMYŤB1:$Zgjۻ(2g 42,T4K386m*Z3$CLKr2ܝ,8A,Pk{h^IЈ@C0%/BRmNQ$UX}gSU=n%קn#޸#fMV_XlhbEG6D+]'v-w^SUբA'`6uX ](7 1sOlP g9Cke;3*|PT4~\-tJ5JIoH8lR.GݏN$3Jl ɱߞ$m3N!Mt;6ċ!*~OS&Nx걝설ɴD?POT_3d :l익+ !6D#`,Hl#ɼP 3T✙ <Ф԰ À2 Y6!#Va&`Q2p|ȐS`6 }њTg"Sp{Pq9)?\˖8:Ov=i-&rNL?ekkw42rNo$3I /:o̲[AL8Q+s4pde*pIdZ)߉+elӋK#'%Hl ז;*WZ.K`!ø\Y_jd?KL:ǩtCl=+7U`]6؀MWbƉ*F~C14;qI~s9[ i*H{k&ȳ &9 17!1rБi Y3 r 93)@i(eӌ3 i& P0Y: zߩ0;u40-j#sXYs:s„*O!R~"9\$rw\4:úI'#AP! ƒӖR:=k=4kS5ֽ b-j>Cd!{5KJ.c!>-"ĽF[Yߜ0 ,Cǎ ?Q,J.–I)+@i+((Y߶xi4ٝJ:V%jVԔ_%i QNX8qN[K)'0: ߟ;{;[sy:)0e'r##r~{'㠢99qqIՑzr(8: ; 0:I(#p A"3" rIA 4F\GX%Iq@pyPiH$IY(gKHTbFdYvD^#=RŬ!Li8ƋOlZ{SN{Ru $ $ &(JXKJs0My4 06̰1 ),9+Hp;-A0и ҦOB%\979<,Dؓ;`П ;КfDjF@x霓yC~1H(ᓜY{(9#r͜1'S1'ƹ5J8yI ߢ;lŘ1HI$= 1P2ȩ>#۳@UJ a50`*Pɾ,X% Y+ӽ;4=Z5-S*>pF4aFc#dFFo>`u26B-R0 0ܖ0P&9'!6ȉ(xDA+Xm{ M̙z,M(IZz 3 z_/kEWYRYوT;1`#$"d9cYlٲأe\K:K &rrCa"75S'"ƾa'sKP(;@AʊuA#s1<79 @784C 5mO B PPHlF{ P\R GhAI4j_Iȼ,1f-l>^R+Ԗ<6 m>O;R!N!k5d5s_ź5,iCEZqX058I'! cPԄy1p1H(+(زJ}܋y&ȸD%kXa>!U06$],OŝƊ 瓐ڼHH `Co傐10 ,q9~E>(7Gqѓ ޑ50訜Bw1[ LA 1&N_TPĐ %3c)'̨e0]MA R _ fY yًh;$7=9$Y=1A[hA@L靱-jֽW5,!gWKO54d4*|p_WM5-TiA?i߶!xx|G/Ł ޘ4˨P!AœN | ủyYn!=sG] A1XYc@P鍉12D ٫ !P`p0: @/q 'B91=,[E(9":ũ8h RrdHEp<)1ݳ@$ivy@9(}H f0‹| R5Q,æ؁B9 .Lqby`\!kLΓH_j=z*k6Dp߰VʾvN>6CJ_1Fߌp k!JNz4v MyPG8"za\@`*['iP@/YK~]A(PPOpp 39RDF٫8V$Ar5 Q6(@? Csph뵹ѧё|2'|n>RuVM2!V:ǢS[6v1'9C= q†>^,!iEQ[A*?[A5$v]mi$ehH/e1LXZF 3q2@ qNr9&z)Aam0U&3n &LnU: Gvo>#5ƛJ5+d5pfƜpz!ۧxƩT`[Fy`k?POdi6B_9 ?OU{?ϔl=OQdv3qS}uvUm?Җ 'o[%VM^_?x7 7FJ d 9?Ϲ:iI9sb.)LUi6-&鍥E1̐Z1-4_>cK7[0v_o6¡{Owg?_73(~__tx;P3k*8B: ?7 (X  P#L3$$?@D+"̵)qZvdI' ,I+ԧ/Ľ&$ T,J%LrN*jy4,w⎱")B)T⠢1C94& M%Mт*VY]lׇ}_ @EVIYiiU͜s]סn6`ypwA]iŵ_ۗ`umA\2`% Q18tW ҍwMH"OgHh@֭JC:cV ՒEPOC<}Y;T8'Sb YGl9a*1UK9KA$iCyndFd=hX\Zͳj:>0.ӝ\UMkGk_E8uCP0o862D 'UF%0o!Cc7;=]byQ;0濄p{ڎ8}EXOu4hc]ƭഎtgsϖfQ;x8yA;FcfYlU)L4 d#mc&%fvDMY5:ѯLS _UpHB:'I 4'_,d,F"6\  ^Cm"|4pU ţtf,ћ X+`2BYgf,eFɓXUa4Ydʍ2_q0{BYm fD"t(Aj)ݖ2Pɝґp ; .4fv&fOi IS;2醲{3^pU؏5:ay9Ř r7^N`cp @V:ͷ|سr᱅2ЋFgT{p=5FQ#r/I~Y ?e a&v~Td6`IJf-V&& qN.16zXY3Z|N TiNXىUQH1LO 2t3 a.?yV: ],?&#D*ĭ³DF\\r-+ Huug"WSv~tgSҿnGϱq8!:w;o..<'vZ9+mlC3Jgd(bTgB4aova3A-̣ ddZ!f͞@XS:Tr"gs% m2 %YbXb d2y,lA&&f'ˤG&N`gO=!\-BZ_+X -WYke6a8^tLK[+{D?ƀx =:zWƱTa*0ڄPK銭6!e "1C: &w*d[gFjMbL5+&s6kkMQM#2 wTt8e"#PKlq03m<tX!kA;^sT8uMWOk GjcB*>W{wIȸ"hd.޻G|]$#XK hAMG T.ZK5.F Yckn+6Ϻ^6첥] \5tPfB<_yU_+GquOC*Q|.uϟ悊GV tH{l.ʱ6!Zd1'|`r@P{2$Z;Z3kpR$): 2w&m\DwkI'(K}kW8OV\-3%tn|#d|b SŒFkEXCv3n" a$"z(K$FmQL L" s@wHhs@.@bzR,BzB"'y, a+"F$"p'"pgFd$P* $mn$fPXބKPɃBhR"Lc`|bfUeΓ#mokJvkFbRnXF4H.N xBXN-L`]eگFZuHӥƉeea\]J(` > p6"v%p"b{d.IMKz*eL 'gbgh."@LF}bX  ׂ N(f/d0& |Ƃ6f-n-ֶH ( "e&Kbn+D|KPf-La3l $PpH "Zb rhGgqp<:8:@bGJAKb"yFGPx"zbQ瘠gl$"#6l}$3g(Lˬ(jT&f *d-˜@"ҩkJ"IT$Qˎ-ЩLKY0$nJ l%BRLK;ľg* 3PSUJӥ_!d]6spQ7sc6qJh DljDdtp d#6BR1~8h^1H)ξc1(PJF&Q*d-nHR(ba`H)$6Dfs'OPKlIh 2noB8.'R%.(fX*ml2Mi H-4&!Jz^v dF)욄8$G +ǘ,mђp|!'HAIiAP<\v"c #zG%0,,2Q S/j"F "f&B$*o,Mh&m&q*K1/a05k v5bmkR? &ؓu,H$nH(ʔ@btgp  h mDWҊb]^MWEX[lAҕ\B2# ԦaG"Tn# 0)%# LR,ubb:e"E"GL3 d**S @a'%-#s#gto @bzSΎ)Hz"Z#p.BmdQ6 Ss#fbbl6T"REtf36.b""J9UA``)$ttR'v" w5J#r)J i`2\,:3#, hbǪr6r$bӈCBg&,% :%Q>H&C`ľ``cwR,(*%G3䶌bh/+{!bt"FUMB$rĖBgi~12CjPn`zK Q'j 6kx7XIyi6הn N*/v,4^s8°#e#(*w6+0(wbb@a3QSSgt T)&d)z`1)*ip&qa"B5H$"x+LRedC "aFEYqCE+yALgGU]*M,Iڜՠ"Gl8$aJ-dF0"z3v>$t*tN1}p($rĂ.6ISzQKs! 7s2JFR+Kf!\)hF("V$CpF'(R' ~af mwDc)3,g{ZC@ZXRbSCwvNZa zr726C*r+󈣔wB!xkخA4't}'d'|^D[ǂF +Lg%2y#,q#tSE+@,4>/T*bRf+27jd%}v HKLmiLU4ʔ "Y=&veSt. ("lZZkh2ߤ:8alXcdtwzjbͬENDf,/R#hwvwQB)QC""XK @'%)( TCb7+TE;Tv,y|!Qd7E3E&b"xzGvH;@f4'[DJ()%:gue{<%p!#g KFoÎl= ^zY0" QqPFs&' /GG) V|szGG'.$rQV8#tD ]$GG"LD9Lh$b`Q̀bAfD|=&mmefGIТ*iq$f#LnAAs!:m{Nld~ge26ěfժĂe3rB#gzˈÚ'#h+$pzF17.! *$c Tǂ{"XaѮ}."'Mwɀ^y p E+>ģ(LPK|hD{ygml%FhдjF'tN=KhSoM"{bDqF(&pǺnba_^.&E2%#ue =E p bp2 `'#*B)#UU IÊNAZx*ne׋9C'v̝VrcxP8Eķpy8"QǢy7"H>4IOcCOcvgb}\\ON٣oBe Cn4޽1.JY$w3DKmѴ/#l,'tc#9Rvܰrg&Kr0=v;F?`>.9SQbbbGuR@ظI7&cQu+};Q,+]TÛ#B58F-I$8GI (SdjPP < |?0;CEd?I %H&X@K) "B?2y8CΈ9QKMOjE :UG*],l0bv0[Mh?͗} ^aprMN?ɹG8$g}W.Rc%Síc{ci ukiOOOzboW55zt};DAWU8`O\,bAHg@DhCzJC\2$QMDg3Ry1zv )k$=P3 g#D⬼.;=6>o="(v94#ƋgEO(:ѯS5;n< SQNs+@QϠ9dz$)>,H`3L#UǶ=T)6 XuUkDUt*–5Y ׂ*x >UӭIO3tG)ql1 pxF$4{!X^aNUuE:֓L^ `6=#v"4䊙C9+#G1L(+fPkxmV7:(:a&i>j,L]ΩP*:NZ0 ϳ0ϗNK/ۖpTѳ٠׿Ot[vJWI`n7wn/UEcTP|%97^~;Oc&S>H^ ES ҫz0@4cڏP x'邸w\y Gb¯u~tE,(ܻ 7" ,RS>%aܼ4b˾ueg]/Kr'Vx%Q^<ӹx0 7Vۚk1YKVMe`ԇK(Hs0f`I>G3^`S6FAG&Λq3ZIڛTQ9I cVLJ[1S 嬪'j_E`Awɺ,;W˗va7<؂L{M/n(; ?ĤChu(ɵ7Brhl&|uIĝId By#̇`ct'P T@/LDJSп?SuR*%xTR1}[2XvFe_# EUx_ǀabe"8<QP ,'L6(w_ɏkL|"BX Ili!L7FrʫX+QTt$+ڶL',B_+Цqy-uZR]+Se1k5B>և!„fǙ:hM D ,%Fךr71+Kl-^Ze٤MZ7H;ZV; xKWa: %"gw^ r@Fۻ]te:G}>tunpM=G.Nw?iV*/X20~S.'c|o~+{*kQ |k]cҵߍ$NDVTp_w_~+-HytW]l`U=(% >Řk1ZDkx+: $?JEtVd ڣzyUn4S# ԗE'"ٜC m9[[[*<&[huRWIKC'G-혶\7s ws0,ʋd#r.ݳ?p<) 딮^(A|#ϥE//rl@#r #08P*Zwo2v&O읃yKL hQKoQɬX;K3 F IQ Qөz : W 1h9j31 k69Uq: " 9(+"x,;(=ÀY+<9g  !r <c RqHQ / spi~L%XQ%BT$= ςC[-2͵ek{X-%B#{P5fTۙT-b-AC຋LJqRr zy0iyIIBdA/},48j,8}&@d'Rv@̎" Xa 9?C!9cɼITAt HG94Yh斣R&1 OP0EXiH DtW:؋7L CIYˋ)U"8:s tiܩ 92pIh`9QpH 0P8 k ś\ưȬY$"׽J;KZYCⵡ$$X-< Z##;< hr<y ?*\58-ٳklW'jPqPl$1z!"! %&5X*"[Htb,UD~S$ >˾MɑOL](<[T I"ŸYj"T2i`u;+ܖ h S$h+Ý^>Y : ]G!\ ^+9H H2Ȑ/r:)G*@ Z_7阿96 #R]\D ⵂNA]FZ9%$RnY=8䙤e,\䪆luuӈrЕLj$/YH# 9"jR}T7&(q.?{H7yXgD ʉ )m<-$ խ@L=W`dU; *`I7Tl]P ( /5Ȯ u4ɉҀcxQ?򠉁vh;97`%t8x_hny!4H߲~i萖|0bn\ z}yuNUDiܗj!"Zb 胞HB󏄫aAILW@IEK0-bO] r4kʨf!Ox%2 7a > t (j'.ĉ!;?7/3ȃL׹ IjhЕ'l(/n~Š sAyՅG8㱁 qӼ *r(X])ʃI`G(xI՟[56 U=zYWQe3ШjէYU֩x?WBp  Bn%CMǹ[p̊[)?:rv Qc3,0&(Y'ąU3d 7BH ؕw"s-gA7%9ޭj-F^ٜm O4 W73ֲj щ'/J:>&h Fn)8~- 2r(P܎v=? QU${<ࠟu!k7ؚlG(MԍZY#ɮROìXҨC Z-YF%FjZ5_# z#Y-O0qyTS}j8MDȓwE{HȞ8L[s&BX~V@f/l*"n8W߹>A_8C aF=_#l59I_YC+X?x%9H$GjS>D"GCxCTܘS#[SU55v@;VU&wj3ۅzc:__1?8zČo?|Xf*ӣߣ Akp؊^:b8+ZpNz%5jy7Gz"e?K|+jo?ܧ8BD%;nBl#Q4K!1CШ%cs8C0/'`11єii G´# g( #lZo(L2HtY 8iS&@HB*Dpm 3MR* "DRı *^0KQ/;BVS9HVCUp#9fդiJX-d'PLUՂGLG1rK=h[eąp['(8jv644M#cOb)/TSkca$#6*8MS2T˜AIrˆpV BB8_m8gOaPF6#UbذkCWVSX6϶ߵn%o\opU7`U`=e;$dm"Ӥ+ĬN~I^ MDNr5r 2T|cKR쟇Ω3 '⿉)ʱ,o]+Kg72L.Q.Txh CygEK(>лq_i݆>|5.Sp;mꁑ(`cAWy^ etdV{[znK'`нbwVl3ZxOZB'0`c-LK.1?E2ZRMMeӞnIe11:iadI6,U6 0䱕r։2*lM#e$a(eP(Kc,hR:(ЋlZ@XU[. LŮGi%*ī]KpNJE)T4@qsm\@{н,V x]x+ 9 h4u\b9?E⒤.E `PLs\WI6E.&oK(I"im9fŚ\ReZ.2U)s;c,un4ƘKr&Inha"!' Se6Mf@f5K"M7h< hB{j=l6< T u&$Z Y|0W^^;tԒN5YnH4)3b"Sjm 4 j@ $Nz('so+>WK頁T &y%D?|3̿R{lϭtjݔIlYNg:VwS$ŲƂ.%0Z-L^Y#큎*f8pZ\MDtW^ tN=O5ʁ[̉Pq[Ճ v)2c0qtSq26(F]RE8E*bY9ez1r5Mhovh$KE(Q`z No(%H_Tf8KX&9f,h ̗U\8Hpr7n} nIqh \aSZYSBUryYh`Z%t)[QA$1dðr*$Xu}1^Opݓ*4-HJZ+r'_ D͢6\F"KG>E/O৤ P|G|,u{ A,suh*D(z >, L ĜMttiQ\y,}e,e,wN>٢kWKx"c.ǘeifT@X+xKx-q"#BR>f髢죺\^mCWH"T |,AFvG6gYDL&R>#/P9ZƮ9V*_ hUШ;# BRT* `# "Ƃ,ѦHƢ\wHhL}%,~&HYBJ R"A*{#g$>nwO(CHߪ$NPȤ{EeRL|VCGn`{r:l?Z5V%G4#ܡB=ÆB+t:Z(**\î/H3x"@@IZTcE@ETLh#+Enij3-bS,cFB$e2A*掉dHl c!"=0ze(Ad6sRhGVi$脌ʱ#0=¯蒝fcE3v,ޛD"RB9&"ECuFavG62 HGtRX{nCAG tzN* #(ӎn!b$a[Ee2D!zC-d^?*X1j6xZU-C ƄLc\TV"$N j8Ch!#4L."!90M$La"Td0P5|5)3*.’ARDfr8fTR^6I.e5Xc#6h 6%& "{9bϤ0l'X3H4XidS4(1X0WgpT3tmx^H"BZVU-HNX"TҮ"S+5Ky|kh"(l(sn j.Ȥ,zRtOc6>odV7c gf}gv3'tF#'ĊLBz7`İKJi}v0O& TDLzYciT*yR%-$h :!S'u-4>F s)6b 8mN8+-^=dr1*m:OlB2UN)0!("X>!*p9B !*"B,l(66$G$n4=ОM: m0B,c܁BSbGҌl6eGqTÞ&TB7 'FGk>ua0 %BE5(&6ȓ4PvE*f$\|' $VCV:U<9%LZː5ְ48ԑ"$pB`IG6QT=l|:V,*=edfmc*B2=ELT!6X%@xWY'StBs#(Ԃtc,uc84)-<48r02F%(Ɓv$Yg?B #l>IAcF$bsm*tsN%%&mt`K";\˜gST03;xX(OS f8)1)1 j4-Ln4"c1FE(h&}*$ ৱEQ@#z=hz_!Db = g8=g8_'~JJRnzRbKLzzTQi8ة {QH. bQOD6})ŪG8rƀ6%@#+}?et8p%Ch#xB-2;N}/ER^zXCx,QQ(%&JfsFCxvR* $h-z' ǣLZł811ed1s.AIu ELoX_S8^tr}xhF%XslwTQGĄE&HRu'N N ŪEX8;IZl $>f *4>FX؅ op1+Uˣc50C݀fh:Kx@]qC肬?fm:H:FEV\& s "YWHNem0^-Қ*V #=6%64bB3M,St0Fނ<uN;?h%TFY-$ӟZdh}h~6jzGׁsJ%1UTF!,3>#ysD8*YNupC *c},%>$KAN4~(y-ǭOg8R~"wi. |㧷SE2x{g72'%-1"XdIe["b4Q$MXXb$Ys !Z+;+*\<7 Ӽ3 ѣV?;+묵>..zn5!>Y@%$>1V+/Ce՟c`U-CZߴf!(&3G/MXIM4;,n?ijF "('e1KFӆvx{,B*#A@*,wrUZtT5〔<^K;SqgLrSPye5(>QYFD"_?PW/Bxs"^-(86QyRP*t*k?̳X<$9w=.P 4+?T*J ]a?-jJ\mafZ_G6 JɁ025 ,sri_3;f?=svY?GFp~3mfߑBthΊ!?~]s%|WR~J@.;<Ι A|&ֵ.ɲ;D ?o BĮ+g;%O,D3CwC1\ZI6DFҰ#!3ˬt4L'95, 82.:l4# L4 S@G,1ѳHr伄 eMĤ+PS|26m*"Vj*U@F뒠)Ծ6:CgdGLudg>@Q)QtJE5׶@J:TkT[ n"ӱ0;r\#q1$幷WMt-}/N%OVwRP0 4FKȏaDouws}jiZn{3=vU\><݇N>`Q~\gQ~T"{%ÕC;_-0|!|`ZV- *ĕKg.XVymὮHV[q"V$G6l/]Kx9$Sr%Fa7G=+So%QVPlSJgxWϔdMPVJ#&l,46B\w. Zb.448_W@ߤUBLhWaAتT&xyo5匨~OmQ(@Ju[scXWSшq-*D7J>xןI4{2h99fҜpDvRn E([hbQRCeğ<=KmmI1XLmZ6OaD灅*UXJJ%W$+.EME))*:OU0b:NsnooE7 kĢsn&.Ӛa|C(TsͻG]˻]Nr  gʉEf$*aFg~,k%JMJÔWHPoa+%{J/T[Ihp!E(^z.R![1.zjfӤu2ZDGsp(\QԖN5A,&l9RŔ?c5 wC[BG26v#E:k ^F"l0Wy_5<~"lە%68wr\e5á+=2ɷxk/Q?6{rg<֖Qs z![へ+@;?S/R.ώ!%?+3|Y@;H9|i+q+[+)S獩2R;p!/R *|K )ه")*2~VC0oC0(A!:'7Xݿs3 +HR.$ a=AȟTpq~JBa$ҙNIABɣ٘#CVE0XB/[4$,9cB8) 11y4QQj_:!8&)*>;!=?qA/@ct,S/DQ&+2'q7@d}XT?7j+t+u9!:!hͨݗSiAC.~)2ʕ)/tn渼B4$QC<29(#11498ڀ[hIE!yéh7)1E0NYrCa arBY!0 `^7z!ayYyq'H% Du9r AA~` 8 Hœsopt-2.0.0/images/cameraFS_L1.tiff000066400000000000000000003314201277570055300166500ustar00rootroot00000000000000II*" O?зGD_蘤 G?*=?Hy$*AВ\?_ɤ6Dϳ<&\(O"u<@f(Zy?7$V__Oŕ[VcionOuMUjI87C 0b_|cǏrVK52fsuJ?:7}n[ƏƵ=\nvRVW}~[ըp$#zU*˭3;]H;_#͙;*ƿ7nqP T@& ̽C\1LHY6 ܷnK2C 9:1߰ƒlCcCB39GClo*c19ɏ8R$ zj^E*l̛g"I!)Y 1'$dSʖ?t JPʔDiܧ*GFPt*0!43˩+2!&oY8V\$URR54Ha6IlYSgVQ[U۔)CSdk4%OL]MJT:V+!L17*Y{2g4uAOiWQ3EKGI˹vi2nR + !sM$D6m.xFb5 o|,\sS!B].Ų+"F־[/^[(ڍ]܍G6w}9ov=xe2|R>1nbeV#@%DU@6@z_+?e`˳}0)@Sc8 -l;9xKǠhA(ZkAԚ&QmI+F! kguzY$-I<&Zg*#HzBTCN Zh̀+ 08X; cKGTFDyj>0JֳJVH+aQy,]}ՌŖ9Bau7=zA n4uhǠVJ1!d!hYfvC"mAXc2aVH`*ڈma qNDD"olAu 7=Kjm|*eqN! ?G/b0P hL,.LҖ`gmuM"#>h` ^0Ae٠xaҪ4?AzQƨ/*@,Ω#?* LR1gAjf JӲdҤxRX2B MI,Aֵ Ou.F{W!( RV2+B쟱 &aJc]TLV-d! 0v-BkIԒ$m£ ,6?ep$WPJ^:hs_՞bbNC'cnP^[%$DN޻FWiȚLpa'<"cVQH(kyЅ+FEZkL-:I5 B^4}[2Ԣk>ֺ u]Agh6t®թBі=0weN ŦSz,K,C %EY.7Ps(q| GM;u.AU `KeڙXNdkӱ~N2uP@Ch\?kJ/S׶1q[] /UdAU}b ):jZWE&MI2&FHГ#]Qbc"12&HbLTO+TkM4vD0[L&sZi- CvQ{[19xr"ݹDq-+sHVq &JWQsH&{ +kAWe9b#i !MdL1n%i\{}q }S9AO*њ9"s0@t2bV;ӏ@UidzkMh0ǹ5dZ.<iU^l?UόYFX2>͝bY9iUɇq縊WQ3ʯ1Sod _{Ʃ'Լڳfl{Z-1WBMn&FfMf0 kfLcD}BcvwEcrdcdN<P)>~[ 2~, ȼGPT\p~[)vvzMi>JJ <}0*C(NOHkHD CVqCi}ǘ #bCD("dk`qЦ:J!&e" DHp//"qno*EOpBT~~@57yX)@glˠ_:.| 9Ij}rX.j:JI X G* @>!ppV?!3"ṘdG )05Bq.n?dE6#~d$TEL~EJTY74xIeV iF܃j^Cbk#d rZfT$0$bx‚ Mh .eh}:gX0&!ޥGtĐhOr0Y0K7k)䲬aJqOn@h ƨjk삉|V4H zCX'"æ}GGh鬖JwDrG'#ܖDsST&r^FMnJMf*fch6'jFDd4hIFJV hx V,@0EJnj-!`iRc DS`'F0a4s`0vGk]^i}[ HArJ~`J]~\q^u,קEL5/ T=M;ރl&*,xefp1O>aP|q- Fza]JXDWo/EOʺu*B7T Ye  X, LA V*xVJ10X8Ui fq22WERk7&g)R)V&H!Ss I,& :dM*Y{cMb~/L)>p^OJcW"&d 2:zpV&=vxCED2J}.HƎUDw~IneOR8æk-çFD<AX)53Vuv(7jĪ3S|̊A1L}@}z僸O,~w:WSȧft"057ٛHЂV* mD-74ZUazG+M^DOC* e#XpvmEevC 꺛Vԫy)~pC*pH(C,@ERx4:掋h:hEDĴ0$Mrjexqb=ΤU/irg5iXB4lG>7(ZyN6[.\tP[*Pv{P#F*$k>)Wx=GX}N:vzC$r @1)}0X(CcۆCh GGPM&D Y:oj̎vX𪺫  vT ElvOraJ9yӉQO8@Out@.t׶'}|y:6e0謭`LWA(OPmȌR*%{sj)XdU=rX|1?LF3v1dy7GRbأ}2س2YEh:ߦ=D YO 9qW{{o :,ex;rQ];9X{)X zXʣe´0ѡqZ˃&y}H)eqAĀJepU~I)|X};lezq dC+\I!G÷$8vGٱaiU׈'8b<]+3.R6֔R&{oLJWJ)U&]|C柳玁wI|آ4ZB0\qߒwU%hDxp1&cЉv&$'y3JU: <-??q) clm(?2v-IIS-e4'M C= #NgrKIMH:@?UT{]Ŏd!YT*W?̷4]}N_1_S؜^(egwHISa6ae7lܐ8q'qn  vT*$ae!%O?~"y󂇭M?ʿ4ӑϻ.@pPD m{b L, p\*  B0hؼl"*~|k8p/fVtpj.KD"/5ܚ,,-uػbd!͍,e#=`B|CKPɈ:RJ?RÒ#G?Q GQ}+ `Re/8؜8N))UU82n.^lp,GHRbcx {)W,|/52J*ד %'`fDJ]-x*l#c…%Z*E DJҊ4:@` {>'&cf&+,"Q 3-uיCEZ{3fp2?qzz>YԚ^z<Ǩ{Oz`Yy_?XhYwX?U+hgq#2AALG0Mz#7&˾=im aVfDM3 N.,&ko2?£\LNJ S^hn-0]rNHZab] 5^ 0BAd†-q5Љ`T/~0+1`c,/2 K@?ƕt^h!Oщ*DDC> czFt ҜSRF #e,xmY/VtpJF&2DضR,2-+d`K\R] k Hh2&>)Mv tS3ODPAc 肸\d5q0} AY7U?^"0aS =a9fP+~rȕђpYstpVI)sU)e%ު9Bi|pog j=Vu \!|M?HQe]+RӇUȇ*L[[NZ DK toLX@-xd7rNaL&/>3 Totrɦ -ַ^v8[wnm3mlW^X۝leR‹T|am9mKT{ihnty$N x4 朵lgY ` yt$I%s%cyI~CMWW_{^^udh MMN. -etL urU듬W:7t@cn |!e>wP뙇 eJR-cN0^ֻ%XҐgނF>ӁI>w='O:tٶY)L"햒59Da4tj#+ϙ]f1p)_ =-\'+la~G^0B/Ea_", tXS?LI)$Suƒ"ö-1$27zE6E7x7Q0"c~"kiSJ)7{ ؿ Q&ɑ+WAVBx 󯖣yɠ.5!w XA8y B#ưS%銸1"8  i12'K S'õ(<:ˌӼ;ڨ*i %n+%5á }7z^{z#Ӭ# ,+2ksJ!8j! .T$&ɖ ѝk3,lk)q)!z2 P Y V(e:jee0:i:']ۨ1D;#( @:hLRj}C;M(dM<Ի{ My[?:j t[">#VM4 |r%⣐M3>@h:i=0M &"I"W4 D *{4h:Ӓ$NWԈ{&jh[0qf G"zi5s>>ȷð@ /8iBK^B_șBkQY@>y)>^j781v30ؒ"ư)!Bym5߭^ґ>6wa,.s%sXq儏G%;N# 28l@rE5It%mɦ婒Y!nKq"E2aC,NIt Rߣ)m sb_0%2i,a^7^R,&z_&[X$X"wXSɌ\#}4}$ a[qs,#!yt$6,:R{ɉabFT3 |դD,NTɼMZTCW)yEWē'$3"L]}ZC&R?c*NId$$z!$>⁀qU)nPJGS}0Sm&&I &ۦWrj߰'YƳ 1© C@j憏bAN649 E`ӱEc]um! XX^=.L@dr`m` G#>Fj#X0v%T)jat$H i )pgrX'.=; vd6|zV$a",{{86E!!3k/m\q IN'vɫ{W8k/ލ*I Y ,C E"Sx> rw<"!ʡ@ tc0UDu]Ze]WU;2"W>#)XE\>RmՠvZL(7w)Ӧ*ىj>#*@g ,)R"M<N$ҝ&*΁菱(}'ӦŲu: w0=[F鱪L*zO`(3=Pp"?Vfy ܤm y%^0S^%i(%d@IOXS *$R^jR4qBbv{B_,0bN$RzQY!v86ŗʍue7)&@ ceIʑPd[[ I+𺠪, ߵ% y5P)4j9u J R4]̀GfweoiUnX2H6֎* UetM?o,SݿX:,\u?&c.g ]+ab+A_HCX! E`?ˑxT c,?wTD_ 53fD;_[aC(%@I]S fWkM2?w_⋃IsZ,__C?8{1YMy E^Χ"__2F?wCu%?[wx1eSD⦞#.]~!Yg?}9__CO14}_63Oo JVSAG_ p6BЬ.9CGA BH"H>+?P:(0;n,6Tq4T4<Xg${=JC.oǃ, Q|?꺈+⍈*\.3l`<\G/rtM}x\@q O|Jw~FBX9G5 p^w o~" %V=fR)!Jp|+H [cb 5ؠ;^W.΄)i} &V3, JT-%q 6QT-HszZ.ʦG9+m{m|J֫qYk o!+ e'a,Hxߡީfp,?ϟXA;op`~1GG`A҈pPMyT}HF~]8i$IR_0JRUz8 Cs{*G=(@ [UeDi?"CR<}Oe4wn i)8pL#%TrCW | 3ꏒ"e}XCQ52j1]#xdCNo(G\yY#IF(ZKQvO*^ PTVtf%iHcZP9N4@q $m9+Ċ15LA}b@,5[Vk ] "i} &v1˻"JAJuSePB/srB^6iQmZ9sn03@^h)e] 'fnE>MLaD5S1DxI0>XO %S3M.YclmZXW['@ט[߂LS),s3x"!㵔Bsda~>Y @THGdOJ9?1n#Ң 9T1uemX-Ekv.%^(Ȩbݳ CVu`Y6"kֺ&ϯv~WnȐ&}탋 R;?;lȫpcd\sl^q]"{*b.R1'(' ο2Ѫ5%z1ž{I0ǿXRgPh>YjWJlX $|g%, چMqt$ܧs 5E:kpɨDJ5t"S\[cl1NihGUGVrR73ּ q9nBioj 9SH(8;5(Hn Xvl|\-YC8x n6άpR%Ȏ"ȎEńiyǺ0/<0S+f*G(P"`Q~'Nګo>iOET+M+fMčNfQ|hh@j#(ң(?$WT$q"H~ƍ:-|H'kLұ-p(IEVfƦ)h7n2#nL*,&J f.fB䲎Y+LM*a@\, M Rnh[NJl.B*D┣ jȢjJȜ .LJ2~uEf hm,hQ"*,^o޽B 8 ^TGR_3D5ʀEpWTP0T&R$xH{؀QְP|nq h͸B&EjeBN|Iq "tiܱ+Wȼ@ge2S(#eECCBʆbBܝkͤ˶HUڴ( @2X4#zyKz9TN'ҔЌZL>.fbNZK v EV ugZuI(J[(OHPDNrZPN,N/>S+nHcS(0D 5L^|OB*R+i3Ǻ"%:GWʞOK%8-IQ$||I ʖN$ jF$WS,l^k*F?1)fe nfnJd / ,5 Q )\4YJi\PXjElV&lΈ,yPGlHѣbU ,/ |NAp)`4#FuJ7Ў% ,dq6>mdT huGTJJP,A6'Zm*Zw8w53#*PHXQK 8v2@Neȃp.=:(GJvuG@+3=+Afm&Hy%$@r*">kb$6VrCmKQHlC{ dscdҰdأmJ;Lr2:-< &N@rv90ix+oF(% 6^HZ4jҖb.de°smBlţ+J{ Fi{&Xo-(NҞ,p eBMXo.*f6b8JR,ꥱRhn>Nu.BPuJl2Jph_҄yBwnC>줶vpXQNT+fg#8whDsbKKf܈ht XF} %hx4>VNwFHa8Ij}Hf|fNe6}p$Q|(0Ug_z0y Tf Ŝ$sE8#~c yج(Ņy~R-y谉N- oZ)\Άؼ[Ps.IM "Psj& 8rPBo )zcz3d(lڸ@hr.{{"&ήǩF0*h"iW?3wbQ(Yl1⬌l5ׄw$tgJdIPt:N!4*M)ܐ"VLxӎN#_dN#@U ܝB*Q^sίHWZړMmP(ijwq;-Ćͥm@d)= [ks?P|M\ | @|k|bBC#-b_B,sDž㺈ꥧ"\^G9>|VCpRR@|"E2. "PtMxlUQҢ*Ξ^vYK 0ތY&ZʙIkɂ0I]" 4m=HYr[PGTJOHy\"1#8v h1V-taJ҅r *v z%b0XOH'f/ǀWT/g솽OfuFc9X30_dg&34jot4jv2rLq։Ӛ!wRXNC'âb?|^'//=1?]Wv9 ?^8M?_{)E04 C7;jۄ `K0 GMħ]C/3;Nnȳ 1x+)Tѧ+ɧ+⬧'ѸdB~ˍpC'}6Ds3\Ί'1v!ЧDq'qJK2۪6MkNRtiPQxRPM !UWSXRZ$'^UQ1Fpz5Ԃ "YhWAW"Mh"}UV[Qqo, *JRtIb1ݳ5t v 2r]rpS2B<$㲦70S\نuX5x'WuYn65bF$Hp򢎇F_#e((X!gjLg(2HDgk.=ksٺMXä᢫~g/{Rh&KF]k>2C%1s ;~:n"R^L؞缲m;LZ;aOM3 ^p;[!TV ~/ ,`Wo` v޺AU{ocٹE@῝+.|_{lwiZ^k*@\]0-ɥ8R &pL$DPH CvIl'E- VJSRP݆ aPUn5MU?8F"->B"1g- EN)3Ehº((0 !r[*mp<uN`c !@3žkF@Q, e3.f02 KC2BK6|PewMԴvv`\d%2A5vcax.L* ՞~cl3&Ufc|-833crrAYXZurZref:&~ZNHk7GLOsn7F`Z=2=%-索bCTa>t]K|YƇ Ρ{u:p|= Qx ;iu(?eGtnaGO ( (,DU!qO>}-`@&} gr4ʵ 1t2U6dl3=KUm-Lz`S)s\33 ?Nx#~%)Kg;Wg텯9:эq9 UN\AkӞ' Āh^u>Gwj[^bW;R [{uR˜k q CHd}+{ҧ*& 犨<ɈocuЫ B yo];m{1O[QC[m.]*6}DwmֺKt,Lfvݛ_2.&C$# έ鞚R q^/3^&٦J^X ɟ Ԝ^''跥G@Ռs3$@8a%8 Hx@ś :غ =".=x q-q:9w:x(Q:<0@&|. ж92B)b4=Sb+þĂ)QDsQ5Dr4JҪ<5")Ei\Dҭ泊;ήA$0&Yw:ҹ@R—ʍF@$erN11@ o%$; 8 Gw,*|خBޒQ*> 1yb&@ȧ(ȹbp JHēsG &%ᤛKX`,<cDSÍ-DJ<+—0TgItҘsEaJ ٪\*OQ=%(%d mȢ0xKљwT@ȸ ]J£@-ެ+۬ 9-4 R  (ʥ㓊 (Y 1 # E㘴ZI&JX&ٞIA([r"R30K?SQ]!L,;Z܎D. J3ߏQ+1>1x8 mÑ iʐ5K3"jX33)#ce^Re=Zcu*,yz3GRab_g$Mb3"mB=:a|5-6Gg7%`VG#;R-,TV1Q +G@(Qf,˧ 1 K䒌 dY3C K^u擫2M{mr@JXŜg8Y09wgi _:&xr'9.p(T Eȃ0Pa:,8;-;V\Vj3# 3]8R>mX8cDeeE k1B,ˈcʴ $ Dћ ɸ^l`k24- ܯ=+o6R"71ؙ8# ,"=uh-x {ʎ: sbJrtjX${ sc67 ~:‘t+F!䒢Ϋgw98 gbdpXz%‰6c3[ q"` CĞ)|ߛ,-k (8h S84NK245(h4MTQ3j_ՐTND *YMiټ;(ꐩXc3rg1ŕ,3Q?d r&kc ~e&PVM 8-M3G#-ȩD9κ R,&*:Keo#1)hߑϪ zD̀kb&BtW ʴtx0B I& nin ss"A\!ɮ:u+àE8 f;u%+ Bѿ1rbTA zЄ/b^9k+U-q%f9 ؿ Z<R6]+Irf5Ƽz17 hxx!ٓys.ff1Τ9W98cp i[9rcVf-٫%?a@]+RTG^*)BZW^͗{9**P I Z?`KJG P<1Ǜ\"4̷*և@F(,` kQE3W%aE"N_6yxY1bXR.U tVXQ~CŸ,A\ ,2\Z|t6z]p,D , ٺa&S^-tw>s@ *ph}5'i}hdQfI16aYp}5~:1M)ߙ1\Tr1I;.P)31w) ' 5T G~Zr"{0FWܡ$ЂAAŗz_D\itoNb_o{m{aCY GG:~( T /,11A`Tʰkw&EY#Mې:0Xf쩄IkjeP2-12"Ft"H jZ͋.d5 4"G@wD5i-J1oz*|$'D.+x)n=#FlT7Z R1&#lrzwn +")nLlXy,t $,Cz'y! udjH% kFjJUNts$ oZ~Lޭj+jzZ䖩Ĉ~dD@ .JPTЬNJܥG'䥭.ahI@o$0I)*n7 šnM.M.op!QgDcvZ iXH ie%dI@,Tah٢ae+V[謸Er eM3F-L،i4g ̂>ctq$cHfn 0AfyeLlh= xDCA% =p)0454' Coz(|nՂtK)#& jưjǚGE*R P̤'bvY-"k'邏/"CEȳ 4pr;'@=N(hnd~2FT fCs#^za1V1! !T)XIAYFEfZ! hԋ%332j zo2F>406q#X7.t Cs)1F,8TNJFJ(NJ,l?n,0J*j-IIrjN.'3 @fxs0s,t2n=*G r$y**vIUN(KCp)Tבwjv׊?@qj|H5DUEG}d%XZ("RI.|POꀫ#8dDʤI|H|". mPȢp# jƬꃾd[g!2^q^#Z|xm#735v4Q3"~fVok]Z#:ۥܐ!e4H'Q$H. i XFXV(7fNtou'p=gQTbN"'ktZ.b+Du8;XĤ&w=ɠws>dwLLHfik(cy5Ԥ,QQQxiIr2x-mgD2,+/&scohK2J2UZDwURSE*4S}#5b$׏7 Ij܄ $OF'hFOإ~~+.8R+b+nn 5;J5sKXo#]'XG &C5o\Ea'UM>V^ %%D X4i FhbB$ai-!jmi x@^ȶZ@͉oi DYHohh^ò;APbs'}q +@ckUTG@i nDS{#)Ţk)K>x;0B%&pTuX5Puy*1G1k>tD'+d,lЧy2,q$%E*l yU02vw2dzVg4S,jJ%j\Ez׈DUQ$Ze1B8 @Z *rzk#FjTSYmMjk dܭdpѯQR&2 tJC+)CB?o2z ˲{)"eR 3;%8L4~(!i-"q 2eH^F0JD !NXSg@? S)5՜ ;+AM,8,t;|0rl&p;CtR°0:,Ds:l*v/60?I/u0J++QJN:vfu&trԘ.^*tv4&N3Db3HGzvOWm twE7h}tK/%4Qv=GJO7Hy΀lDZUDxct\a 1>֒* bn n,wR{5(pCqr4<[>8 mK.xC¢F$,O#48&e h#w xbd6EjU7BGhFP[[}p @8HXZc:16*p+{BmƧkn Nc;󧯃0QZT2u:f uus2tlP'+}P-N0;郬bQIsLkҐl=y'v(g}Nw},ėωlsBtGvk;UTAu$uʙ+PgJzy' ςqG0bE- M#բ@cB>Y{pE%ۤJSsE#,xF,GS]2YtDv"##/[tZ{-{7MwYjIێHj߮MيOIt*CQ%b + rA 8l-E?Q( E;lf?2X:K5sNxOa5 v?ޘ$*U:%We-mQ?ngXY,_sT(e ^6?zH!iG{($7.8c1ĎhqSзfQwX\h?^l?hi62Ӗ=$ ꢨ*3 и?%6&)$AD0Ʉj"Jd<q$"Q a )CMGD 1IQ!ȱ$2Py8qK: SNc5@./eFa*|7&ʃSh*gQ**~TUmxWYV5L۷5f<V]]ס!U=gV-!V5RV,Wuؠm0h]P1w7{^t=}\m_9}Ύ`9z~MUUy b9> G 2>CdPN5>l6)BU@|@N&r7NЇn/%01LgsLefuʣPlsR";+Y  ).‚Զ<'r1m.phb,lj FVYcz Ř$ڂ!T*ň&<[dfaLtg-8g'31=tеri5ϛ#kV4ߺz Bl})։fš>(LT04Cp)2R MM0z&bL>b|GO4,D K0">tDc6 Z`!G51̚Q:U_|~DVԊY-0=*c[hX2F1V#\z,#oF1ֿJPH%)qx['alx2$+,k.`# y XJJ-rbA䇉Tڠ ZO)r%zzG  x1Bʫ8[R($2{Bx2s'[:䊏pT04K01}”)0}$ٸ/0S دzO(Ù"01/Arz)TyMY$阞 4) ũÞ,;= i[(`I:' '[20'08# ecH{&Z\4 u(=BPuF\O4V)) B%BCe@H pJZ I3 j) NA+\YM 4Q1][^bj E !UZ*S[_Z7e:ϱ.!g3eER&75- `OY!k,CtG!YN(s݈V$f F?H5 Щv9$*Y %dؒMjܗHaakGهѥr$]ێ] 0#(`.JB xa,:VMZhݰi#,9/BuO0B$2:^1'C0ODBB^!8M[ E 9Z 8 D8L Փ{Y3J^S _lРlKN ! V+Ծ\]fMi CMi>NM K4y"))!=Vh أ;z[2=# "]@kŤ. [OQQx""(tNxu BQŤcW azPX㈮H kJ[K(M b +«SXN94z]V")&₳:@t<أK460C/{ƀ[iF$* M9e!ʈz=W@)^.quiYN." # ފaz0Q0SzAu$߰qϧ* : 钞Rj//c:ϰQ؜(r~'҈d[(} q[j#GUs(4O)3C422m82H0 a+0;4"M,␒L;{™-c ٰ"aEuwR9V;ZI0sm&l̖lE] AI3fQ 9bV =A$ϓ+M O[Yi!(<":*xM@ʉR5 3+JٕeFmvTZQ.(u Ga sk}}o(Q9+_U}`)VN1_C !Ey?xT2"wND.I_Cy+@?Ƴwt_jaCm%2?ĴUjj04P=ͧgkWTjt1E{/׫N^O+?^7'aę{f s4m?z-C0WC6: ou\vC+֪Q%[?\:of!:_ӫ_: ێ}ƽyI$Ɵ[ICNH|g)PKc&T0SiP#$`:`.FCTƇ 7"㤐\vy1Rl`2A¤<740n\Ӽ{N4( T)QlDDHOYJE1 CtJTGRPӇ!V`OTȤeZVMW/`͉OT5Iѐ }h!p[@2(<knR>;HMh[8#}iVlCP djw^u`qxz&8#‹bAvy+ݸx]ycyA7fXv;R#]my ґI G;5+BZ RYʶav IP4CӅ싈'*\k!>&ಀ>ñ ]oP².|*r;ַ W*z7 | v]o_4|NrC,aWj o5]DѴ<w!E G򬚦O$& KUV+RKAa>Ѳ8 <($?|#( }VG$~(-@  p°S"A ͝1>I%$HÄ4)Y1UѢ$GX43EܽKT=P3#ȔVER*hrb4%ёFh?uXk4 clo!1tXڏp-fn¤| Sc^Ee|e"XRdy7&VLa+ќf z]/ 02&H؀e)3 P 8֌d}w`8'qPq#lmʷpga՟͹8O>P-Oi {`Q5V?-V& p-#pTxG)hdEixV\PFa1k7De2ɹa(<"vƗAV^F0k3R1ސR.gGDHn&An{lcGY5ȥO(o_r&nNfj#)N)]ldn϶hD>UoDT@L*hCoX>kOuh0j?ؖQ=؇qd4J*͢eFX@ˆ@b@݇DIF )hi6d8a%kKe)tKډ(VEjJ&(ZP$\ӂ \E0Hb_(h$VI)Ef D8P*t ) ^jcoP> `~fܟ6z,$*(oFjθ3iN0i6ԧ (1*' oI놬lj8tt*o6L6j$B6d)(oZ= KZWd//&0\OV0ԐM ^/*'ܮFB'8*g N^Em~ -l֊CO؁D 7+GDzM-D~ͰڏF(NڋI)\Jx㴉&H N`hHиfrN <ʨ}OJo:g&~HEdV}Q+n:VQ(Q+ϦoڴO GJ h~c@c(c1j;K$n^f  ɌOڈ m N*N l0d fi&,#ꢇtlyL}(̬6*r⩂'/3iqH'hasd7L $ǹX$ K3s9Aӛ93:Ӯ;A:sS H1&S6xj&j%,a `g뎸Љb(^h^Ē^B@N*b]u'bFJ+-¬#0q((*-m5 npg  !7Vl't|*,$g 덆j /YBt}̦l,uk7@ʉ2t?]U^Au_5_``AaVa{︝*`X!.7ƫj'ڒ1ƌ͆vZZage]WVrMrEdTM)bp:Q-+( ԁ3o+7 *VmaBrXb FqLOT;+(N{/sJ$qKjt%-N.Novok3C CGڮOE Pg:l)o$fP82 <*f(bb`h"If4[*f ,RPb vd%MoAy.s"/tP2N&Oz .n/p1PlwE0ڟb&>p&%wj |C<ɢ[Kcp·u*q榸gA*᥃6aC:ӱ^A᳅XWaV^cHrވ  CwS쫵:2 )bז>7f>@ `Q)4# oCr r$~$JN}n$ }ơ MaLT$ҞɌ< 6v׌aB agO >”bN p(lV2 zC@ooM` VNԪ BgN0W I@*&*6DDVڄWS Ry+^ü:y4F/ڲЂeϦoR()5"N6m#PB(r>Bj(/+Y#X6Xs6j$Bl ,&i&N&Mq"zwGf6p- Wa]>$:CY rAg]]tiH6ڢjoڄ-/"q?CN)gC~BYoZ͟9,1* $질[76:Tvx /1"RKp V눎N_4o)cB m$}p3m<&,cnnEjp o&Njp܈ - GWcv7) (ol*woQj'yMgp\\T-ώqvl;V|p +4L!g Ƨyuj,z=ﰬDX"u/ͣnlV.| *zæu(.Y+ݛRH΀<> k!(d9aI{&{vx("oLkgµ3{L.َcYìf.@/5f4bqCȕr(@>WtB9?ƐX$Y (sk/l]'?QlG!$\!?ò~a,Ifp N2POh3EIJo]+D#Wc0@l-tf?Ϛ`5lMk8?Л3XUR?¼۝ԗG^rLJ4;<$? х@~I8@'Q A7&Ȣh`O{ʨ:n$2ȹCJr>Rz /ʊ*"<@$№q('-┮ԛ'(o k\R D0&1 Ɛ2CddP'!BNSStQ:ѧ)H4CtB-c\֏P:ʬ: ;ZMnĂ!W`MmbBqt8BD+YgZ։LP,r.'{)"u"O7`|xt]W*!5෌|38& ;aF&شݗ1`E8s XՐ%qbn_T5U4fao;04 SUX'3=Oh5L3 5z ԧ%^WʸoWMY2[ BZjv F,lt3P8cd\S2ټ|悱,K$)Q4\Q,u= *(>E{'n'@Dus%.+S5UsP߸9jjn[έ 0%,U#H̐:Ȕ~Q"R`[2g,Dpjg0eRj"71(1&(ѝ3F!G)(^#=1bVK2,+ׄ?"FV ?#p+A"5-ׂwB+%mG)J]8` sȗfĉ1IC^k.e<5"6#đQbtQJ"mupsw>gTQjU,W(wgAӐC+=>U5 ^:FH!i394:ܙbaKtL*˦HzAڈHD|zR"='?4 (?pBfvBR\ӈϿ?G`@A"P"F-D#""@qݣ"#!T!T2s#{18Xv :_2`88'zqRw2wBa] BzA6*5Qֺ(ZDٛ'|!2&Vm`!k&mWAm˲ * 1q7XIhic Qۛ#;/DLz$zpꨃ^(Z-')YD4P̀ A)?1ʀs.cˀK¼@?8Oi- -/ȯ%©v$KN/NKO.& }{ 6mr2#G;b6mMj">Ȳ@Y=iݥJ$DHC?ez?b̄ԌCg8GI"Lt@&6"hKsjHՍ:%"F9Y>Rt1_ 4~1D2))0*B1[b3򰪒' 镎w[Z2w!D( ;Qm!X :m1:mm"] Y0'A/ ' 0#g;L`  +iV!2F<Ȳ(I[aɃISˬ"ETX3I:-*2aD p$̆RNwD7FF)%DNGEtJ "`/?I؃c %qڌ(?<@y"=ɄZ6V%& "ӥSQPgI\ZHMEi4Hc۩ 4jITMntPL -AA+  VQ2Yb(=ݦ 6Kr-5R*xB-F$dJ4F.rD 2Ai Ð2!h!k":*Ymp V#|r1+_ L& xɸ%aHa(t늪`Zc{N$.iz/VZ{Pra%* W J8J$z b!ña Y[m:&܊Q;%P MkV Ua5 wJ4IKYrIܧ;!b!1chU@'yV!vW ]cafp@WOce _3W#NN_׵cmY)$#MSÊ YۉP0;?neG%\Oꑐ[ejY E>$>s8ck`k*aХNIGkF6j[Z4_Y.:*uFiRF|Y;OP/䁥UeF ( $LfMϞǶٛQIJQM DCaQ[f%(PdBr~gD\Ɉ0g;;)g#%p Ol B_xcaQ- OuA?R7LJc3?9$*'R}N5!?·:T Q`L?v7bZ_[e͸?7Rdn{Q?Ѹ7 pyI0Ù7W,>fpXDu?zHQ1C?MC琭[ZFN9|8 ?EGC"33p9E㤘C}H2\t/(U-?NS5@1UWCn,T9 X1Rq 0cE4}26@Hg⍥ v ..AЅqeؑ0pF5 %YL[I85?P]-H 1W D[gc2*02 a*JcZr*I ANNfx Xfᶅ!P Pg]:#rA3{cc.nlncخ7⸮Ń)Wqaş!<_ͭ!eMџL1@oTn‹/KӣDANC!◍|EzE{kc>C6/AuRy8&âtΐNI?O^hK5jK*U_Z2*ELV <)-uRBKUFгX `.x#t}[8+?œq F@WJ0fB 2lp 65Ʃ YP (SN>"&Y`+)6[B͸6NfMO3Efnfrn2bXe3ɀJcV~1͢ &=I)'$׶6[ ie76+3;om 1y1Y11 h]~ +GCYQ-Cs"KӜͲ N _gay2?EIv՞+5 QDj٥5YA*x4ްi\u'@cCXkA6JJ6߫ ];j Y.Ua\#8X[ adYPV=M 4F0fHYZ"jΧ$mn%Y;Ee꬯!Cki%1>[+c)$JmJ5~HU@F$5izr8+e a0*BiKRG8eL V뾗+g`ѣ|2 L ?,E$5 4fmTY:??Y!e gMJqj\C\1X PS:2ar>Ha<ɰכ6fטel`Re/8fmt1W3c \2=Mi5{=$e1x2ۻ#5o2J+2J~;xIdV^ڵC -;.VcD\M/&6.U#(&F< c"bɇbFxo c !Iޡhb*n(̽<rdl9 4˂" ps9ʌN2²(A4obH螒Jbz|pkƾ!&=chNb䫑bR8!#E =-d[[rF7hADk,^3K3(_?#[&㔵9(2*:(M2%3FE5V7.[LCMe/֩$E+Ƽh) $0~`ZSnȯqR(;z;h4_G\8zOKM?p>ȱ򌳋VLR,'DSI$x zNJS8Co[+0%@̽d,%s0B@SD%6PC4UHUphBoΐ nb΅.OI ].YE_vI碋.DF\YE(ra&*=@Oz.$f9sae/őz6nhj?'.i%dq2fyBb/BLdBga=bDrP7p1L+ YHk̳+(Ҵ)_(Ȭ7]mIP-(c *,L#g^ex % s'VvWlCKq& .RD, U CԎI0A_KƒN Ve!sxzȱƌr&%J9a*0'F[XS9|y2r:eӋcIkc*~9L+>?s>nH+W䃭䃬d|F$cwDOMpl 98ctD=ă#Ћ6gG M:.gSTU%@.?O/υL0>52V 54gcRF=CYNL G ͧ3#LRVcl:+]o\͜;]Eo^tRuT (RՀvv=pB̘9g 2X:(FJ!e,X9K )Rneh>#ar$x0xk:ޫ#%ɂX$&;۲jIzon o |Eba.unaj%&Kz,RlP oqX( ` 'Ovuk) 34-Ю.55@j uOUѵhv1xoa }ҹV-;EmnQ%o(CRi4?D X']OE!NGx@?4#pD:^ Г$K%78KanJNCsa8G9-%t#`DpY&(CBB < xv J[m|.ظW5v?kA8{3,آB[ђ7؋r=FE{@Ŧ#"_`(]q^!KV%cN d+yw C9)32{BiOtI2%TG )'r8 `:ڳQSRZ&ęF8 9BYpM67fQse`m-L ,EdfaLaPԶ{I) X.;?yo ؉!T*t,h@!:.toEmI&Usuؾd.I%LůsOUGJ'R~מYvEK>+c|VP9Xə2Xn9cek+?Y1qso?+>5#Ds!ۏkf|/vNUf,gɑ&o3GpSgQQ|r[Oy}CLO*Z+Ӏ +>.b<̫ૻwvkI(yX B?2C歈K["y]Tn*ʑnq}dѢiz2@qj&CY`!u@CjQͤ*ִ)G3D"6-sq5 5x {\-ߤ!q*߸G|+b."ڨa8F+`ixA8Ib7A"k|#yo59r Ab7>,#W%a0{0ʔ&Bd&Sa2&ShY'" q!b~tE;u'R$dB&鼺9 { c {Z4 (լc<^˂Xl^)b "FWFJ8b6 ?H!ʳ?7K^ )3A C 6:[N:?BJ=' A" "% s `q-q61F!/!nQlSRH?e *Rص^^;^]{ds;tI )D"㐂D@k "E|@B)#|BhߩLܢ )Dkb-yS혌T-LRq=L,.b ZKE!KCh0”2c,0à11Y9jy+:yDs!(zYhA4zazeJd:e93+` 3q2Ӽ0y8_=%q|*6l,y##DHiF\mI݌2ˆ p'Epз x>zWGP",",E:"{_?I Lsq>4"FmEl dpU z صh-+^ss9ysb {^ǒ,a 5B"R" JJ;ȵx7mӏzL#AGiB" )I̦%Ӂ*dҨ!sLB11b"H,/j]+zh`bc &D8 ÙZyM24>\A~;!zx;;'X&S&KTTYcMi&AĒ 3 Kt Wt AS!\؞*ʇ䔅}q WJҳ,mFWY>Lbg0d[H@87ע+Q6%I;SAH""B- E2a$Hz6HUY=Q{?):ܸ# DܡMa0 13*2܍ƺ܃>3#P*wcμ,EsI=HMk@kRe&C,sZXX Bq$%YAJ[4J EsDɆW F˄j!sg=mnYa}"m`mH"!O @Vq4 WX 7,b x-$4Lz E-Z="$+JFBD =ҕ|79HcjDJ~U8b7Qce"-ڕ~K)P )lBd&7&CA0cL#&:Ǩza0ψ'2˧D8&; `&C&a3 3\[1[?F=Щy(~f[+{ԇOdD6 W. ss@ *(4bbY9&U 6-Xx)D,N]C tm;HY TiXWmO@a(a-C@2Nm3s^9 P b=SdN=ŸA`Ah>*oS" Z")g8PKGF$2hA -B$PI4 ۂL<2{.KVA,^ ZUԉhQT aA1(J3YL@oy; FL((]#^ )C M~#~,sA|=Ώ(m.K㛦ѝeBr?DqݟFm  "Bގ> %# 1آ+Ah8-$"%}/0"Ek`*^TqEl IJC+ 0d3J[B("G4P e292g MCaUI; P y[%8&14Q;FtA3<:۸NI\o|Zw3 (%tK3-gq̢rOfC"+t--FlXW-7vH "WSLy Y&jWY8Uiqg30g3s !Y#"W3/?ݢF|hH)sA"Ryg KvJא*2XqbL(K /K|#Q중cpaAS{I$";BEB™D1}jlΰ{>2,T,2D2GNŻ6ig3>˰5͘Nwe i[oYԐvj&lÏg iFk-@!a(יk15&'X ^MA=_C# aE?w4_=#T0K_y3x?Γ΄;Qfs&e4ڃS*en?cz9_15l''Xӹ$kM\l>1E?ԙw4Tg_-CfZw+TE_M؜fFo_.}DlCm epZMo燋YމFOΞP05P:?904802Od@=Db+C˔Y- BL3 pK .Hn4>dO*ⴱ*J$ԬΣs9 MG63 NAIMEy%ma}A|N}c[ag_8xWmp\BnQeVXg@ӗ,nh&ءŕfI+KNhA>2Bi6չbV^@O> #8~c1<[ >Z;<8007lBє'GγSziMҟ)L;Nj5iǵDWZ"gBw~/< q<3 Ϟ0=|TW0CHc1?6pg*C| 5)="kAD(Q?n@~"%@H \)D̂%J}FʢF>zq0t: YL/a #D9j 9UjuO؀ I)'S~("h_Qmu4Z[ ^xojLwc;~Y3`@D 'tƆg2\)#$gVXV#8&-(;Z JWG`,F9G%1R) 0ȱYYlv|S(&G͚2f\9ʙ?(RSMF 5t|h  M=Mgb4{NV_*J0y;)DY455fURN鈸"s$mf.u<9w#pm:VBcxTҬ[C>ާ$c<SDFgGhDickuGCO}W`^>a R 0Bg; jqMI] Xd 6N``B\p?)D8 I0 CȮ-uNX+u0-d.Fȩ/ $T\˾_9W/$̎mY{,ZҺh$S>.&xGX$krMƯqA]p 8<,VH{_0\ clvHs`QeB)~>8ʰM; SgN/m+9{6 Pjc懞1CMVEo x$iN'q=i49>EhbYf'OKɦV)yX{07cDģvO:S]@ւ3ߪa3aajV# zpQiڍWU=Oxk7 u\ `>?¤%C>52g&ܠ;t^}m@?xZp)gt?([%l(n"6/p"&-tc N6Ƥ`H#X H+isB\CXzy-|f5Ÿ%tp4 ^n'0S( R!t;q}]ӕѬ+C O=NaFJU&3ڦ9|rpjfQ% '(PT˒M֌pSf$^%䨴XƬEЊ[&4ejify-z &,"ilEqFo 'b2oK(n/gzm, {, яX9Rl6/:Rr-o.Уj'Cny/f!'XhEo' ++FF(V{}FG긫ʼ~dd0o G B0'CoJ-~HkܮAP)Ă#hG:Tj-J ͰDDx`+q@'Ar{z!(A(p=>MX^,j_f $$K bB RRn^贒l`zi&K.E0OR$ I:Oj^e0([)S-E n "D!y3As:lH.| ^>YX=b".B0)p3)Qf&3p/g ("z"6bbDHb$7$}M``Ga@ rT @{QK?jxg`]'@0&ߋp-))4K$0VmLWlkĽ+$)"^0U0|[U.^cI\j@cKH,ji*H_ҺR䫀U0PleA  PV' K鈊/AV0˨NJ+K(F3, Ft\hk9"zgYD`oGxJ{O.(o}՞?1z6C$oI-;Z;vKD""4ذ@\Ktƶ0+I^chzlDkiLy)6ï:mMxX _ŶfƷH"Ow%^j0IK = Ƭiǔ%Y/_teGwAnT{$$Vy.Y%Ut Dr^0g+yn]LnM_מP ]vLnz$7̔O*7#dW oIyr'|6&}=Ӈxh0r(|Au/Š/;*v,!9d7kbb/R6!x;Gj`y145yn F'G@V<*1h)H-2@C BAb.K쭟b fX0q?}MV?G?}$CzCm`4 HC¯"9-LmM[MY XmMVnYnRnljhF4%.UEsEX(^)4$7<kqQHKN+iԦbB^+ƭֻ*4[;04V [!Btu*9.dI!a9p9҃Xx:{I=oV2x{?0W:BsoD"H%!9*PKs1撩bBpJIAua2C;Q&sYri8HUQ:,ƩAFW&Ht jRB\@]i+>?θXl<H6$ƍn_ 8-ߙn6y3?\ݾpi:W_{ݚNa?^WK~SO1z݃c@L؋0QAo'A.C6'NQEd]x n1 G5 D@#"|rQI+(&IҀ* G30C\QML4AT+=P'eB:PK2;H '9NPLOlb;m87g.C;9VBƆZ1N)1?h*dRܱd'ġIRذj|举ʕmzެjs&ꉹnéeYfb>vBx\6\r!c)l2C'4ty6gn{ 0= v ~1/y.c o◶>O<~HsGZ1 56GU01}qq(  G t`d0DX(QD(@FI NRWH@Ir/ W K6&ⰔbW*ڠ(0_bC%WTZSq5u+xa@\>>T81JCؑ"tP0 $2~RC GMGcG@Hd,_*Ew#G6"$:"qQ P >="+/M7('B/͉6zXK=uN}ߛig%J0?m=7Kka$"H5LXlZyrg ӥ~N%W'ao E86edfsbg.&1Jɔfs=ϰ`6Ҝ =s;Rz];)ɺK4=/U^+9W*0 %#MeND=0XeQ- A䒒Ѹ! "I@.0ҍlPX*ck~´{X묅>,?5 ,u\YkbDaʈQ)5f z(+XshBX+ոkڷqwCՉ",h`h%[X1Q:Z$'&m9[bBR`ImddJ!N,I13a4Gz'Sp`6^fu&X{e7VJJi$2gϦ?#Lxey' qMq7SOK69SlQq_aV\eX\K~p8f'0 279HY!9Y3Nfra7+S #n놫O/x99liw8Þewgw*H]™T+ !YstaBXBTę,1WF`u@h(kΪDMU dpSVMw *O[XZdž. ߕRJSfØeAX>$Z%o 3h%|}XyMX"kr%d: DYo> {Im'BS{F !I5 N46.&}d6Y )Iـٝfy 9A }3=X3 Ϧ5fӜrq\2( `N4zQH4.S(ף G ፤Khs'=JS+(qs0II$6ԉ0E^ 6ʐlf)K?ED=~ͦ|+ihS;#DV㎱U*j+nγD5VX* ҏ76\ݛb.AUJC/-*Vn=ӽ{7M.:,+K7QZ"4$!q`_YU:?RafѴCN$@+ {H(A0|?ZAsdJQ&`;hI03&J~A 2 k* i{Ii}:iQ&m{ )Ѳs!; '7!1,)~JWzٞL.1xzJq DәDЍIQ ;)H㝓?=3\39Q[|,ez-IM)5UZ'>J5 +ʷF$,+ U>5Qr.JfzBA/$*ţ7dB*BDFDf ?BZ8?VF;Bتu-A[j6+715'-D4AQP9gɰT8/h-y zH y!JppEE9E\)ēXzآBU  wJ.j (m+P5o P5jU55]r.j8lr6i/4`qFPQ  e(EdAr[7Z DJA8rСRPz4f A )J3th0,10(VҤ4:)=]%Q "R}%1#.*R뙋ѸRЊA Ɗd&1ˀ ̘ȧK14Rg4a 餺iLL( ljw-P\'U'[ɯA9Q}C%{%Ę02\V9ѐhBؼ8ȦzQdՈPL(xгU{  i)yy)xθ S=Zح1: ēZšCG{]m5RG5\5SP>[Y[s[+5,,Zk=W88 z[I0UBDFHBح7 -l\#j9/6Q4P$Q -V[k&+]-u/$T9{=Vؙ0'{ձUH;q/BwK91U5]a >>Iƒ C 2)%c9 w1L:o*P驺S}Ф/Lhq^ 5FRaK.|VAƥA!!Gcǹ kK!&ܕzB*- *\$+nu{}7K[iBiP%BҘIk!۴03D8sWZDY03!&һUPx&ܕ\ )ݨ/!0I9 /B&\;:%]-'~ꀧV);!'N W=a@(!M™͈M_49,[>KK4Ǒl'kK*ޕ#28Wi;3/-8/ B"+cK?*?wT4Ji.[#jҪ:<kR4Y,XٝrÁ:$E-$D Ț 8&`MW`Ӱc%z\T>s6K ØifJ6 |NB[V/#*45>ՇUtp\iL` q/E?NH1 D@)I/FJEB4VEl05;M6”m}&1@DVөI2ϥ7ݠ1Uƅs䡖~F )p!CUOy(sP5Q1%]Q`Ak,!E BylqsYJa90qT?!WqlV:EhI"4K6 ` L.AllCc:~#G{.yҞ-!Tfj##<۟$4]򭕻JD@]"|' һWÀw/lPс@ 2VJ;lZXe'' at},IT7\cLA*`d= ɽ ;%B KSً쁘99:p Tڈb\B)VӜ Ԙg32 QqNM tdyg5cϳHzD[kqD!!f!!/X(+X5r Xy+0:> z8>x B?R#v!v~ ځM6&Ϝ'$,ǢY7,=Bsg}(J?UPR[DpJ#P(=_^6H JiA1v m {䪥WԠU :g֑blt W B{HXS]ZR3'Һ{ӒPweLUɩ牑!'; 츺't4DKO iNӘxQ1W0JO\?0<&"O BF_dQLic/&OzE/4}?47_:cIORU:]4CWOu?7bYOn \_ۣ)wOg#O6dÁ wkk=yGxj_klJƦ?ż7n<@Bsj"w5_' Ff:)W!_c~am;Ocυi/B D40&LI!E" I2>I%!F'1BPS3 $ d- YFVLd5gI_~R7$ŕb3]D|Hlγ%XDiZ}p[EZm 5N5Uu\Zw=4=GҤ 0LU )TSFj6QUx/jJX5VR%/U6SxnxNcuᙐ矟VVxV:it`V6|ҹӽ.\ƂG#kGl`[S2 fılRǺ,Ʃr[7 Iwܧ,N,\ⶳ||aUHg\=K. [#LkZay_ߋ">W#.{\Z*:pCѐ|Q$~ЋFPot~ k, 4ҚӀ^Ii.'( zKZ fW]0s;_y=4bdF2[PW"˂v+<s @K"+Ȑ'· \ 2]1Up/bZ]zETiF3̘#%c @2(Iy0IA'72v;c: 0B?cn GƗjUvWף+Jf<)LJ72* Ymxq@m&Wz }.]2rM"&Ӛiٻ;S[+n9GJ 3^il ?R}$! ABJA wPy鴼7 yo=Xe\G]ZLJ6"?…1|OM[C'S*1FgyoKIڥuSޥB' $jun$LQW1O' 0JUε$e11HYs.|*Hs.Txũ[+Lɵh$%dO.)VK%Y =LBY:WBjY(qiSڥ׌[pA*˗.J1/_ zIVN#ir9/'Hdcerdi%d }(& ' THBZMCfW2Q%o8/ Ï`C8N 5s/<34{iq|q1&A[g.~XxtM \rexi]qf;M5v~CSye8qDH۸((-4O>(m)4;>Qznw T;)@WC,gTyަ?H8ct@?ǧMJi+7kVf!k`q[Uj[֢ĝ\5w+$u%$Zej[HXlNVTjFZ1;diCX|N#e@u{gYt]H tCAUR_lG֤n UD+rRrS_ku()䬥)M|W'i-Imݹ$=x 2^n(nܴ˜ 41r>i4nMǹL qnPg˅XQRv[;O t6Mn-vRJ۔\6?*VᳺT|sl&}fWJ(a!=!к+?|K -yQCy/8›4*gahDt2־mDkv E%X`}-H?;b6?x㯄Ƶ(앋 ;+ Uz)Xf,aJ*K[f?]qE:`Ur|%(Z( fVfF4I,T`:($i\$(fb&dfE܅BB@Tf:BMdJm\QF:dUJ:"Tݰlzhjz P@I4(B1IoДAд)sN3jn,(ɰcpÖɬjl"#k* ",bq@3(>lkg7j 10@}q'zl>6jBkjB*~ { P,gnDp*HȜJ`y-v h,aF, .ȼH Q>b:ݦdi#*+dOeH]Hb HJ . !+0$֊O|ۄ .Ȥd8^%$BvO% c%eehcH&plcn f`r"eV$ddK$ oU$ R#4 KQr20 -lRINv,q -@ .!-0q,2-Т. 29l&l(^+ 8&m.w cΚ.42Ɛ+* S4Cm*Bq j ,$,.: x BCMfn'bw*Z]\#.;!S; btȊO6/NKЈ,N*ӈh>KeH<_hfFigfdd^"ZLMzU@[!2hkZ! 0OD1г[֫Ȝ19K*\ VOH`pR", e"&cEZ(.`_ *i"₽0hݰb! Uq_JOfdcPB' !JpPc4a96Mф!+vdd&@D81I7,ɰq.U.. w&ɰ-B0S&p.U *l) &ɬ)PFAL`rwĢcz)>-pp0N/v -ix(XC"w̱ //X D>,zi(8*?Y n&ҜH!i\m*a]X]Aly^_6K`m.Q x##gU>s=4gǦxdki7Ör/q=5X6}vTz*4y>9*pQawA7C-0,$՚h![aaZB8wkZ8HH8=8rh89b=M6rྈ>M^8{>h _$dļFLRPT%ceo&Q%#?Ed" ֳYv+:8 >Mm.؆Ҹ}>֘Ym<\kp ȽL kcejKPK@bZev[eIVR$xa kee( ܹeoP% ]:fJ@K/OW1{!jv|W8 2*E$Ĭ\del^ed\VeTPKBb@d'+۔k q2t"scZ#Z f;HcJ"5ͺGK @Ό@O* Yv UWO쎖LԚfSQг u(W($ҜDeLHQ OsKc_pX(&:Dgpmr%%lvݦW'bJ$h.ݺߕ%V$n9 sNw=΋ιt]%a+tT,-𼡵-wIq5=wNU Rg ɣvqBb-i7L,vI+X4lF6ά5(j'(9n8|n<6<0I*|zl̼bV 7©C'7m`As)]^~`6Ak(m!  euȒUQ ;g*On(pVJqV]#F/G094B;OZdܳ jY(#-jx[,LDKX#Hb|W%2eRew ڐd"фr+;J0b a-A'h#lml?RH0ITW*/s5G%ynx."} )?ક: ?՗XWk;e l_˓/u&?ĸ m`D&/,Xer7g9dM]"}V+*hX=B}qnG_{M;ǿp=xqy#_[j~A_1Q:r4,"0UBM :QgERa_kDkŦrQhG!D8#䌒RaIy)Ἢ>Ln6 p9$IDSaCM9=ς@y=|t8NC2&9tM@o[>Rh5ͲI#>Ou:?P5$9TNWUTVuM3L%' ETMXgHL7eC xKV%0LDfs 'So['O\6q][K]vEKME$,AR$%C 5T$@cH9b1.@Y7l EgefN7#3gy6Pc}x:ixg-VC֚[#3g[fmCN⎣+{.ϳ x- ͳ`, |g) R:3>)3 0hA_s۵3kH8HlӨW˵www { ǀ?Ou@Y/ق߇RA@ T g ^\X0%eH@UzlCXq-R"DIw Gц #?ƴ;$!1 v?KJ)L#D,SZj 5D[YX!L ?/T#cPB5Jf23S{N(н}^dHe]˵v,7ĘYˁiBILRGHsJ):\JI:VҕpE1#brLAd qY1vӊshMf:G*ȚLbT;e)5GqX9kyc1fsz85fa&{LFi]29k$&ɮx^mmt( v2|P`Zf7v[)e4KB9䜣#Sj 3NCu,>QI~N;gPᤫe=c_WKϫFVwbsꓱ{|JuQ(Q]KˬGtPMz c(@K!$+!TL*xX:%Oj:&aa-T]Z[lPvp?}*Chr-.\6?ˀ&tIaem˫UD]MS >T%!p%2)ZX^>Ʌ0^ CHE`.ۑ2q&尧JH[zt\i+G .X QIQ*`?Ki@?@ 8o* xfYZѭ25{ַѬK{2ʼu=K@*&1ni>'L^I?׍I.!;wY G>ވ"퍴wblUx 8ywB&"hہ??E180BÏKYZNۿh"c6N㜂lwS]ކ0; VW2k~1r7yv$n(1"8Fʼn a4VVvADžN)I2/_+v,}]/'9& j'5y4aQÑ;z;_ق$Cw-`e(Mysl\Cla Ei%'-+RHT;Fruȿ4kb|¶'] { Rދ3Oa#Wq{ ᝱5ڪ+[`,?X@z([8靖ύ x.R=d&*9Km*6A.>R|aA𺀼pZb""2؅h$!x_KWY˜+$P:ZC6{y- aY:)6?:Z> 㥲 ;J;; Y$1& 1Y/_Y%Ci0P%! S L0C+%cEL+%BR2j2 b)R᫬B>L;'0'63'r4rk02ǔC#0Fs4{$gb<&#ڳK>37(@y9C d 6RCY螌c[f!Y y\XBqZ7@D r偱sS cy)G|^>T7 ,a-*xR﷠C y‚$30BE/0 C&*D*>S<7S@#C 036 FTyЩ4 袊; 竀 C#?Iԋ45c5a7+5Qb*ː;.yHH=$A|Ǭ,j '26& $A363ЋF)>R.-B@P:ɚsA€C#+Ɣ;& >)9N>;&4!*/èQԇ3EDO8c-bM4Mf۹:DR_ /!+iEfE̘z){GTM>C%(c'F1G:2teFyr'0ڲtg@<=6(}C Ǜ<3yC63J3c-(;<6CcZ`e-+(۵X֍yskD+CE$R[[,CђAJ(Ӑ=T Z6= {6̫C@ 4CE(2O&Ha[M>r8(Sp'J>PRq(=3,!,8Z{C":fʓۥ ;Z@2 ;Α8 U"2aDO9b [󨺙e[٥Mb\;C;*RVI12RDiZNz ˑ5UI6Zbq(>M &ڳtbFUkڽ6FS'JqX@陳gzB{i=ɈtA5@(xGЍ-{B8)Ă*$@E1 ),{k?u0Ԅ.L6aȣd!₩+0 ү\\}8睵<]1܍@4U3\F>7z;'%!/k0PLy >UTK92 bb;D9 $.<&d PQEN[qdZFWNlQY;ZM\:9#^XYfې٥&cMQ0C"R.[$?$lZaN]nb1IBbA@J}Ҧf)(=WsئFT-=m',j+'=(;'Wț3K-OSڽ>uhA[3u-'(eJZ Yb > IC"]$CKšc6M$QhYpX +C F,5ҥ<,*^scB䶾#"JAkJGJ0"^&+=@tr5x@DiŶ "\ 6e& i\=ՈzI?e?e~Y9N[.C _ՑZբ.% iV%i;DO:bDni^.hE%11nyl.j9Z:C] !% /8'zqFzOi e(S0=bɢacC2q `ɲF{4r|;v>9qY`*)kk0q ^Ƞ\¤:b՟[cBb=]Կbx#B [k$j[j&.VfbJQbeQTbIQIq#:C a"T&J㤪EkJAZPii$[D^-b^\O%QoYi0BND0DٻiE]i1/FjIkb`C!ICgɎ``qga&dgq'iFFbwchWP4eri"CP@<3> (?31 3ds{E }# e*kIb4Zcϭ\ZHsr#sRD\ \0au$cгÛ 'a@9黓tF#,j[ġ/ k;Zd7>+9#+ʿTt7atAxD7$믤0C.E\a^IYNZC._3"$E[$j/u+4Q\ʹB@]B*!P[ ! sV#Z!s$s/@Z/"BA_C P $>_cѨI?IbvE"I3ls?ljM%gJcsSC!g´5fSJh?͖{5A6kt7ll5*xZ9u4RCc $+q4-rbZ\nsÝ8n8Uk]ʫZL3{x%?üuyH&?}__C{@??w_?= rYBGY K9oDGe YšayPc>+M |xGaT<DrII2LR(eFWLQ4̳QeYRyyRfV EaeRʼn䞐^$qCM\>5d=γ@V$~?#r)f۷\ÖŸ,"ҽ+kP*<~jBQNj!0C71ŭ|(/XȲc` 7W5u` Gޟⷀ~ ,/ uj#q|K9 G7&RpRq*˲OCO$JX!p0C$4Ad F@р3xT Uls C'A(T8 `J1U$h b N0ZDE=5XR CB@ (OMG!(E@d}wV0wh:6W#2+|۱q$ڹ_K6Zc ` m?nmZ<T}?*K%NeMΣEɿ%^uNuX'}+ܾۇ&3ܗ3cd z_!z\v>6YJjsvʓcJ/odɋ/LϢJ,0EL .Y3gĺ7%bI_*]ؓ-\g/,qa/؛X%iza>YQJWm$l̻Erm9c7HHy|;'Bn黈p6MQCvhRO)-~iOXzW\kثUS0?§:=czQƋ;бqH^g?,*Sv`~ AޯdKVDlK'hD(VKFErK(6+FDn.Gfs$8c"F.@ rlv^z^)ODG}"gEJ Z(I-j.q$zF $gxFaĉaf].Xl^ii,^ŅdWb NL. lH(*≤4I^.[6Zt؉ʏ<,ޢJ.m,/(#--!h|I+ **Aߨjjԑ K@+/cصnQn@m*anaip*yr8. r-p 2mpֶ1-j-p..NҲ #j&J.N@9Dvrg~hAg 'huftGTd0nIJ +d4dM>Dd kDf'Ԇɡ rk@GrR2DD fI2z ı%*m C0e*R-VuQ o@ͷ+8xnG(OD@.pZBh5lffE%{<™II3p,)Ʉ(ȧ2)蝌.4fIɚuee /e$WX0N%]a!^Bs+f"brzs"sr+*ʏԍNҴwjֱOac&> 5l%Bie $S&-*ԔtNgցQ`؇E } H3RK%*lh؏MmkDK8AVz8v5'sWQkrGbFF+b07*$OP=+HK(@(4>VA2`@2r>J+z)Dzx꣘BmL8FԜnOK *Bԇ3K(t>6r=+H8DvDgKp/$r>e gYqN0!yjo+kwh7^LyɵfyMY X_5Wu^i5^vK ^hxb{U Tn р͈푀LS88ؓ!,:Bg7#s`&&짘/+g)^Z.X5p'VuB&/b2 H W G@s 3m?@ϊb.z8 q!$K~dso+z :\͔X#;@2PF-)N匃Id;Î's Q S^8"2ԝPyRo h6^]FV^&-|oz\)|v' bpo` r4[u'%SMRDsR$$i@hTm?kH.go%b>ԍVm䮸'OaeX,ՏMb*&K/IV$ACRRrޭ +FSQ^glfʑBIkZtViÿx)hR )+_SyU镕yfudƍB ,?p~! ԰n0J1!H$Is-1iD4GN&JP55H2RARWW}z?W?Zun<ϷW?kہ^;lsӑX/g,9ɡg<ѩZ9VfhWԺ,=Ԛ^st=]6v=Dvz6#6t\g7brg`GtA`! P'1>QCAQE']^QƧkF1gEqh_ ᤇFQ%ɧ(Ip*,F30ײc4L%<3NO<5K B'JF츐3>m)N?@F3 RV۶^',֍G^~ʂ3t=NQ7ٵ]IX pN\*jIx'v\qtwmF2:|A=QQaSar(V'ac2Ve!dYVSㅁZ96KX*Wg( W縮/9NņYQ!=x`NQhQCh3j]x){v¤[Mve*[[Dp+L*! -XqA'.[\q MӼ+/0 /±tgX7Mf3S$1i4#%޹ֵ轵xyxM> 630~?gP}dxGiw'8.T=uP b 'V %e>,4@:m( B$^ QB*HXa4%'x?L?*!V UH]xOㅁb}v$x =1"DNAGXaz5;?Lo^7&Crk-Es(.KD{2&ȱºnKJޓVlk!<$}f$5JuDxnZ8|#[ǩ2[e2ݽ/&ܚKQa{ I2,f",yAi7G ?uz+QF&i{4q*|Ob:GE%d[] t)EDC-ּfu(a" tp^72Gptĺ[ڂt r((ڭst?'_P䢗}Q?GS+~DTyʹ@~f|cl*RΩQUcα}aQ~l2v$`!eGٱ @; )ڸ] j2QqÐ}!7#$ڔ !wjV*+[o!J?״vۀnqCS*-L0CHյW Vs$H8Ȱp價!QMpdtNOY๰ WueBavܱs:ev^8Hmr"U+?-Q@^p[g`u(l?X-qZe+%8^߇$0q˸-x$ rO skn Hh,S4(^0̢Z;u/Їd5sW-;H/iN/bԦ[~s: њ |O5s)efLfF&B#b8Qsr+sYD3mCfH mʌ3%a{4j-M)܊hpijS 1!f:kI/M%A:ZLF~R>s~%EWP5>M]S4/;ݕCtΚTX rW+T+*0; ,!| i2¬8 { -@ |Sں;;OA!9,8<F% :/VBq&jL<ѣ%Mj40(ȯ<"$ ˰ :[:sM%8ªD4 Eӗ )`=8(~(ɹ(!#2*'r{'9 2j|&k&)ErL3|9L%?78CBa`CB4j&@Ba;=󺗢[ ⛾tF P9{L4C"'9*5 NYKϖ2ʼ%@_y6h1[Yǘ*T|RAr0;m; 0)0;"۬@%A̒2, /83`;78T!:#8T!KM/c@&k ']C:fI8OIZa" z)3AjJ/ G+@AK  `;H> Ǧ𩃺C>ʌ`4-59sJLGl"J*ϴz[ R+@cKЀ?x\BJ/ *JGCWBܔI Z5scM%1c j&SʪaA8顺з044!AK˺'H[S#ƚ f)X&;:A99T09j&J񘅨?]Tt]249S ͩ#)$X(@H4EaAjEqB`DaM Ŋh#Tܙ]>'|Bх W9W;q4(cW%@xZ)EANd%cyz ^4ZFAwn ayD) 뷊HD,ԇWMGlv@1} Sbc 1)gP+T4aXHsahT;)hIIx% A,^Ui|'P]\4A?TQUsd'~Kq-07!#~4PB%|J͢=?ET&% P'e5ɇh\%̇`o 4~JI=('nLf ]/ aj/dG lE|C%Z )xc؈=b^qfs2E]JyZxA3:iΉj6{ e ]1%Ӻ_O" ]1CgkE#a8Vvh鷛B&]_aM4Y// |{4v ,Q5rJ*[5u q3M*hrWXA2Tڬ\w/]X1|EEtP&pÛcLP!LS+R4:$],rDk CW:Y˸N0\0ڃ)ƐЊ[ESA+ʬ13y( zcYҸG`ODĹ414YjTGGǻȜ^4]V ^Z /[9t] MQ{ bU@FuL a-6kB}z;]h[:Y D_H)ػD,PʨM1Xt qyP(e  A*ʾ.q%+I.tQ+H aHϝ3{c࠱lW^ᗼ oʧA06![";I)%nD.AT A4At0>?d02 Z8RIIh^ +1h*&fz~1xئVu4)z;nۊ;WB8WYE[r[iS[nn'*:*|jN e8`ENI6 q"/[XQ5 U/E QILC@3]H–3,`8&mn+_#@R~&jsY 8I/K8̞2>h*tDռJf; A ##}-:Kqh3PqqY(>rL`%xMp 70Qkq':ֈDBājOIGPo% 9D4Za盶E~&9n:(":Rŧ+ļz_4[q #@9ʐN`]hBf| z}b]O(]&x$O?з*F_阤 ?ѷ>O-VR$^MY4seU]svIjiWXhUj2 򀟏@掠*h#椾Zڭ,GV7j~+&>' lEk4MC6 ˌB0ͽp26 *+xr{|0Vjxix'5GNMO /\UѴqn6j˷W('{'%ɾX{@o(wŷT) ñ2/L_Vl;n. (V%<[[U IGB $2NX&BGE2ğN<'ԋb ba.bc*][`{@f@%bƀ̇0e }]0hp: ؠ{wKVF,cwg?hFhsF] X _}R$GKeIUT4a]0A_+!U1U\ġcj FX"*IJI dК:5#b z-1Zd!3Y+}*Zk97\mmnuE[/tS;@ m.N\c}hs1]W+lR&ɹf#e+NQ(쀎**GkwnĐ2$ؓ,'V-:5|}J]i;$@ qj-1&pC\e-:ȉ1&;QCD,eRx cv=Xb:5wC[}rtY-9 ɤW͏kcqNyX- .ȵ+:kΆ3'qM,%4:}2\C&T6 !rYZcr$ڥqWJ# h5QԎ*<"3Nf{F ՙ'*t_Z15 Bep^N^< }^Ε頼Q1F3+ꕹ[n@Olejo'PhGPtk!+"6V |dTHdCtf*dN6 c蚿_Ȝk="BZHR("EXs>2m02֜Bts.h.'F~,'֚麙2Lz*NT$BD,fiqo<,f.amg?(PЪI;ep8$mȣH vx>F*y,.q[k-&O -Bm/.qHӭ8B/zq6$"qޟҝG2s&x(^eau-K#K Sf^i R=H] Ț]fbg0cf0XO˞= nN9\iGp% ƢJj`FA""LҀ"ʰ Y GTuޖqY v0"H<6Ƞah>R'F^$e`6k5)D6gsjp(CIjg2Bbii mfs.iF#^M\1`{dlXLI'2nf讘bDbR %h[$].>F:Q 9fm0@llrV1Ho5*ŊJ /u/8.j8 l53\c:1qs`tEn*R.܌+߃=|RGPP<1= T>6H XgtWE"B X&YN'Ljޅ΢L F:܌ܒHmD&: E+x!=$pc6Zf?Gc@b9$WF>$e6cf$R)fR-B $+`f&e=@R# ȴUxWF0>c ch(+I즐"t*IP. ¾i8Lf1i FI0-%.`4u&PRn^q8\ K|μlu=: c:_X̳V@/W ^~D$|@RIsҠfe\a5I]!؟ލP8u'X2 nm܋lfN:Z&B'FS$⏫EJ"I6^f>rQ܍ȷY=aĉtfYLetsUXca,#RYmfO\exR0cnBR$Sd8!Xa0WG?p(E)uO1n2imm42 XZi -őT1J)&miN"yjJbҤ`&6eCʢMTY>פ_#׃^kR OW9ay35]@A\ QYY/OΓS΂|d!\zw{`M\ϛNOizz\g60ah 汈>hA+HuecĐ*91R(dvef ߃i gJ m\vFkgrT\zgZaDygցg[鴰S֞ՌbtfEbA+G\_ñ'kԢXﺴ~~ӊ4` |ݍ;e/aUå ditkgBCK GWȂREEdaņ)je ofЊR/ CnaT#&Uc]-%O*`(x,|Пm`.Lni,N0 TLNCΖq+lT0%YS_8dyd&:ptN3%v H/-?l=Kcm??RHS--ft2?xOsE)E-B?J@Ո5>TAZp<Vi^Ys :q_gD9mB4\cFELjƥK@UH˾y>L l#I$|% dlD*3dJ3D/,{"CNg;N$YC%>΃ tE?e:#@PTA-ˤ2&BSETgFET$ 3=U5}UՋ!< nռn]#IWA\ۗeN}ȸwnRYugg"{q$#BwNꃞ~hQB@x W޻zxY?QPFoJDJj H@mWL޲i\2;ӔJafD~d!b-0:Ԉ{p,Heb5v*)Ԭk0+SdL`v'D;JY_@`bULׯkmnj #?չq1GurrG ָ:-%b))1i#QWU5@Xa$&w `;|$cT 5Ijn?5%_6ӗ` Q5&({sUV/. q- kvP?g0(Y%=9#14uy wNXִԑqyYxb1F>R1cGfT\r!CʒKInEޟg.CT⹷H*{~A p=H=E('{21F9sHέ2˟nßOcI&3걆%C,s.}x0jQ:ڙmlU*,bHd P2(+) A[1@qFrLm ,nw,[q7YW% uJW(oaVvu:lòH/Ō#3,?un4) Y m 60@(X ^0|[V- }p-RRB$qeN>~7n0}vJayeW| :50(a sPSֈ <>t)϶h4¥93m0]$#=ȓ|JʫBNDLM3ͦ$7V6AS%Co#nEykU*jDpUa ۥf t Y-Ma Eckl k|6#}`7y7y}.H0w7Iq-uRu\5I, ֡`+i'6;ԠYy6"r 6XYϏ^7;98,!d &萁P c$,%1 Ø' + yQ$6 a1*ݝ30Ŝ՜+i娤Ci#:/83Kޒ1#ȝ(s${ <`(!r%PJ15TEiߩRZ0b?ǹK,C;7QCMق.UYY 5fN:]&z@;: 6$jHHR$oN*_fjʌ X$KF7[KSM4;BY9H&cݖrZABHR8yFာ '+RR P_hFUPUM`K=X "$S,S]Yaި(/D ʩ}WPy˪[HZ^@`\i/Œ2~L;`-l6%A n]^_=鎄OY6 @ц3^x_SY(,Y0bU! :2vx(IMľlY΍.w c 8c)Ȅى42/JLM if\@I?PZfKIN #$ \왖 sʍ"o1HQe!M c.~p7%%i2\q2$0H)Oر3K`J!}-Q9QD[Z-l !M^> 'k!DbI9;-Tvr\8ȕߐ]V2CA]ch/8dsO;gsW>s;'@aC_tOB?5s80` &c6F ,rAA!vj 'E~%wXU&fHųm_uϲCceS@614:Č9Ȩ,lcPoP v:m!+Uh~ЈI%ΈUeevm@݉ZMƓQ6Nʌ !!LsBA\XA.R_3P-C9AobSqRIASaL@&QF4rh IqW N..0=>k@g-qnHLUs*S ]c{ϼ{fs:ses=sdo6swAd1>\#?*REt(KK&LÞ^Wn=ҎnE=r|gds82^XtZ .eM\fe)[Eq@0mxݞ_ϝc&!E'19_@w-m池([by"?ѱw"4HGc14v?Βy4+%|Keyk8;3{P_CKYG%RH@Ua cWlhJkeG$){o^Dphފ?v"4CXMѣ]9T3_톿c/k5ڣͻ dep'(\`Ѭ۟P1oE1ԅtGC! ͹}y+}$Q@K<RT Yy ё@dX1y`FG}pXGi DZM"YWII(P"KG(IˈF?9*D2i 6i 蹮CL :dKKQR̷0lAQ6 AG(JE=9APl>StPTANlWAu%1#5 U]y]ץe!]5"TTKLі?ڔESO NKQ(2sC<>} D^v,[xUE%BPd kа tm5+Ӻ줃;YN:([637hxIiv bgaVOabhݹX]v\wx^|\Eqon[FX]&#;큰2LwϳT.<hBU ÓYʂ=T$˶w5b?l|V# k~PU IV F EU4dQ*-uwX)9dsFt qEd׻\ {O瑉ZE+B.?y[Ikqk1o\K){/y)fWR]Kqq Yؚeq8)Qg$R#]Kpn@`egRNI!T*TطU Ϊ M ,'8µ .=}=,R EΕVDQm1Cp[\-2LJP.wJ_ܯu(6#Y9'AP]RPnv)ՈB8<1{y8Q _QS>Rk-*22DV(H[]ӉB@՝N*~nc.]]f ks?5(c+-$iD[1d%Gg'gYqL&xZ"1D9Ɩ`^l2r˕Ygr;G ۻ:M"dlgVMУ8rS RLi B܋ ҅߳ňr!3ua(fF<yXdUɰC%V5*Ŕ%ԕ"8 i0 t*ڀ\}PU(FU\}u XbByRZ-v^[)!2"&QMɶĔ-vm>G[ +tZ ИbܒO"?>㖏gHԢj斣Boλ;c$Fr&>"-VFngH) M&kD|`^? R V,v*tvNwhPLN>n@l&$0R6Di* ʊHd$x@Ĥ@JI.TxHtJEA*E2 '$(PG̝JBF쾞JB(F jBadtLGBb`X/8TST@LP]@2 h JH0rTT@6c)Qh 善nB(6l,&'vPX*P.%D.~GHJNiTef[_w<՟Z"qb [PH 6VHP^0XnFD)-$rTXn4JlL%WJ(<]S.VVK X2I2W^BG/dnI*$kIڠdIH02boidFdd/IgvBTQbueKD %",Yk e5%ItF$aBHԨIReUo(=RSG%qݑPPbOHO(Z4cS\#0BHgr+"c=v-&c&L٨g^OL!m@RA0,ID APSe:x{T4zkG&nVV2vPNTx5jjv*W9HCI\az$iۂezEj GgILf.BAȞʥTVIPWLyFL%6HHGH)'ŗT%/;EMy@吅2;e~U;xW(R%^ʦTDZc[AJ带$Y~l9r"YB`j"hB6i#f#ӵw^}Dꮢk!bPX6#iM-t&^&?gF[9e~²MMW93ͮs)>2.UZi nZFV~дJNP Q%3fANI,͇]n[STANgg$Gb(GL"ulF'W.\jjZϏodğ,ʕ%{: Bwz4XlFpFvNvuelP\`[傝5 ) /D#kD~rI%';:Tbʷ>Ic)ҞIj.ZWJZAN[]ٌcx#-{YEl>.Oh*^8LEљc-=;"&""x~Ko~9|h$ȏVB^BT++׻o™{˔(ILlum~#q<)+e"BQϐ..bh[P0R e@-2 xyKE:uj)(9 T`rB6)IW"ԯ Fd%&PX,G9'c#*ekxO,vhG1NGvLM#j\FXwf{ hGdE*$jܓ$[ rB7-S:v:{A|O!{>T8HbLEMh:]h+9,JSd6]'cZE %;F.p#K 1OkݩX}2Qu/fi)33' b +(gG0+b‹?obk>ɊՂ8 ktf%9^MUq)Q%${ϚUs bo?䰋tŭ@[׈FvdJ.wz5: lEuU?԰WTsmjسaŕElY46?2؄Ik1WpYNSɪ_![5wII#+ ZY.SՓEY@yK^Uأqy]YiTY B=^ouGp`0V4 `ZZM7m7;v=~KM6>'<9'& N<*WxcvNtķ_?G%|\ϝ?KxϷLL/ QHA=/Y Aq @P!) )|WBLqBF,o0LDR4rRT@I(iA>˧0K23Mԓ%ˣ0=JRt1M'1{C4T;#O0(LS'5NStAOG2L9.(铎\9n J2Sض(#:+TB5ٖe`bڦePWF[zԐ) U* <*mi^]*^!ʧ^W#$6r]lZ3Xw.,}]so&%Xݥωb q*75u¬նRS o^+jUU,UP5WT#69cs75^6: tډ(غ5ZC՞UI'J5mћH;nB@жNnQKT'gE$DJq<7 sQ^\FGH?awT8}CEd{OCcӕ)Rrnf~LϠhf&v F+J#r״ -mT@}lQKہ\?*eMoBUƘ ),4`C5Qd̉-RŅ焬uBU$%*lv弸W ˱w-f0! +ÑGK$VS+‚4lbAWL/TlMRiFNW^^HbԺ 2so!3AY{+%@t_Mrlf9´2na9%&|Tͺ2|yI<]H/a8W 1àJ!⽉^'\+{!M1{bkLtzGK7!/NdRoAfK7&AJjUdvRY6d ۔F-TndO4'=ea4SYU%Ty Q`_S2iU/v/XcuV轪 UQ +싕2IO'Nbe *qF2zFQ+)~Z^@1 pְ]J2٥c s(LK_{HncyN]k0— J&MP.bT @SVA> #9NUo98V(K(\`Rq9<}|GY<=+pqN6ޛRc5"OQ=GSv{{)}Fk=JtT{~#}'- Fr[:+Q[^r>(};<$V%0Q8wՖz3^XnWYZZꀽ.0s l(I9D"X ;#*6f=~eÏfCsLȒޑEVIBI+fЌlmʛQ"3b͌h A&iL\!'nDmņ!&BWI[ Τiof$a.; lgӔ"UתW \Fo"dET|`&Bۧh:fJ)):&W4]8(r9RHn_Y;G{;QE3sRKr6,ܣtabK!Ҫr2- 6H71A6@.^v|Q%B?l m'⯹ :ݏ ׷!1<*`soZY Ja,4@ǕH莊 > `{ VS_q.HYmq!f1~X2bB㭺 ".#$(QoQu2q2#V˗: ه"`4-xܬ(ت<؄K ){+o<TDik\0ڼS *a(JP:T麛5c! 9A3AarUCf)9&+"k7a,GyD/y<)<[/Y4,xI⸑2<Q:88waIcB01 ㎣:? YENˋ^ PѺf9K¥ӔIh5 J Z1;*aC&2 c/:2+Bԯ<+r 0à2pa1* !ۖ񁍉u3p,Ș B#8IlHCtOEAS–< Ai@Alܼ~X( ~Ĩ@qƩRMRJ1->( _=K4yٹ?QP'α ]1*Cx*+ya,.&7I%:79ט9c~pO: ~&8ćd Y?yU>IQNQhQM,`U FFA1KGNc揹RIJ ޏBɀų8+p+12,5C"+[3" C YRX(B{P A؍̋[DHQѐi_Ju?ÌÓ9$OԢPt ZU [ڳ4 M9¨? 6bzFp%%@)88uxh@P &:nOv >' 8_[|+\}uu|BpWRu%d  <"b 2~ f(ߌ\!ah T⟉NY9iQ$M%- Kn0H:YR⍠h["3:-q$2 ;+6Rŷr2cP V^a_ YT}21&% `18m&;-3?n~}Bn_iBW*amNt @y jh]a-: e%a{iDc$"1XKxa@Y>ސ) TK2C"CAt2K"ZcK#*ĉ2ETF=+`[L 9LK1TIP#1S˜ iЭK 84+T0Jβ !s2:ЋqVԌ-bU]ihڔPB.ܑ1K al0pYnmPqB͐:f#)k&?W*%{.<'0vguHIZ"ȱMOh19e)R bQ0a T OQhAiKS*&y& W9\IhM]5.1-)dfrF32ڸeBeQbɁH2r1T$͖H,܀± ah P0 @۰ܙ4ñNY .Scطe 詴Éo+Út|10H~du hhj ƇTVqlp) y >bc/lbmG'bAvFqLq oH=!/?9GEWosry_䂞Jg)ʥYcu؀OIӶPy)=SOIP&:cg~BmhwQM(0ǗH) &+30>83(DxrxUs#讽^B 2DX乖@ O XD `'dzVM{pI= TSƊuQf,uOv8n?'}խ4:?Rد lU5{f=i_B Бt2LI;BKU*HF%h$Q,dSY+!ň= Gс!E 1)\&QHjI/Fr2ǩ|ETJ(B+ih=) ,rҌM T=A=OT84>QT"=UU\4և[u[W}SP1II\Ĕ=4H(,LcJdĊnʤMr,OD7oȨgGqp7mĆJu$ F$?$UGx %EF1H.=SC\dnQ9[:[/!fYT^odϻvY& h1ANMiod;N[Ax̱,a9|ʛNP 9mQE!ިhk,BT^tH^fmAgo^7 om njsqw ]pRË!Px)`-~Gؒ}2v-2S--FѽtR'R/K*CO]=~*>?Jb`o( ?Ä 9qW*6AQ mBM!>CYV W21Yp&(NDol[@3nc"k5\i15Co&@'ϋ"@CFK^(}6fۺc-1.6okFk> v~ь2rn*ܫG50݋ٌc2@.:E#pV*# ,z\$u<"Inċ Hp7(CT:YD uػ :"Ln"-8FDRT.EeVbyN(cߟdyy* m2N. pdNɟl-[ǎJI , \i6egTҍ08L[iݳ7sݹ 홍u^\mgmj.2Ӗybϣs83=.uKˠ&A# /]MԎfŶxћSRb_ \)y2]PNͲ<)"Č(hb}>cq^~<У"WzF sn!֘Y@#5ǰJml|2ɴ96C94%V,ntlX;E˩CqRD٭om(ͷ!e6ퟟ]ܫ"8Me{?gnR1d4-Cpl^$%$hB\LK! p!F*x|&aJ|vjBN#&'yG垾vQ$XMɄꅌ NYdL&' H\ "̦`vp  J U,N`JI$H ElDc&2!_JP{hHЍЈ(CBFLN-.b(a-bX-p^b c+b;P!f,N,Ds >BF٢䨴F/~,m-Pj&m DH*ߤP̢ wEĂVȚk >ƇdL fCvk5'*g"7o4v^fH/C~2/4fDlBTl?IZ5 C @ro2#Z/21.$sB@EEŖ+0O'N+Zjy*)h sopt-2.0.0/images/cameraFS_SARA.tiff000066400000000000000000002600401277570055300171210ustar00rootroot00000000000000II*_O?PJD_舣O v %@IЃ,KPs8m7OdO'j# G)O {?57FV_:M_lO1?6~ \_ˣCwmv nwZȉ0?ȸW/d_嬣L<+hl`~Z\3^-blwkwcw^eb*?}7?)v_.߆;7_og2|{]?ş߆OOi8B ȴ,#44>DD>ćTk 9FxƱ853601o243I*4B IP,#I2l2ɯg9L#3:=0|"=C8TkԌ+ȯKős*˒4cY6TMMQt%, 50YVmL]v(2ļ.Cu:(CP}g+Yvz=mͼ )EA1ޘ pBG` B# G%@>%{byHׂa 9 )I 4Q)X]xpXU#SC1căvt`zM02AH2B%MX^6VKupB)=NaIזʆN*&-A 1M`Hb?rU-DT޺}x-׻ cLx؍Cwպex5+(,٫wر0_(B2>#)͘͞gL>$O*6=4D>y8BORCh{VjT0.s6>KD}QCW̭'H"a Ӗsc8.CQw 77` `&r0hqN9eH7si7w"^BS'Oi  $ZLo2 vj}=!qgTN1v1N \-T1FpͤpO ?mI|yZ3iO$a9ҫt ͫ#.Q=-cNV<* Ն&ZڃOi^dv2f>S*}!bhS#2Ο 1"DOL'(,]q4Kci`nX}[Q/İ푡xNV=ti좽ͫp4ȤL)mqZ|~I'ۖ{+ekSʧʚS6X'Ӌ|4tt*XD< LEvE e5E(F/-3a:כ' dxl@&׈&1T*[l?Hx"Q%6ׁCue3b ^2ݶ+.SŎ_,Ð{ԧgR P`?fyXIg2t6FYUu9ɒ1\*/콬Ȗ-2Y k3""(OR{ q(#?2}g j&Qڗ DOH>wb}ڙTtO)~r%3IxCvnMλ+FW1H] tjw $/J {>#3hWJaO(?gQ`!PJ䇡UŔBdD"ܶ|5ƾȢ~BslwN+9ˈ6C΄%MMIm| >®6|"dGY?\rg/nn~FK1 x٨ >X%:r-s8PLM"~\?Ǐ#<:}p̾]Vk3YaYWI^e#/Q#1dnjq=4 &; SĉO)f\G%Erڟ֓,osj"R,HBU͚J|NnFC ú|R^'*mzZF<총REa&jFl7'jRD"!(_2_'A'"v` )` b4Bk*(l&b)2>Ml=gŎGN)TE\D8rԇoYrFN&tgMXMBN+bpjD&F~e\OB殘Qxqʊ;ηqģ:lq>mfֵ&^c8>QI> &.JJӌ5LSztJ xo+Co"C>+ #?0< 2Qb.G* >i`d6jab$g!zCeg/2s"cB0UM3lJ"hB#Q怮`CtXYt$@CcM$m ^ KU ދTԉ:$PN0o*J`^diϡ%+gU J.$e > 1pU sTHlG%lB#13>1i|.oW Q'?.jN-EfQ\ɔ4ÚpJI[)WW U@.hF$ # I:d= r+l3u'ZvK誥t& v]Y#T+FGkA簀E4Ct/,$RJVPMC#C%$1e9DbtH2fVmB!񸻋NNB$(潤m(rUlr{ Nm.l 4l!ȩpfIJh2#rnbw?A("\rnԡo+JKleM%*Q%dkR%eE,f" CScBVX2-ާpW v5WZս8Cr8.N DgKRu:S9ʊw\pnzn=8p쀵$-2FtƓr3.wΕ`!ׁx  Rz_P a Ej@g޴t!cAB.նSC8_NMc$|UG;nN;XFTN7TH 3Lr=uX>Lo{RsGdU CDD 8eOrb&o'8ᣍqpk'kG+a`ԡv*GT >(#&ԼkA*gMyh#d76"]:N2_Gn|KeKu1hc60^2ORD<}` x[Ψ-,vՓySO5Lmuo3 &nIFlefHQ9vqi\W 2^aNq]Bc&lj\862_xmhV͡ }vEDXh2B)&D~x?@^qݑ]ABXKo:aB(v}句<{Q uQyU tL؏>mVʇ)FeJeuy|9AO$o]8!)J+NI)&abG$Q+lfmͤFf{z3TWP䁖gPOL0xu8Pk3F+86EPPXCI4J*! XÜmumukY:Þ[5^,mjU}mqV93WLO\$√-C3W9p3dC ;QO6vNm|[&O.gyew~NFvGU{Sv-ZYyQDr;OѵĈ5 ;6Elmp$I\c^36hE2i^k&tfNfnejlrP;+[+N _ kzdboD1Ek6FvgQt$dG^4H[^;"ģDži!EgGM3CړD!8=Bak/}^\*C֒[$$mVVhB>]VO<;##ξtT]t~p on^kcP5qbU5`iTI@~h_}w3Q]_j'Xv| w wD'Sn4[фZ5:  ?~-C易xɎ82I%C#i5'`?T3QԊ9Lc }FS(tX[kzbSkL~aN: 4^ _e*p\ag)` x~g#J oc3&VI2+fwK-؛%oO.S:y?}Ǹ?w7C?~~|s(pD@oݎxp"#5glB ;D๡7(|06jhذƳM$4PIk:6(, "TP6H-!H\.DǎU$:6S sN;= gcCaQGIN 5MR'O=B!)T - UUVgK[s?3* ?Og%cb+L`>OӸ@ [uD[j`İlR$+e“2;SGk{m71Y`ncn ' ti!s ';RD02Bʐ,):XejįGKe5bfVqg+R4Kίd$6:Fbm]Ȟ:t%bH(k+_+|akhAƽ[]okqx&ug:*64Nwtwۻ}SvMP*JS$тd~߳?me*&HۧD%*ն+l7ʄzOTʡ2 `4LCNZ[O9ݒv1TF׃28;n\l ªql]!h::-CˍfȳbB3@GqR,I};vۃcmN sOJ!bf9a mv+'R_cWeI@(@/BZT[Kr G_\ҡ?tTXCS@ύIGЕ`k3.uV92W"ҁu }\6*1K'" #3!gQ9MXAڛeGؖԳ\k"t8jNykq\h#xBrJe nB6œFOdN-"-`g+,rr%Ժav[|b31W&x$;PwrsWn읦xj{pPm &K{p0sx;N&rt62zW+ ~1nDge1b6e DNYŝ} I0aRwU{OBr\A}:t2SH((a ^vyt1CH8X3`3G\sx6#hTA ycfed̪ydMuV/UvDTc}w۳Q*t#:%'K%($F}٥1]巉1)7W(ˣ@;)93@ С= ɫc=(% ( g| 8H 6 jg.r% c a̧y- * $B'l d Ȯ73t 떓 6#02  ˔-~(@39!ҳS* ,j9ՠmĕD<4h,Q+5ޓ!C0/ L 5" DzEź!\DK+ZAPΑ(]\mE;kqm*kQH vt'9ۯ2$(78޵8ˌ22]GF-sw@4ỷ@l4蚤؎țBg%HՂtB cB%#:]KD @BECvHT1ɏ A$õRMC 0(ܛ2A\2;#zH2{ ]! &|r]CCX !'/A* B o@):s:ok BCTJBsDW9\FZF{\D;LBZX_ڌ9/L)1=. >5M0 5h;AY,PKpkS ]>.p}@I 'l@, %ѳXR T/ A> E<|OF1`Dk3Uͣ8;\UYFb" B" i!峼=jOlVAZi⒑>#g(%I- USt=tGߘ5sA\_OQ T;-'>29%%F% $X d.kŔ 5(YF`X2a/L~ ƌsuv4-)i/' AUV9'Ibs 3;E+7 ͮ- 2)2[S>[f+µ[, tFŠQLa x! FtX2mʍxQ+ /*ٗk\*3 F^O޾[ѡ*l Y^N마?{9<|`U+!\f9efCJ<@D((,HX ꝣm<`*M*8 rxfyG$sF{bg6YÉL,/ = h]t ~`~h[s融= 踜K0.-6~/Y;YAUqfshnc !ц:si9pcD)5K-E?Q=y`8ʌ]in%k1a L֋=V! x$de*YE_eM_<{֔M˴9tLO#VPPm=^!*Z &h)C銎5@U,#^b;ʓ"gcHQ~nٻ)s _gYi')B[C )@`ʛ@(nC^p(a_)^@ \YV.7ӳ b @S38E W^jcv,,s!؛6.p~AJ.R)vty~CCƨVFr੄  }ll. $.O8qޡ:;SmX>kQf«އJ![}g}&UdLv k@hkwr޻ pfWwow)6pH%{yJ.ԻERGIrW[uV71ȼyQؑ%j?p$NE_HLQ?ʒw>T+K_I37ju9C*!z?iB5.U_[L V3[kJA\eYFW$a_Cy1fFG%(e_HyJTO[0\fSMU[@/6ye?wh4CEyr6U.TUM)w^_ _, 40YA') ¯*! B ;C%4P͋`|`XGrAPc`YH${CP3(R̶KK0TȻ.ܪNpyBNSt7N<-f& 6%?O-ydGoJ0= .Ŋ+Sp*}N ZOb\w[3UJ05E;dZVUti8'Ɋ)H&p^WTcv"x-R-uwz^=%w_JG (^(xHcG7n@,4ߺn=^-ŷ>MRߙ8S>g9ߢ d"⼙5{7TjwcՊ{tA_W֎vcK|Wd+՜dlўgc|@[$TStHOzBS cS,>]exU,g )2 ) EʠuP#DTj`pa:?U9<@UY!_hڠ Z6%A <&(P[rjqdƽZUцU#}J}^76~vb1^z2f2K;j^?HINQ@.=}<~AǪ.? HAC( 8ɧL O) 6#TcYTKc=\<0G 8]KPUHe%\>](cZ"8^H+`JWhVdQ\'nM"Yc쮭7P9, r˴8f"ܿ$r#bmG0 OG.mLH (/˭<.Z쮩PPB,#G.9-z8q,N^*5Z<+eo+-;¸NTZ!JN隿cgi)%F&R Jbr/8bM,,r)zLzǧDJ.vn) vdFDn w,), d Hz 6òBУ 0.6Dp⪊Ej26+##^6|*P1, 7QdIF-r nzqb=o$`&YB#)u718L  |8 78iG5Q 2. <Ȓ֜C ƪ*yRA(1`xМIh;)qcjT.c'08s8i%$:APbcQ*B T(1 ,lb@ hJM/Kc2V~R(&8o= 8z3-Ҁi231D'Z zRı$<`: e.>glCBN Ι*w),ITA-M$i =KΞ>w$G.aO_TpfÞ9r&hw0=a* 7Rd>92N15b58  m*Ѷ;4~.)#r+Ui+ht#t~X .S9s48LPoEu,.zɣ$<5G*#Wd@ YuV՚^4)mLҭR$VVm2i#TC:e9q59+EPˢgm[EXhV0 Md%<25X,-MHI;:h -byU1$ҺJ/*R$Lðw'g iMIMg'`vF4{6Cf蒯lw,:òLJSF8n%&anSoN$NAoU.)$ R,誆GrRbRf$^3fsLh6E4.hT=fG/fBmEKs~kS)t"Ӑnӱ^Se8^ѮcFEi<<'5utNv..:l0[>TeCAWtk`cqZ@K}^CCD4;|Bb77{\5uu6"LxÍDfgyiEɝTWDwF OL9$_4anQ$Φ3nJ 0I vv@JyLɲL.GLjk#k`7ji׈nIkJ5iic +h8øԂ8ET[f$sNB /snqD] 'VoHoxL)Xz˂v(pbpSD(.`9,#)(r7`r#ӵ|6wpxn6)E$1ș㞜qv?4ɲ,rMLf2gzaQCU0muZTLo,OOcCu|ӹ7F8=IFDod8Qz8i+ufp5t77$FX\L)b d9}Zx:8{2M)(pa3oV?<(ΐ@,Ɇ1웘RDl6@Gtz $oZaDMEBL;)Ď?'d{&l*ƘɧģzT'ُ-^ٯY}#ЛB~cYPI3ձ"?e瑅oX$;wWQ8QN\[AZGG,1s1bddWN2`-@]U|AT 9YUTw\{$X.\P¦v8M;b~$r޿ݍz-罔UpiOtbXob{-~=siCf8LI ; ,|ĭ@ù pvxXH'Xj'Y}:k=_ZGLoP>d)ʛ{&g?}S.+a7N)$nĭmn^5Zkl%U?PW4sbD]cA0 f71$r'Q' ia[Mrv^?E% IpH1f,TzVV?EjnUתzqjFLq.]r?÷?`3K=|B6v}mhtz#n{A8ofsϱqB/ql\.[ȴbjov&}X0tSXOhkڃvO<˟gk| 4o3q,:0۞"=S#T"C^cqG'#0L  Dr1I'༞ű$RI K0L13DM,3N\OP1{2.T=Dg'HQ m//P >Ӽ:QJN*[0Ak=L=L9Eh;'9b=vQBYhզV@u_(rcMӜ} :ȡvmwyi jj\8W%ZAbҦF6 ǎ,7P|FF6K݂C}cSe,&yS =heco=QC˦e!8 SW.TNV\W.OSAO+qU~k^nIÝߩ|63PS5AO[c/XSsrOlQoŕˎg^;.k+ N`I6,$Y<x?*(<>q z3OR'{5ϷN>0h]SGՠhD~?K~]A}3ָlqE :`{TkEÂ8~fB7j@B R rUșPX[/daEw/WK&Cb0&"vzPC.yئtXK!+x1Na:x38U; |G9e>xau[a9.pe^Q!T%:^xB }l1XZ+l'{[e# 2N!oIȔ'K\rV?+h<^L48I|^f tƘ&L 15n|lr܌8R64׺SN[&" x/Mq yc -%"@|;={tUtLWEQ~ҔRI3@}TƒK umRLyfWa$fd'%B3 a{eb*T!2Y [G A Hb*JO*+W?9)!r0ib U=GڽC1fè3,ٍq6+7f͙^Q#U4-fO,I9U< _( &<މ>K mƎӣ) =^bc |[ Xm{`V*w&C/vX$_o?T^Z,h"܍CۛCgO8dELњH>+ :{\'j j Ln&eh Mm9d$o Iߵ,Y]>촢rJИ"y)<[K &~@&T5! 坳[+t+DC0e7$Ţq2&Aby[0/Lļ1FE+KX\ObfZ#$o$kZbε% /F*]b"v#k$haJz%,-tƶ{L&vĒԆ˟66b2*SΣg/A bCO,K&/xCvMɾiکʗIG8s\E\q;sH2U⍢/Er5TW$;籋hAI>̫;3*hA*]ucPZe't~7}UD)c8tB&h=9 ;zyʵK}hsWjw^$s_RfC],͏m՟d25}p A|)+H<`<f&Aoaw+˻O?vSv9 8Q Al0?.ἥy%BUޤ@ժγ:#ՠ[wx7hZ NdK9`Ϳښ9) -i$¡:"( T+71k&)۲;;C;ACFܲxáSĐQ*x>Ä(FID0DJD`GIG2cLĨā)H@h@b761 @ h$ī)a>(6p+29=WA .ɾ駥H [ zޮp9'h\N$?! Ͻ)+[ϳ  O˕ .0ȪxɍN:(ST:2'kd*"B̭#502}K45A3;9F+Z7FjFyNDi b0.0F̶"&AJP OlzfI+ ?rˆpaXCȋpEzc߽ ޏSxdHs*ZEcIJ4:P R iI[3tGcJ|j|dNIe;Ґ2BKRj(:;2|ML45+4E*K1l1M 9PYsF#e;(Hx˰B\'FZ At3N*M +„@TK69yW@dzXCWEr @+z0Fq8ET 4ў)4qR@ڢyǘܝ@ OϹQk]U5"DH$eme#ČЛ=S:W6e{mB=RME Mۑ7L~9ž9QTSx@ΗH4(:iܟt-RD&YԯBR' $1B/CS売60T1EB =3NT7Q S@u:{ʁLQSD }jې| Cg)a,ay፡ᝤqHe1$S)A1k? 5 ؓhN_RԍO^ BxM݈O{,GĊW;tV@ѓ3嬃`<vsɼ[U\>=,-&@H/8ܦ`bG1NJfGbiiֽ۹V򎉏 4c+VW@ If֦ѸWtslcQv|+gzXbfɺ nvB6.~Uoq)*5:=4SE3ĺ[E[(kO:bJZb\?+qsgH zcv_q36sEQ_FU ՗,dqxD UxncyX3-PVU "}l85.nU`'>6l92q@+|W9g8z7$zFPH˧__?@eAPst?3ai \gKעW)'ܲaS*9MˡuZgVvu(":&ү\uu\'R 7  )zc*} 0ځRxU!ato۳uTH\*}sf?Q#f:g(qdzv5͉̘&aڑCCFO&-&o6߽(UT WHe?07 6B_cD 7LE&vmcM #R]$Yi "f(p?47ʌ9_Je.u?:PWuy?v7?Z_ coOv%?<lYT*$՗A ɥ5g ͚}cO^ ?#|p_>#)y\>(Gv/U?}s;~` P+ o7'i~z !P$@D\9n| P˘ .X/Dc #a2QRǍ`'!dII9'ܸKe/+:)Ib8n1s7::Eg$;=9j:i.&hB s+JRHͬO%E;LI.Օ][V -V[Γ/R _UV)P)'ٕ F Fځpܑ%hMHY uc50rW"XUUvRI8TC%յ1E$i`Y @^Aa,`Tv(3ZÖ?PT*yVY>JƱxĐk.ZcdADAY~BSM 5c+mosĮ$9 V [S+=\Kn@3pZDA7=B|)],% A n*ཤ ?E°4]tIM 'Jפ|DjidsI|oyl΍aywr5EcbW  JCPO z*xNKx׀INeB (<?k1;D9 dX?1_d#W]wCظ^1<>mS:!L1F Ƙ(yKTUdE2Ęacq)&ȨQ#(2lFұ.ER6dW 6>5ZY-AФ3Dh!+G/2&BzZCb,rԙ$qܤ`?ݸ"V+l7nAʺPC~)Ǟ–p_{nD=g*l4CiGNog)WfӱNvIn iP;<$zj#GO\l20rK=IeOCCOdTc||m~2Ǣ8RCRQCY`ddy?Ce..L ";}:21V#EjuN?ɑUU}L$pT5%$z̼WG^p8}ZC"6G#i"U:& EgdQXEcV..Ee*4+6Wi#f=grYKi!dm3wom?(QF 7,k?MѡCW54޴˻FM  oVeO0!D—(2n/Z9VC.ӆoN)ݛ2Z 9+ݖNO'lkԖ iFF=,Rx U%@حkߕ571;feY-eVE!ǭ"D(H ;em(Џ3m٣Q8PIb; MVYDž-Yb߇f<cھ >G$)`:Ksk'Bn,$4u[2:9>9lNtLJS pԢ.Pȶ&JLBu0Girxꎬ` H~bX*8 a0^ ^x̴ 5GC8Sr ) *'@x qzjAꎨ %O0ZF ,Tx=xӅ.H JLhe K6QNp֧bo|ToYOf~kT1Z(nNKebmo,&\ׂcFS@J$RrCC.0g0 @,95!9!ŭ"B9&{I@aGOe&iF2T\[C^dJ')EIr|gҀ*<OAҘ)ҤLD H@BXQQM { l#BbЯ!4j Z.!.. pw% s&zZBhO-20EbNOhNgLL=su6-fSf)շ?rpɋ3?5?O@K馼$uior%×^%``DiuWGOemiD)jȎÖJl- @IdVT) &\d0 {1Dx[gF< Si1N˓JU26GO gJ/ΥL'O|^ݠ7lvJ4૓P櫑#P Q'Q/Q6V(3E֯$O9JTgRj(_ҼVBs(sU"*&b"9Q1u9bsXwOtQtRWuo~vj5"FkL)|ރ[[Cs[=1o>xpS]s ?u %?@JuC`Pi} ``b6eksQf^ֶdTS 9ZdƠrAa0b涄),8A PH^t‚3IKiiOR3RDa#GYBL$džj2^=xG[#O$΅-ҪIvQ8xسoVo3p$pQ^^T 4?5XfGN(bqخov wc:Kfki(k)q*KGxdw8lYM|甩ayW{=[!z?WW W^@o5{v͙vDw~2"8T!~w6eh ofׂA%7Ikrң*gTISxPAZdp%_ JQUr,mE5"@QJTvCIacy8غOiB.Im0k8Wysuy/+2VM"\uژVz2HG*Z3 SV&I#$ fwL~o^g#a..rLh:hkp.~֞rQrQSodZDxS77ec{]s]w[\I|[#@a9yvԝL_2CD"dD5^SvjA?IE%I;&eX%eAmIy᯼:4#S@Ge#3U Xcrk3;B Mu*YHo4V4^p**JON/=Zc٦طn6|CEļHwS|=Ś8xĮy(}Aq48f~;UM2hԴ;8CtH/CD2J//ZbYBAq9|yմ\ι[lq;>]O\;I^̈́!t` D{bDv[ei}$~BbM_ȚehgkbQ\BJZ6,[tݶpa(Ǜ,Iz.t 5PL#E#W/_s# 恟~gwT y<_GKx<?s??W3 6d a6!7z 8 B+ ;CB$GĀ> C0. B4 ő]BQ4RGjB :!*1@IDIg'<$+E3.$͘SA&g7[Nz(?OA- D" aVQI +p6g@pB Pq8Ч3AO]okOu=cWaG:O2,G8F єT^E\>;w3C~!˜ O?l'O[o#$?< V8 NcAuDW% V@ljO@?+s!2[ G]xJ΂SeI!)!Sr֌i3 ¶RR). %Eq1uxV>&j!K;hB(fl?\sr;.5GoH X]!,Y?Li쾘"L V$=(Y$RP P4flYv:e:Z4شMƢcSBc,KKQ6BWbRk-YVTځN* h(Qme9s1 %(>RLo#&ߛq]:'BĠ}\yOK2,Aj<dJ%GhJɎ'dӒ-ʇ+*x5) DOSxTEN Huo@ߓau|?` >ڦ?ďI)}.|"P`?Oeq !9mc_l $Q\OʹSws}q.~RVi` 3gzksjmo^KJ궶+ cv>Vm`< @9/ r{|q%O7頷"?@c@Z+A!A!ac # .Ä C?Q # S [6٭[q1B\%9hVB[ ٶ, '&:Rt11>3q&# qb)(I bX;'[D(@Hx2ܲ2;2kLŎc*LȲL̙@c"ԜTtG2;M2TN$ؑ|SUdSͱä:aV:YIXZE@B(̧YgS4,z+Kihru KMeae={b&SбB1^陷a{NukX :fm6 ،Paߞ둖[`#AP+fɜJ۝[cB-(*\%Ӏ΢l-1ϰRa0٩T RQe Xؿ'SxM,Z[d5K԰C T A"YU-9!yBWhRT2')-E2hT(ԅITTAT˻ϻ.)`)U$M*k uRh  C q&jK0P+:21ݺ}սD4BD>6UèJTDǗڑ]d%ܽ̐M5Q͢MZ•2Ti[1 a1N)$V.sl!6̽H #YĢK)TgSeψ]f bQ6`Sӛ]%gQ[m!rRmxXC sz2ti آ_ءAիz^7.|Xa{M>*\)*^-Lq aO&n^Y9OIg0Pa,db V:S.i>ShK fʘSye+<:e#0UHI<)9IH̥c;5L)Dc<FU*҂ƹ kս:e%lre&H jxde!`#R`ն#mm##Y &bI!`1P))K8a48:@xJL-tAaBy~&v%!N঵?o5#gh99A$E Q-2ye]]`1i SI•]v9[=>a YaqY+˪۩%m\٨&5T@['vT|C\'#EK޲5U܆cܟ+)E B{/B3QD\2N_5"J"QHdީa7PTrnHP3jtgJj#g$iS^6 J M  gfRP3rbOv JK%4Cۊz1Q @C9*7 ,o#orn77C7&ؿp qw_q>w#3R]g۞ UfNB .˓ YF^&ZO &RצPciRK 0(!)W_%xHrLyv kIatj?eJ岓s;gm= E_ C KEG?5wBYkj:_E ?6]_[ {o[x%Oy;&VV0iZfJw K@Hi ᴂf6aKa g u COs{OC>ҪWPa(b8ЖZY;jᶈ3Ho M):C80pQECVH`zh)qQEەYkEw0`qsnz9]YtUze]kuɀ{Q+oHk%ӸHZ91.~I}`RtIä{^N.jy*@h&QѦMS4$<\ ~sNyQ-@|&1ٟ|EcF;[y3p5\#/U]ˌJ.48CY?!"dI9-8Bx~l-ӠڃRAB(QLm!Um(`?X3)+qb"3yX\>mR[գ"]ӓ]kwߛߴĮNV3مbn`nqյYb`;$,j/?6|O1"BRs9uiPߠ!XAGܸ ,A[78 'eLxd`(6c+,T3NcBWo*,Ykp.D)e5ɒwq '͹TW3R(֣fk;ޭK2t7jlK'׼3EYC0-GESSw1;[Ó׷_mμ@`^Vnz%-i>}~q_E.R!)>#Rm =-mZF2a~Q;1P+1*)[jC[ckʨd.X_*0hr*BƮ5C~zx8'C5-`J" ƃĄPJoDHb>0YkhB6#8€(MpvрOLh`m~Fi& Oz牀O\Ȭ@n pc ea&TIEo im(hƋ鲚h2\]6FIӠl(v:#7" 0kƙ&4 μi^= npw.f-j0 Fg"06/'`"3 Lhib(`εZƖNzIN*ИnUlnL N"pDm&Ҋϙ  6lOw>k+)pQoϤq (p_ D.=oȯB-Aiʔs#cuOtJ"A@9:wwz0 jyLٲU%V7Ɗ/ BD*"=)Km 0Sl#rJ:Ə*+/)1c*P2/ KEXm$ ?KmXn)9F43 Ւ&m,rcFr2$.q^GA##3#r<4Hy?$62On+p2[%01BGiF,Jr!T)2KZCJA#5,O1TGLE|xƎKN4owA3R+33v/vҖ! &2&Äq&Ǟ)!283tS{DRA#w$1Dv hvbp+FCVٴq'v{F`hCZw6t:48T:r,hƅz (23Ni|2f(HQʨˏI-!-R?ho>uw)BȒiBBOR?s9fg(ȃrq0kui33\Y'rq#"Cw,-0"rhփ3`7)M (5ZPdeo!;Jyt?̖ffļinL%MPṡxd Bɀʆ>-(s9S#m3"&tkv  A60h? 0%6CfrhyD+djVQeSuD[?7W$2.ֶiElOF'h.:6ygG6ich؇v}Hr A.ƉIzfb]4㉢C38ƌSZA Xy? 0y*W삁뚙\u'$^f+lɶ g`r'W's3"y|0㕺 llǤS%#RF4"98uv"փ1X.Q yT!AEGDITLr3z1i iPz.WHɒ.8QiQDkƶzWXhcF `yP%7|&4eˋ՟^OhI)ЮBcWc$FCGd?eXQDWexX`rW wXyz:V~:yFo#7+_si~ vf,I5iQQng:Λfbz9rNYYM5|[)c=?6JoW+ym ˜WW b|s1rW*zvDO?_W/kA'dPQ.A9Na .NC5F1?E/ AF'DnM3P7"Qc(㌦" K'.:2 2LsR)DHN<-˭JTIЧDr(( 02TU P F49C|BL00K֧jKTU\@MVu{~KXU䔖QSYOhYS M. E[DT:.P |# v=xx׳ 󦁈x#``N #>bN&bN"#5)7dP QFf4j9zf X& 3LׄfXov4+"T,[ N&)6*3>( v*j{+ Ig62"δkrɯ..}(ñ,X-13!Ȳ 7\%ngdž~3Q^_/d'p< lYE!W}[ZVG "ø%Rsh(sPE>Dֈ0u \!mjQ9.;w@2@d@"<"$9y|A k @׷@Y)a,F:E +T+)9DӔQEHyXpdҚjpLhq䒟SꋭKv-zꖥƪ0׊^v%z .El0R"D=c/CKl`q5̋[k?u˻mY#}ww} 9*n?Xj'D|ՔBǝ"85E`?72aY !X2Pj9Os>4m7B2jw)%!| ʱ͡c>Q) I#;2l4"4+b "̠ 7}4nJt!<Ԉ)D5H?0?AH D,a0S躎|CA|+,6:䨄pD!96A tuӰ-<B(XP?#ͅpZS!DIh\K:LlwaPD…MOAq,rsGE1= ;s8J#`Zdױ<7<\kt$< E`<`8;:$2+S+H*F;xLl\\#[ŘF$C< #|6}1<ϰC1Or:KK<ףM24GzJ2ѺFuOm\IE\CĪ+Dϰ1d9#BDc%*2wKfWPFDL<4':*^oED1J\B)Xe硪|D< oNv$uٻ N9㽕 J>WsUM_XCMaNh#mh;g-&-RM6M{13X2ŬE^[m=bn݁+2E˃[[]a3|k$`ZU1[LU@[jvY, 1]!)%ǠHZeAKHH^0̇c&4F5RQ)7ĜcI?~>cԕ )M* Ic{`%AKVjL"h0(kdYj'uSKJl :n9-e.V*|[d׸`mƼI-z훣?BRɋZe؎$d䕴XU /1Sq`}w,s¥vTLr?[YXA[!0^ױX`:f,BD ]: ]M|0C#ø^b$fy޳[ 0g;El7,߸;A4<]e ,F+5u,s^1bN1b$TA8|w~쎑L Zf/ 1f}ZȶQTck"Z::cNA*s1dRҪF`IfmJ"Z5KmyT) 1HhVcԕJL%_\ldϫ3>nȎ3o8R7ssĎbGs[ÿ])RtQ|(6 *ʚkMNv䖯l[bBğ-~eDC]$㋩nmx_\fVkB|xs˾ܐE`,DYp~"BET^sqyOqQS! ; p3D*: jIonj>0Zo#ϼ:ދVh#8Oy?;Db('P*$O~?\Af) ?ӷ"|E_%>DNYl\͐7M 7+O5uj?v7\-O`?7r-^ot$xMNN7Ƣ_謦O+AEX"{?g"1?Һ\*l_m/O~yp_gOW5?7{ vGL {{]~_Cs(8l7{  ,Ç8E`LI ōvۂ1lQqFk`eFp-Ų*Ôk4)䌬ӵ2"LLq1H3 6SOI=nh)?E/ҋ=8/ @6ALI]M+ced)@Γ<ԎX-cmIҳvNjIۇIEKo[Y+/$׍y^${^,eIqhu)L[#'lr5%qbYc@C9I"L0=D뛟y2S_@eN<Zla6'ziӱvͲZ K*ή˹;޸#lcN7l8.gkzaژkYZuR\?Ā0DAgV} o'lws4vSxt/}Cu0__615CIt~O@+4ͳq6}"_E? gkw?ŌŁP 8?4B OFOnj!4#&BQ+aBwO"jB'?L1rAIhm*.p3 ki\?IN&U:EV\X@oCEc{2wl̗5<0f<ؘ]m>'GQwǸ hF^kCsˍg.eX Rmd#Ru~!0C0S%-fLYI%]6HDfb4 B"M%RܛJ%F:<[VZ4ܺS8Y{6"Xif  ygQlΉH$2F㉓dӊq2"g#†*U#|.A=޹t/ ޞjݻNRg~|ixo :(8OA=4 o CoiB*/"pQE}5N#z?YGʼR:H?ŕiCA$C2]Ykx:'\{a|6-v 4JP^Q:,n- .FXC_f']iUJg:՜MFd|Yg["G)<69XJb9ǘX&=яOQE B)eZRJ01sXKzOC(%K֊J\'MABY-L%7^9~̈L͘DSF{DXG ٚєinDP3 ?jq(KGEP9Ss-rRT`,bEqIec]3|MfCKZ<_Iȣe:,x'ZSe̹S#mi?VB)?BU2%|u)T t;}:%TS*9Ci])cr L(+p쨽'V4P [&^7d ,SH!9 1 0Hձm̸ W=BBkJ Ƴ?nӂ#-mZp]Ҡpm;IU+Q/xwaؚ=u]wPbjy$(WS5(؆<ҡsʝƘY LX[&ܓ/1e+y/$3~z ³&e.@)m8MA:ؚp̥Y$>#3fmq2f/5 qK["MDGb~Xӣ 1=zR&6;3iG: ,NêT>_MQ=H5/Dzϣ*gE^AWӤCށ#S])6->{( Ÿx]OH3Mwc.oᗾp[!Qn% , 0Ke%( ҪCvH}Db})a.$&%nkcF@lL&VrFB Fb,gƂ,!$nQ.dɺ"a r0iМllfS n^b^Âi0Į嬛Eꤢ)ffq%j _$&P©A>:*VO'>2X*ljplC,DLOM-|2 DltʐHtp} U%E1O p e2@Qa21+kɚ!"ffk$ A4M#r@K$cʰlLe10[&a5*ЭRo)%C$`Kh<ބ!.:\) I (`Q$in*k(*  Z $ 0f- fgly , f%.&f0J.Xk ''"lꎢj0bn3ejiРɂrj2:(Ms 5u2}*z:O,]7o)7d#t*: Ǩ7ǯoL:QDtӜzM1/voL0) 4 h4be(Nɐ?(}@kh[*lea(+V"@-画H@e.pfؙ3/)Lh|S /"e3F,k0SkTj532tu@'a!2Q32nPaKl&FYlspBu@jGuM6O6ÜxӅ7S|s78Ý9}6seS|s3YLHttZmv ξpHz(hr]QoU3U'[ΐ˜ s`r" j# a3aY#T5E䶴KDN=($Fh4LxΔFifazbaa@EuOK.7xWl{ӝ;1wl7j2T 8\hcOapo@S4BN{Cxr|h( `J *p(RKk?ĆHS$FGm'\K}n5*)Uɝ͟Dpz=Eq+qbabb=ÝLҭ'˧JeIxsR+i{k2 8~Txj[:QjimlXl QPu4((Zz38n)5oWݍP94C*byJɔGr|oZytQpyt!u'Wљ1ӓs|9=w:Y:v;U5[+<_.ϰ^z4 ֶ[A{khᛴP៵y*ˁ}oȺmBȈ$ ``@CXW!'sYC ˦_%3F:v4E٠CLaz %f`TzbO+\[t2')M-ZGkcfvrj/α4"ŊTm8‹MHZ|(Z3RZ5vm/<"t-3$FuC,wɐ|8c89%D;7pD C_?=~*6*o@CudAgܣ$[/L !A<*a0M Eb8)d?RXAK鉓/5glNJSE.E$NU]E=%e=i?wS]W}Tw tJ2/c⌔F 6?Y8>-G}U/]V:P?mp3EqS/OBu^Gsr<_LCv&k޷dĮ3T)7(l[=3 B\0Ž9 CЄ>nBRGE|\@qDTQI;۹;2$s#:Bp"wGy3w9#זO p?Ļu/' dIjpR3SVf37υU4],tR3$Lg7 3 Dbazw"7;S*h{=b[t=3JjW5( )k-e: t9'`L-.{slq8HJQL[ 5:pP)+ T + 'Q+PUä́ru $-#xc L6"Dd(U"y0KXGj]O&$Ӯ*a૪ Puy?{Up lO&FYF 4K {$8EByWWqeq>GzXAуvV>g| fzن9lys.53rԭ6铳1L(zL,qt4)z (Z$ >)*]_mq/Ex?\ꟋM4G2"CD:V]A0jnը5Ia%o3?% yo<'n\θݏb)AѻO'}LKT'RR*Μ7u'^ 8|UU▪eKM8ˑcEjczeeWFZ ԚnF\Ug(̕jW+ܜ g^¢_ Mm54ȭsvpa?"YF?52d?l?G$#rp'3cT{g1f4(5[` In.Ҋk9xO ;g0yj^ F Z.uę!};~4CEEDWJzm-sȭ.R8[' 5k14Dx@: D3W@ Ô3M:@!h!!d|k2R !AFA +K㭺󵘁?|3I=;@;x3i #J#JZMhYzd8D B!:,$PtMEDσ|P; $F2{BS~?4Tk`ͳ% Ra -rq69D1jk]lΌGNUD 1%Q,  Ϭ2"2|"O|*Ohiȹϼ=BMPt4ɁjBRE,V,rp4W t)P "(Apz6} jJ 0W( R+gU?>Bؒ5J+׉4DpE:<#R៣/M0=(L\ge5SdL˼Ru|X8˭Ӝ`M"-;FFTh=MqmXeBTٓDTDF6}(,8 $ @)R%@pU@Wr!b!<Uąl+\d<2t!2 ˮ´֠ҁ4\ܝjp/]7Im*gqx}<mӕ-=:Z:l]4Mt m3REz[X&Yˆ+p7_ O! Y?Ւq(唜eUsTČZ5{L=Z =Z,}AYm%6CD^ ( `y,6K'$&Y 3AuΔ -P5Q1G N1$vUVz ۰9pUO=Tk(\!tbUӱ R\QFϻ; 4.1\x/P5eBùlc>;l&;[M9$QnP66mƼͣXtfdE3%6\%aGTTJmE 1E s vI5RD>MJٕecQEF=:Sfy(D>䵤C`|n .jͪ%uqǜˆ RnmS cg~|v Ā O6 b:.#5–KMhc\0\CZbdk4b˭B.b*Pd#/Y>+;ý48QՖ.+;:* xB-^ $=҉ZYV\_SWޤ'fe? G%?Tڤq$XRY4Z [j ^^^)^^7vjS0kŃ̈́ffoggl k' 'Z),W $ 6aU8N1I]>\^S+h ȋ*(FT!IeǢΕ~+B+4IxB0 ~`egvm$ӴGUe?@;eR=غ(&XY# ZDm2yXOxzSV4_捠w$lSɎ(^+`*,X"(4қ$ N$3{ <~fO9ۇ8Ǘ=yW>ŹAm[t.!,tn_HUȯ <Lր̬%QPaE\: -NE] {-t$<׊d7Ͻ{%7L e3R.q$Rtworn3~v~}Sy"k'l`w|xw,q3p<Ca_(D1 q :n~NgmomhNQ@OȮ,[CdRG]Tn b⿧IdMA_C? E?ǑwV4G_%#$Y<eFcaO;U(M %?Ӵ]5 S*=eUjdCU+(zmvgVzՎdB_-?x|6!qG!?_Sօ|?wsTQk_McQ?w{tM_-%?ќwA}^[y{v^w[ەh}jk'l˴>k ޶AcB$0 C.p]< Ij( !@%H`(@)HU%OSU\QUdUOӔ( G5^8(X>  X@~viu}Y%60G_>J5=Eܲ4םzP`mGkY]~2x<`t`+-R½0 +K !$NdDz$'3 ,?fJgl?G KVQMIBܷm6߸$Ơ81'k ;ۯDkP%Z@O {;cx+C=zֵqQlnLsA/YĨ3&myڛR]Wo<~SF?t.h@E^SOh\ qF}aIH PF&ENԎ*욘Xnlm0H!+ŒDWYdKZ'*TPgѐ:4"~-FhЋÍMQG&dhcG")unCK}-%k#\vNZkDrUŶ9R‡T٘и t4$+xC`\vR_Lp&,w(&Rvy13 yBPɡr ̕mNY8jnt(֨,tJO>HdZ@(M+P^vPAP,GUţKj[%cyle1&C pu6]+lʇQ}Ljb5F^Bln {rFDxdq s[4pq0W\qnQ[ &rX9}ؼsslgoh?Ŗm8>zSjeL֮է r햅J o֡[J}%s6_|H˾\5'ZjM`4Jy^e=/No{ִ@J?UQD9޷ iv}ure^~BŢvc_+Dz= ČB1.2;lKPEFU)5mBu%IǾ?ιeL9O++j`c̰α(ڥLZ hD톺de蚊RĀt0F+hwPPDuxNKxHɪzI`h\yIf2#^Ć&ޢKƼvX%KWpWа~K''F`L)BA [ nۀPF ~W͆[GVu$  *;$0#.@ì(dj#je2OJ3,K2@4CH6dƉ6犴+o"0//ܦ2mjJ>10nL &Fnt,ȃ&@⁈e^*d B$-!dx)nsQM0a Į]0U@}!L֕VY"G\-L$''>~G#R5 %|)"y!je⢀r!'2s dldyR%* lbdnj2QmL>m1LDCč2HgD //2 ! 03$[+.Hd+.hr(ް 2SBjwK4O2"P559O*8GUE|eNulnO } ka J@M1(P[< :SuLm<[KWނSj%$$B)%%)%EvLWm 4#emE a +&"3@bC>@/VDƌRv􀍌&^CL5%*biRS+3EcRޒШfRW.r 30 LAMTf92 /N230N1z1-5FqPGP11{NfE3lϯRRsRpBLЅp<0xSրU*[IP%ij!i-;3WSWVӿ<!T'8"9/xp~n_GJVP0`Ls53mS8ɦWy{IȏIjd/$+꠳!SAe S4ћL3a6ku W6kZU#6QS:lU.d`Ūi oF*"{zUɰ{eyL_%Uz+um:ί`j;y5DuE@%Ԭ 4 e`*|b9Z֎9o˼|dbjBF7X`\cB} Y*%FBW(8wݣ/Jï1ɑ!܁]ni c|ʼmQ?kqO+PV1Hy2f8Y؅3r8v*j`'_Y~beSp=P>e7;9W?@ O>D0# Ft H$R$Gcr\V)fI|9?TWzR:s%Q*hr~}@ X5!?veEq.;xP5?XW+a Ę +d_}+htv ?DVm7^?\WwK\į=?}WGG<_?>#Co ~B?@/  [>d;C=KDS<[dIP7 A0,]Q3<$lQDpsFqK DU"=܎Q\%BФ/'E#*Bp|K0d-Pl0K)s,4IT$C,GH1mFG;GNA:qGi.M'ANQ6ΦAeF۰ ' 0 d'X!\evuu^Wx+JfI6[(eۨmlZHn%BLYruu\St$)}ċJuf}ٷ!u QQᬫ.b'1(2T+ 6V5Pcb'MH>M1e~'hޖ1j,@7>DdF-l4Ul N#KI9=DT!!=O3#I/tA<_@?*5C/tM/7D[%N1<齼;GOOsܤC|+B?o˓ww376C_YQI1@P[Ǵ*Eᷓ?6NStNW߁W9S8R VU@`kclWkI"A%[~ ^$uB5 V$w% Iq^A~C5 KXeh 8?؈[*ِ:JAwe쑘E֊i?X#'Q4`GH)FcsAhq)G[L~*È1 4dQEصcyD(|eޤN{QҢiE 3 p(8RcyH}xqz 7tCzQ bKُ/ܤN9G^R[M2Ƽ' oN9fInR^:S0bԞ~xPOrԢoP0}T&,Wk1-}Y:HӃZAJGHi%'"DqWRꆋ꘯ rƚ,GaT`D۴OPGA?T*q k-EBb'd` xUbJ*t?gƵ=Y('.W1+ UA?EscGDłUBlX,Sg[[jm6|ɛEhgnVQw)ݳ> 8]metKgduIw\9jϸ7"ܙ4ns.ztZ鲔&ûvnN w.⛓aȼq.5Ϲs޹oWSГ \D2Wh[+łcQ;'>+ Ђ^-zMppҢ.L!,$ژ/YLm;x.VWMbx?4]̂?.G%`tcB+lv`j1$ 9Y᳙Gp.p?nw=G6X?ǞEkGfAd Vm͐j#1 gQ ,$|2ڹߝH"Km-AKp/UW '{6e\ݙ5.olNYgߜ;f{ô:\7.ItԌ6QTn Z.֭5 Ve`q1E` AN%ĄÈqp;L282QC D3:[CZTȥ,U+-U %q5d/rz?K{J>"\R,YD|8ShDύj=DKˣ7ٷSLEDTUC#SEџ:*@ q _kc+ FL͖jJq-V[t>!h P+, @txcdʹ@ _ ͥ `F2.,y@ZZy^@s@$;ᡔ:CsB"3>q-$UV5)ֵlI}O Ime1ԗ df5j+"5#cy]Q⁵2N$ X%W]CA5QR{-_/J^ XM,d@y-U!Ļ^VĽĜY)ޥKuX=q'#Ԟ@Qd ιbq\tZfFT^l͕چ_FgpgrgFsg.hmw?)Y΅mkصvA/C7fMPj^`_E^JeM..W$ P>&YZ=6].\_M,@GGl 2*6g&Õwfnvfl~o`sVttwl m&r+t " 24@t\1(@†̈Pn@äz)֐R˱cy)unBk?goE]-Lwm =v{S]q WnEkL"[Ei9^Fj֪p==]pџ ^fA keU6WkmX_kRwe/ ƽR%]l?,w ʣ?*lfv. l&rwlD 'm/+r'-[ g$ѧ0z%HΡc<,!@"YMgDr]+_DgDtP*t9&gOhu'Œ#in-Tti`u}H )H /?[2u㫅o3$/|yXE >_6䆧?/ΩpnLяlńp gqfe]wnm!}6g]qrWz@ ~b!ٙYX|?*%"SR%Cxxr)xҡry?*h, Gvli.|hζ 7| O$:P80ߪk73( LH Vhϳj7.({v#:4X)m;hE4/bB>5&Ldwˏuq6w}W~RqQưԾdH}Ot~(p!$A->l**yu/)χY~.𕏈 ~yGgO0rP;؀ O?зB_ᘤN*?qT0CO#CaYcU/Of?Г}7hO}ۤ?26_ڣWkUr#gO?W7O_+O&?|B_㌣3Ow9HhmGGG_c];7#l٢wK+]#5zb5q:{Bӿ]7O}k餺 My3b7[v70{j۶D'  5C  đ4QQlSőW?ð/ B0T@+?K%d%I4Tu,7Pl-1sIQ͇I7,䘦`T:O0 t) Q='GԀI z Q C% T AJ U5URS @ b6 U5FRmy_U3]W5(Ema*Yeav#[ ڠUBsl,@Lñ7_H1%[X_A:*ma>$8K <9 =d㓟T .>>uxgKᮅ{,rB@}j/$= Jk+zʐL?o嵽Nkùn;kO۶=4 L>rr4ce, uͶ;Fqtc1EWA\--0+H{4ݵ[9=Jܼ ua.+L9%n,JHY6m֌h}Gg҉_ՕX?s@~ERURVjydB*jUlPϨ%Ua(E@LgXF]r.`JsIaIe( Ȍo坊YRtOtY$ #~?¤i %@?q1Vx 4h|쁃H 2fZn2q1#kMGw:$Fdӓ27Vܩoši8x; ļ-zQ@.I7\BO%:>9Gȭ!PtEK1%KYCG &W/AՒr@ -1yĵ5 O)Ed]JTpOi1R+`]옢W\끅0X tQz!]3},=?NJ3*e:l= Leą"Yڴ39 -aUJ٫'֯zGňFIomWJw6xhk}o旳e٥wcytzLy7Tһ;gzNuΗWBo_nH:wֳ%[)Rq.-Xk +qbbby&hا5݌cª—Tsh"\V+C$uXrn.OajRb6W:}Z@-H{X@Ww!+잓G0MFҡ4y]![_c?U ;(i@:ZMSUjegBA6P{.)nz}vEaYl&ێII(׶m#ron=迿nsNلܤIGt poؽ sKr6᭰PK4md x< `,Y* %U%]JL,Ϯb,R&2b]H\PpZ]HrU.(hR& ,< zJRJ6]ʢ"XXbdw!ho`(@Xhm:$  PO:31/ [(TbphIsȔlm@i T\͆x͸k~:Dfn5T P8K6GonOMAɱM+pq܉Иt6,B>בvRJEOň$}4bĂGHSRPgİt|o+ NU$2pRi htΐ%x#(n: ,Ґ)a re*+Xnn VQ0 !~,l+w m4Ӌs "*ī`/`m/02)2 i/l Ŵ] 1"N1\+"a4'dimdMymZMK;7stMK\ :˂QC!DloC쾮;g;<1<-k߱1'鮝 .cTrm< y-.⊡f-+B Ŏb8XĮ\$h%2V FТ9&"8EtKEW$T`'΀Nu/AG, G,T0@0#ܤNxÛYhI4\JaԬ`,LQiK.ԏ2RК R% 񀆠( 2T/?2R K,j4a3L53R RlU1"#]51]"S7T1so _7ȎUWU𳭆8:99IBةJk'8ӥX/Ҝ:  ՛<oPA<&?fHFFdB!K3"is3f3p<3X yq=qȧٳmW0&@m͌n~oXm[\;3\u՗Ye5uνuuwyW}ux\a3K[]<:Q:>;mvwcZwZu''x7O+[ \5wkvGycaߏKBLL8rqr*യx.ĸ:]Źs|w~lW}̥`F| `}~Z^#(FR& v&@V,щ/,챃Jt$W+~ dv@A{qkl/36TnXx.|H\Ǚ S/VOd8 e&V *" F Zؠ*± U.ES .p6Mo͈I@k# Z{z8wGx uy9v=skݓ7Z-%uӑyF7tI5YO4UU_7ь2׈,Eb]}`cDV+y~"A$αaS}AEߗ9'qbvEL2nHԋiYǵ;dX.WvR ` Q)"N2N A|^ GWaB`ðHq8jvpRGM@ODGi,,;K:GZU{R3O"epfwpۦ 7"K5Toeu)1W!5w/sM:7IM7C:G:w,AZǓ9X;uZw|OwY+=?t.#z/KKAGć lOe[^Ż{!HET|EH!aͤO᛭%!//Y㯻OE"A.k JWU,!}Bƍe ,LZxW>I\K|k=9)=|c]Ź5y߼gwYv{!3KArlL j_ҨJU4e \#<pi~T9~`2Z$|>Scn_Hp[` ^Q8^G!ΰ~ Ak=r y{;ÁOQ\ELJhhmYv!~$;eŠ mUxQSdnA 4J yjnR3S`0`՞=TSbN dQ]'znם=]´kc‹iVՅ z\k]޿~>~U>_7M?=SoSy<%+IP@IA>DanpMB'1B!J4P'%7jƤo!H2Gt$IDlɤl'*EgE˲12LdL$L5MtDNgDN?ԃRFb|Qn`Pzk͈b6IqCv )4?|3ƀӆW$b{@An 0p֋?9>s@2\0)gLٞf3VcE)dQ+ Sچ4^-'S=mU;Mx|S^x @Oxs~ލ @N dHM v"Т֋k~+ ,7aGT&$`a']4A("i;T sOAVJ U,B8MTj}I~Bj]1jj5xćoqTG5"VݭH)^b3Fj-RX`#tm` +@+i07#Y- 6 ?`C ##\ gIΑiˀ?Âzn-WJ^ i-097bt e`@vVCL> gnԊ,(BVXI?Í'$jQ9CU glN8}¬\ ]KBTN<<loR}*1.lPV!zH'DBK5 vD|yCH$JTaJ?ڗTEFUT4,?=x+T3B6;k^;S&H7[].H<X${ؿѱ am螡 ObL8?гDñC4kV5@AQJ[ԻɍN_T4@u(,628#BsڕTʇܯuK]?)Z0KUưLGI@EAQ3[瑱٨\E>ĿJb4dĭZ+/W&pb/ݥoV52L]>3]F4^7cϫW!]#(P^0]d+u~dK7ެdVD*s7X 3@5. MIWH՟JnG Jzs LHY-IZ\'IF>_a RN+4Ȭ(?5.h IFJىFS<[d(&JYZYT=f@Fp%-@$֫cY''oM(ՋIV  hhc&]676hW]<>:%v~EPC^S0~WFiF鞟iʩIP۶LNQD2;[! ֹ ӵoT ԕIQYQ^RESL SH#LF)[e&+sT}$Th4Cɉ[Xu}7N)GR@6,*^G,rSoXB4U4M\F3ݜލhmammm.~Nh~:9OtO=U*/vnGIo:̓ƆPJM;2XK品M`j\Hvs觨QQ9QQݏbkp22/ѻL O 7,NƤ-Ž+_"PLvg[~[~fQL2mJG \a)"gFx bcdA5pns1n2nV.cW.c_6s^c/]%?W_r?vwRȶ:D]_r?{Na_\E?RAPt)R_EM>Qϥ]~ͥ3Yͮm;j4%Lr\g=N[t;ܮ>Gp1;c,DGA}G{F F<Dd d%p) p p9DE1qf?ŵObT $\*5 a<k9lq#b v0YH* v(ТbQL[%N6,E`< ?-UάV{1^v@dNq{<5ƪE5vx4y͞;י#^빞!#_;kDgּWRYEDzL'L?QhRJU+T6Y{b-d_$įnaΩM+4f5Л\I5vFl)h`H<ح.}v:ƪ'{sXOa+oc}X,}" 4%=C~N4"Q^ȄB `’j@^ T?jNa9ؼpWb}yV9g,VJjvZT[$rj4ܥe8Ŗ卮6؛E̹D ,~mI)e>2nh-$v[[V(B pLߤ=S:\t63F&IfE!`i7!cV[wޕSWVVV^ڬXl|/m?(L'k/hM aF,y1*%MCἡ ~Sji6$Xؕʴأʆvح9kNbd* +WJ;W33>d13q]qʶҋ>l)eZ DM=GAi\tצ}/&zzܴΛBќ3]u]NJOX]x\*}u=5_O{ڨ7W?oP4?yC@0hh6DX-J)~қm?Oy7}7PTb>W0sy=أu}B-.7'f{yZKMY{%wƳDim,h^J &Όo+>p.N:-=6CNCtd θ@dv>Ncg#rg|Pk'+/zNrPkU I xG!o O<@o.OE ̀(mڦtBH.]_* ޭopR( o6*0cfcfjbrȅ%0ˬ&nDOˏVjVk/:p y(qRyl7&30#&KD J,NkeMq u K{ pcҙlv$+FN˩x*RhG Ч n UjPһ'RCc/V X >V YhV!2X0  q$` Y6|vJl()P5-ZQ.POxЮ,bf\ ܏cA.c)cR+q6,) .}n?0*q1I1g C1&pN-%]anmBnχn(q1Py eK P/'*Ƚ xdu9P>u'ͻ 6xL;HJDJx@*lŐ! Rqmn P˭+(fs0,*+K+Rޑq,,tL&62-32..C.E/$s'0E1.G1ƶ!GS)2NqM!34LsB3DH L(GpFPr"Q6.7-kL2Lc7r@PG@DKG/Lr 9:$Hڨ, ,, P ,3 9~Pwfx~XU犙t'U.Ӝxom;Zegzl-r|<*Ka :.G@!wGU~km#mCYEY=S]:Xhdny[L姌]Ecan_6<4i#!Y{QoGp7{ّyyv37_YYCEV5VڋZ拙txvtZǜ,[|MӶ!Pጪ6ڲq$P` Ffrff8DG@ֳu6۶rXKwcmi{yo,ZZZ{ۗU{G::\Z3HWyì _ubגkj׮_b`s[! s`/me+9RŐM۱(Ew'$=Fj9L*/0yX!x{}{quy:{n;o;{[ {7ADVcY6OL}> zY<^׋h۴rE=Nd WrYto:rw[V6mgAF݇|}םƑ=^<|NdD _@ ) &><ʔJ|u< зWy"8FÅ%,{׾cX#_wS^C!ߒ?>ѣX3w.B_Hksuퟻcigm\Ֆw"O?X$  P4=Dbi,#\}?RWQ %c?sW6p'YA-?ԴҠ]TUJHduMal/i[ %yiIZM.`R[E1S?Md4E3c9^+t 6OiuU/6[]ոwz¥Xn %/|bNmE׺$;w'ϯw]}^@l @T@>/[3 Dl9FD$MECtCq[FmCvGdyԅ FSD\d\&I҄)JRDr?/;hг!1X׸-k0̌(D)9HJ6Ʋ ?PGQF$1kH&c'N>UgԴ:gU'VE^`V.]*t%^X5ڞZPO/,.6CR2̫)o[+77Lt57K]uwUv53]5^ظ=K`0 O,(ȶ Z/ a;Ps@0\Zm/B $aT属_f6]湜c9gy Hfe$hFJч;2۩9# 0[-sku5V(< [*=QEaD{Eݶ{iI>\5n^u1MS&?!ɘa 3('P 4y l Gŋjg5׮sj4˼FcdO-ۣwnѾX!M;'t\E1UtL\x?辋z/z SWj)EHI]TOv x~O+1oPl'ElSiDbȢ4kyH/ azоLɉ-&{igĶ!cg(;k~P&Y4x]@H%#|RUH5D ReAi3;alV,Lh3AMvwjc ޓII;ddlIԈC ڋ,>}78?[HQ& GXзLbtQmЩg/0 ) j5Pb]}%DH|ylq&s$)85$e狹Y<$=&DԹSjEL:<5'jW]>8%SUk;cX%2ִ)/tx/Kw_25|nX:4-cSVbM745eNG9蓲&ٹ fIGYnLm(+h= ;x WԈamp=ĸVYCp2D|2yATJfboO$/5ڽ 9;ԋw_wjS7_;( 9v֚p6/ডqЮƛ3 TJbs?3rX,C%66K1ua6`fH'/|&BդM϶m%d-e["P+)5Ўdۚnn* Ts` t۝-,9^ٮC"޻yr @;5@ <4u/H}Rz ] ]56X 兵n9ZO׉b,6(ĚMR.1l<[635t<5ЭʓOf|dF*GKv=5B;^ӝ'DqEy''|h%oRrcMli)sYζdr>mд>:L,:\ka}al^%jVe:3^;ѵ,w*ϝ;Jڀdl7>yoC7yo|mn}7D̟=Ax_Ngϼw{i49ID,鮍 辣5z0һZc[4:8Ã?S ?>羳$+hk3Է 8,DLRֻꂸ 073ɷSxDM@PĪij3@)+~{͔̉l-kD\As2c7];=p4$a3,$Be4$&B\'F&ƤhƣIB+-K S*3?s 5?v GÔtǛ :[~D2-"lCX'aܻۭ;܈ɴɣj,;5#,K1 @IM4IR5IIŁɬʜZI#ϭ4䠸SԽ\J;\Jl$NʄJCT4NdK/Dy/0'$r5?4KlCt|9ܾã1eC}4L4sQkB6C;ԅr%̺ר*@\3S~IDTӼI 4JI4U7kM׳T M  M(II%U!ΌRe%tAB5&҄S$R3L8lB+*>T45O{KKS+UL=)dzЃ("d)M ;LڄIEPQMMQ|OU=RRUD QQM(Ksͭ-$DZ,4R`R }fR*Vuhl@ -ִ_ֽ-R-#CVSC"E(9CUORTK,7Cd,-S?̩FHC K7UT,2ݍcQ5}̓˝}XՎՍUYeSY%7E@eɤX̤UaE.VM+VfօUTV# ZaMmZ`=]%W 4UrS1s@TQWW:G}|͸׽}-~/TD.TIKl2t#-T͌(MM٭Y=NYCb8\\tTTY}YmTY-ե[ѭ”ݞDU-$]Z-RE0VZ=ZMguตLulZڭecq•:N7C-wӅͶ6۝:ϢW۬W5KCo?=R ̊ȝĉٝ\՞Z\] Tَ`3tXܳv]]& -`n ]c}XI ڴ_Z^5n^$^5Va]eM4[h C ,|=>yS5v*[kM?5@A߁u/AH%Тŋ`F`cEEVduQ B͵׷.-mUVea&S,R_V-c pĪ>K5bS bd2bw[S[f)%zefbtvbN_ [;kl ^+XYrԡcȭf;U= vd^ynBc F], `-3f%hn!e6Thf֣W^mbePJ5/T^BWC^1q^8ebbfYI[zûۺ@/|( H3? dGԜc E`U>CgA@gu\D`vrRQ 0cQ+UKRhY妊e.֎NhAoF9Li4oҭ]uz.lc_MfN+fʿchfl\BhjNA΍o>lf lub*MsiF$  S{59m&ӑ*ba 1A$ Cb:)崯ƛiC\&7>:XnJn5qf`OgDOT A Sq֖>#N]/8Rέ)rr+,F6NWfe#lKppSs p?p?ngþh픁JmPTcY_ЧjgnGnlL.6>rg~snQUr,r=X X_a4[7(7)O-tciOcO/o!s/`kb#0 TOf(?[q21/=_9)vwxB|?4B>B4kq&TJM3]\WQ?`^3WTggS/Tu?UWVqOYgXRfG$K]M]3oL5v4(j/yj<80H=2Z̡dav.mS]vWri9wZAfd1 wwp*&t Ngw0|Fl7cacu럽؍'N7䱍>_-t^l>_{紶Zx^& iھ>&l0&}pV6D!JLZ=A͙AVYٌaJg&<'58% jHY$+v@LLܖmؓm6MDًv7m:"|*7\)Qwj]ETqZ6(.\psqG>Ջvhzv$?HRc"Mz_x+E\y {5OݔO~Q J4Ux7־C6fL1%SI:$%a )%ukQH 7SpN)84L(K ! 4I ZLC̮uC 6ѻVzϙbJ l-x\șFLk_j_.ݭ4`RL#)b9o4EGW5MuQGU"#?4;e_NId9PF:R$xe#HE 5nN/h$ߔWJYf蚕,▦. dD~2ޖlSFcSD4ֱ4^idݒh!?nsYgDv3'G‹] }n١Hbh PqoWTn?bZ[N%p] E7SQWU;7w\QrS*R#T9] t_T6/ZO 9?E.m]7W=a+q5VA5)=sRY@롄5bKt,v9-10sAU3Ǘ2&AQdD6g*Aeg-S μ VVkmH-hٵC֮e|.0\/X^k/ZmM5[ZI%LXǫڵĺ񍷄ɹc ̋&]n2V0Ϭ,yk-]I92+w8?pO7Ių9NaC?sQy@ J1k;5 Z_!S1iZbM7^]-,KEvoXI75~R`ckz"e&?R̴u/Y,|cmXMѸ4e?s?_+f9G gKQs<<{"Im7Նk۴MYB ! 9zC<Q:CA~c +m¬2n-YХY9*:G8G~Sf<k0AAmFO0CJRW@wNnMP|/M,."ĪjM8/"O(iJz$rdP|3Һ ^,g~YdonZ/zp̚n̎TΤ` 0HVe pOkU N Ĥ=fd@FH/6J/CLGklt`! bn^<$x/J4.J*Ȋ7p2-*>*5"Z#cNM'dL#O?h(ba1(”%bPmxQ0t Qv2"x t%:P,cZ3窚"^ĬVcOKp+(ܯ@Lڶx@D^JFOF2EOn-+Y˶n풒Mc^ Мd[$fflhNė,,$,A.(B1Fˎ ."kDB.S,)K(jƾ=iPlA' $^Gm-0ndA1q83sE!3LtFce /8Nh9*m*3t.mM#Ž56Np!n% as::EqaE6K0pײ$XԍkHϒW&\JN)A MЋl2ڂ|>L\2F6Ina51yю!t3QI4τ2Cq-`ݣZ% D܎Sp<+ -6SCd"@,gESEfpӵ<-g:sMŒUUp{VwPzRQ%SJS~Z@-6GD.ZcTcqZzAM #$L$(RDINM gڜեJd p;I2SYP)S(ҡYL%B MO4=sDu-JlIa^ `_sopt-2.0.0/images/cameraFS_TV.tiff000066400000000000000000003017221277570055300167270ustar00rootroot00000000000000II*LO?з PD_ȣ #QF<;Hd#ԕ=2\:L_ 7O\?47*Rdڤj`?p3_O5%Y!c'onO!?v`_L%KŠqOv5Vc%Lf ٷw<+_#uO^Ymv(\O`i_ -Σ{OOuQ?^?Rr\ϰ}?¿a%@D I`$l4Bl9 tC&Ec]t#GmFJ%ȐČs +F|!J,K,KR̶4MS)2548Nh" 8=>@Pt&B~Y6R*3M=N()=g+UA;}b7Vh7WUw[O5A5Xl00zB;Qi6%m  U\EsԎUXK03ɴ9{7eUd݃#Wnv".Bv$)I~_qdY (Qmdy.Sc2g0K pNIwCY:Yx'i^kZn8Z7Ϊx(dNCQ3$2QB:z(L./(?/^{"gD ⹃i%'_hbТ{ (@U\ED<'D " AAj8y4IT7@\{Ԅ-ǽ0ϛE9=z,o.?axHyYԭCiڽjFHHIDp6 HQ-MT<ᕅUƒ—/$dRYC9f-{I0-DV2^Kx٭FZ[^4љ ,JS79.U n|P#wl;J)Go2-Zm%5F{caBY<$cRX1)_:Z߉z[skY=YdLDCZeSzXb ärdXkVRLPӌ\a'm n<7ŗB0mM)N^ ύƯ#e!3NkCy=|\>j=^Y)ۡFbkYt͎Mo1ihI螋J*b&\fi&0cflM*MM04l hl& IC!0X擅h_ RamT 4eKN<.ɣ"1 5@ !h|t/=tBK$ 2 M8s1A1Ĥ+z(K䐺ѧ<-XE؏=Ű|͢KL#DC"q詔Lj|x, f&ZlMpS.nM谎Di&HB$l%6i,|N&N2\nL)'j{ƴ|FU<rjr @D\=*b<2U-,.5"L)&jr e$T[X.ZHn$ ή&i.N% 4ł n~~2XkMpx'9sFM J2:DJ (GXsl+1.'ql.(x,o|}89Gsͱ^v1(DDO+ HJ|;Hw<?=o>$M{/ I Cg{1ةM)@dHtAc1 4KBy Hj 0 谴.^S.F̎0Pdkʼrl*P*4nǏPW( nYrXOrԘI]eT'1JTijK>%K*H*M`n#pr$iv_nzP.N"dRbNCI (X<%F&U %6'ODV4`&+ʺ5/i(g*4y4N1 XiV*O$SqLȀdڪ*8#K8CKVZկVW[o7W&&D1ZD@ **5*_aܼ촨h ?{Ŀ@r4@1*j(^͙A[;-QyAdBD+H:(R*RO>i® j_i'G)~jʼnH_~J VZI̝Bj*t%PȈj{J!}l.]tK;mJ1mtlntaB7L j2MtU(I<T*RcI~n-CbP꠪ *mI( hLPLd cU+H$N,Ʒuxj\NWnV|r>*x}4b$7!y5WW5o|e1\Rxs Wդ5{u :u}ةc=\ӴQ;jdQn!X᷁KtB&+)'c„tGA:XH҄c$>v<+BjQoȳeu g^gL856`Fnl*F".F0&N40!7eS]iTRyF%h tԝJ m2 mX)m ^-Q4ov0rMt nWKA4$"!ALnri&WzSEi(Oi%LD&.X&DjR%ri/ul @(ehfOV~5lL1)[7V4WSW5DY5~&.TS98hL*lxYZř=|y3O 3"w XV@3 ]Dd!g6L^(᭡xZ('̅D( F @$Hm(҄d-K7#\*8^4HqfVbMJXKȊJNYBPtHNEHWW[2"njIjkPТWwF]z"R)~洧Ꮾ'~a=a?pt8x,V*r8{bp|@L *kXH6R- ؞im.Fm嗦ȹvr'RGu%i)~DdPThQeHh%Ne)𩳗&45o<בyH UvMPiݗcOQ ᝕4|[L^5w|+bId]d_>&\ ^G̑: aY@-(؃/&jt1}|.ZL;6ɆII]6Ez.*M+b -$XH2} BX mQ>$V)!b!!, jej$2^nijnfoxf-p:=yIϡvoprU ;&IMp~( nO, ^0eЬXMjzS [2lEWdt% nXR;7Rn浖U|P܆OƩ g/=94;y88Ɍµ±9{yM!̲ʑ(Q!^"w:#ń Z[c̽@(C|qT a^-ƍ"sʕG&'̽}~L;g=2/٥жfd+(96E=E% XEkE %T}eU_bH!PZeMT3q%_/w!^PcѢ1 4׏箸3lorot 0 (Pc .NF4nnWhө]9.צg.0,%yO)7E%q{HT(k((i&旈SBDnOgS[Wuwyx.UÁKy$U}yZܨģx'1هoҝ3Ũ\2$ઇDZ XATCHm??ȲBEɤ4H?#h )}=OTtBѥdgB*MS?eJR-W_-?v!eX?uLe? `M<.3c朓Օe9ΛE:SkgM.0swo?//8sΔ.2:%nB9"^/i^yjyŽRxBy'h/N' 8c":*b,Kf [:, ;伱4BP,3225:=EdPQt@gMO19L3?!JǜNd An1 ]rwEm /ex>u5;ܱ y\]B?@td1 r\EP|oV϶&ҩ `> i-?7}OJil(Hߛp((.Mj(pQi"*jlԚ? Vr^|p?6WX4kUK,/r5 -±0?t[_+fPX_Qx.tIѵrOGGvKH[`=8WBy !d<-0V0?FO2`̅R%ScR",GK$&fU cDɁ*eYE.azbVk,tˊ21n7?۠alR1^ofm-j S&!<6P:[>2p;GbҚsnv:8y9W.'{*Yͱɣz-"T"JG)E*,B\i|o!=!?Bzo!\wp 8w*3]FӅi}/@cCS 5p(ҋgnȨSi--?܄fO3S2Rz Vqb,`gdGcWDl fH?2'5hR|5je2Au2j#R2/cr_ 6т1PAю2 ? Ka *e̶ڤbM՟E?qW<^/G½|e!)eb"[UruIQo+"Vњ%vE##cn[JVӠPnv]0J 5ӌNQ#?Nv !Ah)Ԯ:Cu=Z?+bNٖGYNe$i2 dj[Q 38GTu8<ǖs>{YTd;Pt-Ή >dͳSd:hPisY։#4iJySIEn>u SP*5b -m.0/8u>Qӎpe2ZK_[,mc>]߫ w[]7b_'r`]3|MFX p8r4Q- $S-L㼒_+viK@اXnMrp,! Bl%wp*1FU-1:Qvm\-f[2t%9s qVITfhƸā RtU8㬬6'_S;Vh$4VwtcG/ce&R}2-ܔM(X-"3B?yvsv-r8#9|kSp81?[  k2:jn/9tDC?IJ|g 8/9Ksa0#AhKB$9`zZ2h ɰ B13p'Zu&'s';a(x+0ܒ> 5x hժFr>qzEwĨ4L)0JO*zE9tU[>(85\?-"[X2X2_it,saR2%D#9t_~|@UPU~%2X  n_8>@о7FNɿ#z"Ab_bH&$bQ[b[R BK<(8\Hr`]6 HɂBۉLB;}4[iC1pÚ\0TDlVOy!|ZDԄJ)7XA2a! vNS"E4[C=)Uר5,Tœ,uzT?ᾠܻmtPe'Hɒ1 j9].aΙgwl1ɝCSH '[ sX{>qP'a`;|#;jh)U61cXtF~9)[sPHbz6Ӷ3 6ma91+Ά.A2Z  )6dfjXnjVjpfF"i./jZ N Ik(k0%D([0<Y8y0*tSY e㐱X&0fRꡨ- H(X1隄PlʇMď.MFxmXNm>Գe* Sߵᎆ\W=\<2GFƔne>cQ7D3i2j^ i']iR= Cy%^laiYHВ8@8n Tbǜ?{s`XunV- |,stpi|76)a_!XPВƌh&6fIjq| h[Ȼ86&iۛȭ܇k~rkF%j%q2J^Jg3ik /?6kIBTK Z39IZz_:>-fi۽(@rWMCl~҅(l u7Uyn#d"jr'W)3C!**Cۺ8JݼtafF)ڌ%GqoQPl!fRnwj f#n۰v>0WuX@:XQY֒i<~g#?Ə&P&'F- Sg1OI2crdc&&bo&:E>SJKܣ%U0_zB9L$~32W3Xؗ7Wp79s s>n+k_ca0„(9J?ܱ7pP_)''v;@)M+J+-ZGQ( fJѸǣTXe)ǐS;T1W^ q97K,9%FaoѨo %=@nC:N'[0q]lf1ixl3GaOd!io?'ͱmy5x .7j9i,)?w aTE/?Ʊw:43G_Yr<+?rwU) LA\"K7AЄJţ:[kb/Yk)y_Y˯Z\{{_0%?g$Vreve?9ODipXL'O#1nDlu\ qxc7EGap޶SH}/%y|h9Pz~%x|O?׷0+z/ 8B °lA :7C J;`QDFѬovϒ,A9@IG&ɒr0-ki%*ܰreKc0s9CG 6͓t@9ΣN:O@ @PQleOcDC3T @ӃDP4Ҩ8L!BYJ"dF乺KFy$–W(Af*XqZiL'Fy&cY)m1nDfav մ (\ <[1  \.VW0MsՅdgp5};?gط+nGv9}vNpt&yGb&'&yz<7>{ce *}Vɼ$8\-U[1K UK䆑R Q+Q"``= #! ONIf4- 08T?<-J_ ALɡ3<Ġ]뵍$zOD.@!b+EVXD[NvB «LUnh7r֎Յ GoKȇ]kS$ȕl^( L _rLA1ID 7cLbUDDsv q\c_(qP?@,g-3{.`fc BzOViL͖69F[E|m tv ZE,CCsnF)G>؟r'@ P a4Ϟ|v(鯀N?Ɋ#'QL+xMr[c̃;s0ڒWDxO혺Md4wB! f|Nk)l.*@rF 0% p R° *<ΰkkri-&n|t{ tI&?c02R6WX4]2k v\j\*\Lv:̇l\usb:f|ϊu8D-%{ LT)$%(>ώ DzF\c/&\Nbۅ;/PQ=]>E2VׯIqIHϸQ #Kˏ!\2\%$4##46^QS=`^06*@(9Lމ/fёnV蒫ED].{ kH0rkԆiY)I"0Pɉ+fkfIKRK0ԳK B^k 7mI0F{ nq1SL\;]OjJD$T8U4Jw]*=T 1 $*k60,< ?RJ$jJwC89u>D70iSi <|U{4junzoP8d뀝-X/kD XM϶RIh@t~f:(q,9pI &veuo2{#wE/FN[žp=]]T4>]2q]'c0mHjPf.jlWYpHYyH~v@EUvV]' U ȶcUyOD/\Y[bBЍ ~'$8:CʰR^N{)u,X U갫mR^\(O>UK&ʬ&BVX,Vm~R.D /6+B(xɮjGb)o0 *ôzDÌ=&k k kXj.8>,; $hJ?JQcj?uQ ސXtsd{q79'ұRBJgTe.,H*2|V,LtJ?.0,/f/J}fYdao]&_/'az@D ) 1w{Z$n;vMm.+D).\"HGD{ w3,&e 4ċu"av0g??^'?/=J?}W;&]5I?[IzT_+~0'@D0tG t6=1D@DJ@VrgF9-F=~!1@'&G(G*\U2:L'23Kdcd/ l9G< C}t5 C0QHQt0#t5S;LPHAԳOFU U5]_JfjB.xbA%EQ> 2i6]ݷgpXfOT JYVf1]7mw[zM3E7;9`3lhr `r( 7W>>d!!^UepAb 1j8^e L I"F Ζx,zy꺦+&/zmkĠ +;o;Ʋ\Sw5mky2|nAf)n>7l7̳l幢~"x# .ﺎ?n{ l> [G5]hBMBCt<;0(x3gnTPE!*4zQ ;/ J*ytB4sMzL+ioεV:A+x-ȭO բ\jlblLBMV\[*>kon01C5VtCnW^ 8XڷUZFľҖSP6+ eƂXKrE`4hDjFR'"YedABe"P0D $X42@.&[(N>j {6IV&qZl:05d֚X8`[w¢TCNBav.M2 P,G!?g5fVJ8GŎܓ9 ;^wIw9=Gy/eR(_s㥰:Nf*v",C+HfbYO/A*Aƙj_>jzC և*&(k}j)4,4GVB(E5XP,oU \M2߬h 7!"焩>sKR(YxGũ]:ېཤ L!ҫ%*\rlV[utb0@d^]Bn읕wL9^Gi6j>_5u- 6UE\h)=zq)gL>B; `)Ti)2p3|;[2^1sFi-6;B씞h{YVBD-˅ls<૮_˜C7S Җł v ˹vrS0f;GuG82Ü ܗG1NKs|8w+"dmgHPvonwW˱rzm;X',8ܩElnO!7NwK z?hM ؆)ڸ¥Zr҈'=ҵͩx`vP*qAX4Wm[Z}^L4<=8v8rԦg ͈|{i*峳m 5(cr?Z}o twww,BFB= ?w);K wp  @$ *3ȩ&h nX**c{9cH2 d.pқ:R*A:c0%(s2Y*$ʪ;l+"┲؊k".31G/ :@@R ڶJ—R"辙p64!;>=?q6+ > @]K9k;8YAn@Q!J1i6XAœ+,&Q)lkT s`Q=^D$YùM4[Ejr(Dqo>;5ڵ=1 RT7p8rRSY?з?G 3{? w Ǵ^%YHl(**qda;&Dzi ,0 s 1ûۢZ11 c'Ir9,&.(l ;4,dZ0 k0(ixD.1Lq)X6}2[C$9j#,`\3KH!dDLQKRQx"Ieڔ:ؐ))ZEZ̬\ūF!E]y$b+[}B4#@ƂGRƸFNDstA%C%YGk~ :ZQNzǫ@0@T}G!O6ye+bH'Br@[Br8붖l 2즴';qݧ˚ہӬе (ï˯+LII,Y5.$0|He G S`JҔD;ԫ66בb?Fa[j*ވ vJT7߈5Q8+NNy ::yal@PBJ5&+c@ҡ!a}Ϥ0a8@#rϱ'-;p3 3 Χ՝YQẸu |'} 1 ::ܲaܩL.Q`AP˫A5ܠ<0)85CR`/cYS7E?>DD)gRS:14Ei=iKi>͢Z3hFpOsU2!W#(#MS3Y}#?Z-Z<\9xL| lN-2k{IYŮųY]*L!x]*kb=>ZK  R :|rC1띧讍QUDs9\c%|ΊQ\2FM_NBեD쥩fGd|6-iR+bepVNGa(XPVV9)&&ia* ˩aI"s_ ܺ.Lf6ldm(2TxGYgy$RC;5C]"bKcoa."6~$hN&#ϏN~( ¸!q\=ޏKL@#*2ÉJGj>b=;Κ[ IOT5 B31.պ{(eȤA7jzꡛʀ8ܶ77 ddckm`@1~@ 50;6ytdVVj@oNiOo|5:i¼҉EË8)ou]oz{ȭSZ^,M&M3Vz1MvE1 <6#OBx@\UA뤌T?OX4#ꙓyG"L7yE\G(kv]-ӱr,]L{A~hvq{U9 uRws9%SG,S~\K(ig{h%_)#b&ګwZ^*[Ք#Bh1qZA O9˗bT1'{jyŪ ( O B`h+ODUE1j;?R7fM"I2YӘ:9c@5߽jzרG̓`?/jI D'̗_ή:OʁJ(ՇVOM@XcrX9ڦNQAFT!>j Ej+RWi4ô9;yHBfMY-fD[ a6[:{CGE؈!f$0`Z 5FTqa 4șL> !{2 Zd*MdS6fĹ4IHM e,Z,(6`l 1AUp-+бvl5 gq -z݌-b: 5AԚBaC2S:Sfm̷spC1jtL#ys ܞɰ"#1ٴHF*|*Dg1]HQԃK;Y|-*TV|hږ5z"5)bj8ZQ0Fӥ0y"yWhDRJ-@Eд"c|Pè~CBس2*%Y"uWP\L͙MWRLǘ~w;#ɃmO&n}sD" K&!pVF*ZKEOs_bAIg\A]~5q[uJRLu}ZE|o$єV/!kڬR'Aɪ)ҧR|OehsVqB)EQ05AhkZF#m xQ!hb089$6X;qliQ}&D(vkYkV+iH"/-6bj]$]]q"kA&-ű=:bT1gŬEE[)VHnۿxo <eCPn {#A5+,5٪E88` 2iL=9vVv| HSi}WL0 *?E'QʅR+6Yk=V \J,(RBҞ~|hB}.K(({,_-/R*)9guWu.MTu:A(<*DlQW-hwAlxxq~vcr"BTfNj1v?:(θ +^w/ AjMkd;/f;2ۯ xJI<&m͵6#> 4+"Sw/μKݠ2\T먕fov '^o# A0<\вO僞8L8.L5 v,.პgLPb,:L:uD1b>ť2n ,f@! N' d܂pJ~M 퐾bֈtRjZ$Y&R%,Gp,ަv#H- bWHdbH{eb(6d/ Ԣ*m(Zb2+Q8d¦O*Ė]ee Oz`f mdgt`B,hdQ\ErzFooX0 /W I 8C:^5K1S>gii4$DN ^0N8ɐ8P\LNeo%q%cc"sƲi/:RʂL4ҀrkPgY(#'0'DЉp &k&* H$wN jF(LEDi &gIh»+D+RZR c bʒl11)1h[.[Q?0T¡1HW,ﺷ-f XKYVhf52EQ{saD4("њ4kk9)$WM3-‚2m@Y0KAFCRa@ <<0In| =>ǂr^4r(2;@!e@2#<œ)=!% 6)$Rtɪ\&bw!+DQ)E4nE6(?҄R( THJQ0LrS2;,/+2*̄k2Q2ԁ&DhK겭IHPELXhPN/)0 DȦ9tS#2&E2EI34V򺧺aqj~(!Fb& `(6Qw6f3p5BaofQB28M{4V(-N),aW=H;TZRKn|mb !&!O*"uV"V,p$^WBOX t>Xuˑ;qocqv4v=wOu!8T#v*1#69{ OE7cy7M :v8'7tPH:N/O ;#L {+VP#+OvL-xM)?fDIDKKL6.ĸTEGj[oGv*Wآ[[")M,e)!p^$ך!zQ 7+2SX՚ '!\7 %xo!Yǐzm9eW6?tB+$x91u3XYܣB΁vگt ZZ齛 !6ְBYBCD44ADzb-A|#WG('S'55l4 6|N~tb/B'Fm y0!MށHT=kE'f:&TTџDˠES3udJWh;83y [v:Xg R+RY('-lN+H\*vҗŽEI~-TWg Ͱ[ڹCӛ>1yGT#Ђ%NT@MeE-Mۯ#/V]lO=ʐe+}ңr0֤HzMs֯Sh=A_+(mWNWlk2>f.eSJ5D z;Ban ;4 AC]H^-2:5xя}^M:{Wz-ϗURݛ6Q0 3<ڧ?x@ow<P 9OH㞛0FEK!g?U77#鱛h;Y}5kCu~w's rh<Wf>ofx'n*/TQ]/e /RcժH>>e6}DŽ'e#۳ھqL,zTwe%ʀM=htDIM. .Hz),\-.fb{!z`/t[BN bw뒹+5/c!>+e cWA$Q CxF&&?g9$+@$ ?95'o9Z?:E2-ZU+=nY1UٞS0YURk?ʗ׀}{8CV'?(Ieg6ZSuf8k-ADow&R;?þGiOWO%.7u99B"NeJnZ"Cx\I>L='D(V(f7j5j%꺠߫kݱ6u6-%G!YğEOԧ O*BC%%s J˚"S'}j)>"i&wC:{ͼN:/&G3䧫w>ȝ &'#Z޿>];CTNQ,FD%4ʙF5tQAE ftSSU%Aђ`Lɑ3\*N i:8ZZSo 6̡P0 \zQ#'2 &1 DY+7şV"tW1]m iZ1a'Fl쓒ٴy]lyyldTz^D H.z "Jy0dBq"ruUyQ=FR)ŗ`f̔ȉw"'ƌRG~CF$53T K{Q i&ڃlqsr\}H)7{݋. 4X%BU,y ?%O#9Ӭ9Z:o{hU uڗ1D4jp9S**h Y71$roĵOrp-#Z.@rbSFe$VC?iVI=GRSS0)V ` RФlMsNM 8v4Mƹ7aBQI[W4(MQ !@Ui~?T:/PՉV\w!lmmc(C9\qPJW6^H&s=!TK)0eהrA~& L7yޅ㽌>N$t^W]uuWiMfY_.5r"D]1pm̩=Q3T8-dG "ag;XS`8Myx\}.8rq&Rp0@ߨ}֏ZDHҞ^Xhv5kP ҅OMzD-eyhFyj oݸ#NލۃpEmVt.s7Ɍ$C W)9u$BZ%k8j8Ҙ8 CQyzWS{{3SK;1)ä1!C1,[f I:( `/11BYpEXӄ(۹;(’)#;<3;K#1_⿬7eZQ@â!1-IL2B"!CjŊC!+Id^BeK &9==aMDM94e,!By>p0>@6\i!j&jkZ+JԮ++i`kHX*?bк 'x)H%r<Ȥӏ$lJ$ /T;ICTP싗:QIAsj<ѐۓZAx Rd3?P3ۤŒ(S0 ,:Ye[XK 1d# AB&:Gz,JlA( D8'ڒD,B}ⷠ'DDٺM̨8F6 g FHMC6Z!0?%Bld>zq!˞\,1)!1n!`643?@EDъ'!0!܊Bi:[ۦˌt0k9`0",3] \qر 䇮+ZP"-܇K.kixDRB|:WHX"ĜP{IsS)p38Q$QѼ7pБ/苰痋Bd0Jd;+IM%tʡMkJSBerԢ:'x 7KbJz-KR)-%q(P5=L"}8̲(+PJC(DJĻrHNA˓`6\UMJFB90p2&Db6e4"T-p:[ SOjkJ#L6rd0.]&U\Y$C Սhj!q=' rmh1c,tO:O-mD,U86V#hX ciCɽAmVؚU$ aѦ_0]A.*޿2V"-tn? -eޖ}'5^nW-s}Es5eya3# f V^]H6NAR6-]Vy_3`#P.OoYPe@ `<^u`>IxP48 ~{D`%a%n`h՚Tmg T/hk,.u.v#VsZy5c#m`N'be2qӼpRbK]C(O#( 3#HD0U=VFG`L;?,;/ZA&`1"D,1qP=](vNR7k..Q7jb-nSU\l2fUZף_u޶]v2GS 6L6qYi%)&p]Vl2(6JaK~YŊvneIz )4 Y^h)YnR<6]!]#֌VUQ[3pBb=X;Y°M1!1ֱTSLU ;U(QqG XDj>M (L0d!eOI^GU1)m.ҭԭ"#Ieǝ~RsGR:f^-oSsHP͕t/;Ii?/R_BS:ZpidHx ->s8r::r9ӯ e+79uQvHhI\`YQ]o[Yn?|} |nuͤ%`9io$ Tzxj A~*.X ;dUçWxQ0:~BzYj@E6vRD5 -!*-Pz'BB A_C !EcDB$g?1`8_9C+de8I$fzJCyLm0;_jEe?ϵ4us A+jPd/ye/%clvZ2+*$P*Lk.PXƪeP <?(CqoH l(+G0B 4E+q̧1Gܑf:^sN+]AGz1  \j5$R*(?d`aiP7fb1$x)aL=aWB;jS^svi=kR֊xGិˆ: >u jޒS`԰j*DD)`FMUhJDV(P5RA׊}j |*=ќؘ ?H%pA2Jf\5 !1A?CnYJ7ߵֶ?!)neUu0rmiD[;vH a7~K8h#!UH2_ R]K 8|(ʞ IE%#87fzX0LJ/9xL&Eˁ~ne ]MQ1 t?= u܁xc#'/ Y>~JY\nO Y;(LvGɲRf\YqstOL=Xe yX,tK*:gtetYN3L\L5LL4!>vJT >U:\C(^UX+1hVd/E`l~GUX(+ڛSd#g8'z 9g(b屖+pث.fplVY3-p`R8G sN{ cLlTEsY1@4M?Ws\Ãowi'z3:rըqsx /=ϙWq(`qIfqliv1ZmF1ԐfmChjga֞*3+03Ƹ \Krl쾚6zLbHYK'RU gqmz]2N*̒D&1f4zM◦_ga.?B͊9յSXT<*Z5}q=-z-deO6{zڍz׫ڐ~KحFKOdұZ(t02_!Rl[RG^eA0kp[!N1*Q LD$T<LkҬz $dIJPk/ js+ JHx䡠u A @t,vf6Aڝ,THj Ńv(6',/Lɬ"ǮPblhŒȫd΁0 ddXlėXL6ɮ!؛L/Vd^/pQlcc65R1o&j`"CD4OxM>2CErWglBtn7n~nN}vchȊ©2-)қ)ekl DLhD,Dvm(L Rק.N6htꎴaOjpF2vj&h1EQ!2)ҎJ|( $ pTª-&,YnZI[*Qwт]BLI3$q9k9D9mhD P,qJv3Ѿ&c;b4C=Ș5dp+ds=s=@|y3o?Q/z$ @ڒFda"hA$1B -r״(\t2B@IlE9Qєit6s6r.4Gn~hOX-±vH눇lvG J.J7J3k)GlmrOLeX*Zi05/" R%'/26%Ơh ³[(" p*0ph3h4ZK(8XK.2J7TNv%T얳n-z?O7L58%2PS,Is94JLj&3B4Fn-u5#N%.7 &2C6ox6GW]oCj?^J}FAAT A4#?##aU#$!CJz52gWIbDeEda `v/&cf)QT b 5J$lT·Ё)- 9>,4OMGzQ=ЬLd5j!k"O>?$Tɮ6hNfPWh.0)$OgRqQ!Q t,A0b*(OjD+SLLA!sAW:QtQAMtNCuAZ/E qllX뮎 &5X9DI$cm33u&{Zb:q64Thn1\b3c61c"%,*5֪j?4@!j`HmnZH!_F B BX2B[pp r Blʢѥcvq rn~CX*¯LzcddfngzG$׬X(ő^PtHKFikx)h4ncb>O>IbNf XY&ڌE1 EshI)P%p.A) b-CʷrDMƲqcX95tQsC7EY+tMMU }z5U/.M9̌l%yIo@r@FPFz)J p}kֶD}j-̚HSZnҦN6YZʌ$XDqI8kǮHJ QണŽI(ҽ,<>?A>*EHzLܨHk5Iqz1i螖 xjLLzq{Nj!gT^':랪B6 4@@wBS:߮;a\דx8ET0HөsZɩKޣn͛dF{CuQqӏ=V[n5D07 Sʫ;qfM]jantxQv G]ċ)] =}5#r<-?+5N_$33j?#ΌdU׿r?Mz\ZA7~ zG/?Wj*s7bl].?R@ 93!)X?SWq1k?WʑDҠ:zoY>(쒹h;sq\wW^ l6?Ÿ\i?ڭ^^T281+yAۆwhj`Ͱ uwq7?\Ww=tzkQ_)'}Q/7Qz=~g;~OV?_$@'$\T,"-xW T/ C yC<SX·l<E'u^]E!G1u G mr2T%ȍaiFA$ 2#˰.2R, t @Y%N:S!ϰU?=#Q@[0j2YJRBT+MS(@cQ-5cRԐ6BM-[X-_Y-CLuDK*H)X2${^Ȓ%n'vU1IRTŧH/@[ IXQWO\#t\I%v2ī&ʱ9Bާ)|m7 1-'.Iҳ ش6N6#PyO @$A9P!K,'v򎤎;;nr|9)ZϮhqrmC0 @ C<`'7C AP/ǟ&.<Ӱ<9GmoD4s)j nŃU9E_x.~Gny\>wEMs\^~u'O߭v\h! ϢnjɶPD(0NZ-E(j7X`z#4? 14R^p(BꠚᥰyTZJȐ}a9*a dA9Bjb&ƗM~],87?~L:P4M9'Sڧ 2 "CG>{Y<(8>h _QR1iIG%MfsrZi/GNS:➡<^x!㊊P>s2&C{TN22(=3YW5PC}Cohb32B9S F%% EK X.0 A^G4Ɩ到;r+Xx[ fh VY:r 6b/b"J@MLqmEa:ʸ5M)(q"#r&3Ot4q5(m[jR}WG5 WbX8襇 F5I"dJhb.ŚU19zQ$C6kŽ~@ JG;d~,2 ]N]JV|%M)"Zj>@?d;dܨ/ʗ@T+kO g1?,]Z  B""&إN+72T9WRi&eT**j,r=)^Vz>CcY&ue:iˉz7`/ Go[M ͊Z; "KcEx_Sԅ-I439[6Bވ쎊6({we Wh4 `@1>[*AHszRmS/ ۔^Ow O9HR-3^G>tg/=VK"C7=.1&,inf+$)ĩ`mmYŘvbd XhL5.Pȋ 1djHt=Co0yٓ썏\<@*'r her{G| CF ]N mDrOc} !{ XLWW=ҧmCPJy;2j+6ֽΛӞk%f(fI)7߿&V5ɜQ c&!)V1:7C$q%?ccG0ėF=?Lca00acDdEj P;Aa"*E ʫ4S͛ǧEE}YR=´#Ûθ#:0I(䈵­<9c LȷS6BE(haL:ChL@|BDAM;b@@bpcfMZdFQM,0e͒[SRav*ڴ,8 p ҶksO|Y ƃ=?rtwl{|7<# \sF=&TSڰrd4 ULvLrF?aȵ~H`E$sꊱĮs|6|LIFx2L&=S~;:J[Ҷ@XG305\SDx(&mIol0_ıCB@K ᔭ8L! MÒ*dčd Ԭy˩R$ D "/I9LD+iXЯ3}ALLQmS8bN= UpUYJfm\d$dc6 e1X bE;LQVLԭ-;EG5%$h GVlV<Y+!Aol|=3U<̥:̲'8M"4$" \p2H iTT$’$àUC#̙|E˹*D@T"^`]ۇMLF]qOCʐRzN Wb&>d-~Klx= G G m8%ژljV_Dѷ(|ZX2e{8rƔ||G @] OԥۛcFO[ hY~YPC=ԧaCYdPJ+KEEE^0k mZm={ǜyytJ%rARrJ_h1۾6}U:Fؾͺ>S:KaP̤&?.%>/$SQԲ\܍DLt M͹L5/jN9B< \a Cx%-Y\e\^u]`MNS+Z9d^*Mb 6|>U¶|0k$bF|xE3Q,_-VMV$ F{ u(.}@XVΪ愗ka!undmF a=H=Ƌ%aA+ƌ{J\!sWđ+m64(t@N(2Ityʤɫg{Ǟ*Z=N]("Ӷm, F3? Yq*BH$VzD&X8 鿦-ȼ݅8Fd> Jk1¬3~jdy(sgzgV߭xW@Ո_?fs:{)ʴ;kQ``[)c=FW˨h%& Г3q+b64`Q6MǿAKmB$Ne~Yfq܎V]bu`DC WIy)<V3'VqB_mqӽ^$ r-Nt+3 8y ؒ8wytGpA|׿180!`Ot?PfIDb$UHDQR=#dO6@OB7lBN_ ?hS=_cOOVVtӅuoW&#g-VYkw^.k}\_#Շb05qS&U2Y z7+L(u(kڒkwO&s'p_v/_Ӆ\DOoU?'8I_'w=RI%O?߿6p,L,)C2ÇQLDQ)E[QdV|drGxGg!g"Ȓ1Ik'ᴤu-̽.p)M52I<2mc?L4_1RÁ=0-$ ;҇?K'M,u AQu)NMUe\ }d#]γXaeb!WS=mV%!6M`bY+]uz!ގt }W/l+4F 8Iaxh ,XX1 @*J n)ze6Z&?8փdBo i9EF#6)b]$,JVk{BfC;N:^ܛ?n hΘ贠j Lɱs `k`0:1c ͮr|Ǎ}'M3 ,#҈x mt ]ފGj'mᾏGѳJ<;ZƝ8=3ZV&_~  .ABJAG@%"`BC`z(,QxW:A{JII0$7KIq,azTJɖBh$W8hK8Oj 'tO! ejT?֐^S"}U*V)CXXiYitphdx&>Cj?¤L}!XA9@ #j]l x?נC[ݛP'WbRJ77vHY]fJЧ أ ,!0?,Y;f[,cœT9iglCCXg,4B&GJK+9ReuDsn%5%=[ %mcHl& *N g~#C @{/e@EAb Gyr0RQi@җ8_ %ּb) !u.[*4AjDOSLʙSBRҟ97?t9ZNDJ;x{jV:kAߙ3&f>~_W!]c W HJ)D<(*BA8%%DID%{e"H$ޕ[Pѥai.P1{?gR"w$xt,F2#(84 &xO_ZdT,.g15F-Wf 6@ʺV(|0mM*Vz r 'ҨP殶c9LzD̢i8'Ŏ>#Fz,rODL'O4oܡL%x#ojj q pQnO<( oRqJ>J*` R#,Oz/G:N^Y+ Zqу2r2`C Rp֊}qdnO4F& OcpP$$ vP ͭo&hFܤ'('HK\ݍLmKNR >dIt.`Z . КU:[E"R-cQG$!$pf.ml+ nPlBfQ N x0&Q%Fb'FCRkܠ&4ck fh&zg䑬U4o֬B!b8"\Q|Sr\g# lff/87Ƿ:џ;*(Ro͊j U 12Xu/3V--QئѢ"u".L !(E3:InҠnޟ3>-.a$Sp+$A%G%dXK$FhD i'p?$P$(2hX4) G(H`MԜN rdFP"E2VD K$:`,,g L4RdzIL#'RuBk3'2p1 P,$2jt a\ Dj{"bz̶lf-m8SЙ#i{'O@zg7@"ӄjӊfvblB*;3Sb!zB*ANͪ0p[/ωt>?!O.Bs]qs\/FtJp2I^ʝEV7G(јw`ttG2)W?`d)Fw-ng*AVsbmrSccY%*DLE%&ۋgetNPPk8u[8.&"WXfWSKC 8"AgDS`vBti̼'Dq* .b;cCgk)`%›>h{LSMKݰ̌7ne9w)[#W;ky6; zWɚy]5u;Tcs*ՠRLq|1 ;FrEC$9zoí5qcqe$fx&pRS$Ch;{ۿ&sm'C)Ug-HsHbmJpE;ZDDWc2O$le}h5wuF7 խ|Fn!]ߡ>/Er)k 0Nk 69CP B$cnh6:w"54 {%0s-6#˼r sށvB|ٮW&oLp|0ŗL8-"1E]rl@Er1cѹ:,)#[e-ysy1}{8Xq']HF0}[D0I@hi(HA8;Df$fDP_ٛ罛gXhnFpl6qeTJ3q8$pl&F{j|/R*]`x ǁdD߽ M2gS召!8;<ō36#h.)ѓL tFT&{?Ƿ)On-Gb%#X5;y5uNfq'bTIlKDb xU"IU 9AiGq9H?Œ{^= xV `0Hxwc쵐2gVI~fH'"Д)`Ie?rB>mnNZVj`C2f zB,6vă Ä́M9Yk-T&Ô@DSR) #iAYrcrm`Ag0#{RK}@|U dJp *U*bK)qoVE+ V)+!QpnA"&W1[JS`XZ+UjTC)RX$JiDh"KV+$}Q5T -6W7 #uk?½^59B4~{4w#n@vWS@<8oet¼2`]L$Y++|wŞ락im_e ?@'M9V+W ;hn۷f[Q8/`M/dbS=)Ԕ˸:.g&tњ5 84.艅JAI9g*9V+Frr]ϊNg])iS)zhѳjrZ?G.Xwe2p[j_z5F5#$XWⓀsH%a!b5&O`"{5fuFV L;te6XRF "(DH>˶6ET ֵ+`)>Şs]ntj!n6zryH@MڒQJi[?*ӍvTtO4 {lUKRUM8,/4˕'Z8Vɢ\~zhL";ȝNA&$m;MZš d:V`4Fey+rr[l/Yu3:Hvo+ї(ݽԑwsB612Q6@8sNy@Ci$f|@eZ+Rh s@5UdOXScNVXQWZ޾A("}iԖSEs)KDmVJE[*uvA}!ly]ڮYm-PH&ϵ Z?ŷV@|&@9\)yZg$ٚ#( .n )| '{ 0ɡ/%ZV،8 P91T Rΰ ˘&8A/ A6+cZ83@ϺpХڒ)" ‚CØk.CSW\n,Bª=)t)lv1 <¥EX G,߮ ϡ+-Haޅ0LHl@rAɥHBƨ1(T*'0Jr'yT8Dн83A%0P"uS s4J 'brI[‚r Ʀ+$ %Ա|0DCHHCXӎ(47z:…ü<0LJDB$J#/K^G3CAؽA8,OѢxŢBOB4>N$NRO<嵌bΑ Le949NVFOd^GE&P51EOcё-x3UOE%+"5nX -l%b\,&]W5Z4Ed`4afhg晋dU\-&o`TؖqU|U=#``vg^wZ^狃Qn |cP`!bbٮaJbPB.F&(SaB`&*ZPanFovZaͥaզÃ&y\KZΗ̴A:bsi`btDA)N=C|AD^5\ C4NI9B}- ɥBꉮAjֵ3,ڟEq5kLz$f!UءAoljl-۠: VX!vYqWN]fm)!m9emHuZIm@*~H3 'ykdl[A#XX[hhQ h}#po͜u1Rb:^^a`Ry/nb IuMWM>5`8:v7pt8-M.#ԆptO!M4 MYC&i $ >)_x!Yj؋mX~24Ǥ{kMUNOsCl4UJNR֡JZrÓV p^1Ne!Z4mG:sW66=/%]s4U_kRg@[`e"|!8{~U*o(Kw$Vnzx'~ Unig /XPL!%.- u]Bkcz/]_W!H)!w\o@Jbr6C@}v#65w~!w6)c`ȉqjxjLxMcH,~υHh MWxr 59CϽ^qϟf4dd򿖈fA`h( ưt@c"lf1G_~C RwU)%<&?ijyn%N&iICӚ I0NwQ,(zSH?LcQUf_swb _oJ_lC=qEJ?Y|c.s#EDwAu@[Gt?w~7#~\:zovxCo??wsNO-?!$ % лLBd,_7D $X6FܷnY>xO=Ou?PS/ g7PRB8RGJJR48= BR(rD%Y9̳Kb3^YYm'j.ൻp2 W:7YsWm^Lk}WAX:J"+*r~abخ.\X= HF:#eynMb&$6mTK"I"&hZS ̛*0kYJb`*XlMk, {[jyո.pG=q\LXAooʶbMiιoYGۡWtΟNu.Ik"Tؖ17ܟ6<  °.CY>}x5 E_ z#77qG}dJqSj⟄9ٿ H7UʵˆAG A-!"dKF(7'bn*.2? y`7R^Lŷb_}0XYKh.:16٫5"BAdB3m":I!$8/f2Z=3jI̜gYBӣ+1ѤC(Jt'::FhLJQ HZ'99(S_a1ŰGzdqOrTr},pђ$sg9Ñ nѺ'1αםs;c;|xBGe=7h!Sz}ċ6AѪ~uIO9`ToFN=@DOL+II'mROԅ7SzoU|Ι5TO-+;Gѣv#`2Mhs@5&?E`U' dLVeX/ʹdњfdn^ E%ADb=IB+ͭ""1zݵI9u.[ r=GӔd՟RJ#Ea:\e+%{J( Z& 7}?Vz5nL`崗@P~ϙ>IfɟySv9#d0f r"G9IF #y=vuzg $*H UBU./bKȣtjc{Eަ;TC QǬ^ٮ9"YΉpf}i gRʜr 唿W)Kt-3TꞭTU%OQ^ TԩUkP4H@.!)5'ҩq]4dFfL`bbދztՎwc61YgX6 K <'x3 ͱc"߲[y'5Vlr5&Lf3k)sN )$p^[7# ۟P y3fhLo `kyUC G8|fћsn0kޜu ѻ9Ҏ4ge4hqi:=;T(1e PT 3sαC Q܆i)9a5tq:ux'<̦M6.7@M)[Y}-N+vy[;(p홾A0s]w:v}Bґ8q.:Q@WMXu ת^btߝӫrj Auf7o ] o}bPJ$ģlRQNJSdkݣ".DNkJe4{&z5e/({oǬ1̣ ~O?mFLJDBጐr0̔7GN|,U.GN:J:clRVN*,ѣGcVn v5{rB.E(VB#GM,҄JP𨧨L@ .TUJf. NP jS%N D7G c8 qk q,&~QQȤ[֌*&_")³_L`f M n,h"2xcqv. 8ErVnC"FFxPMSdT/AAl%cC%x.B#B= !e?~tJHGd=0Zx 0*0GnS2+N++QS GSJ'IH{.*RrKK q+H0л^k*Ȼ-)ә1CNP_b44ma2آ5fb~)i5+Ru7"BeS4 g"$I!`@U 5^^:k~eŐ< %V nȤ@gY87hg>k?%m rG@LVŵġGE5B#Jc{^ y nykCB6DcZR|trUX}}HR# Ґv =*i(TPT~u /0lʒtOInbb$vt=)f]hM'K2gQemEL0MojN42jOi֫Z_i(Bda33d"_FP"x"QUTBPb1X>' obbz *pAa3Yr W&ruSVN9̑WWWtCuYjF.7#ZJM'Fv'#pNxCqPP7ŇplAlzn{^2aBCD,C!N=_UVHTm-D+(MaV}^=FAk@(C¥/(ec「QD oIn2`H\gU0:Ғgg1/ȱ hLK;kjXkj+jT2jֱ+kEz Bd|e e5kSgloByS'VظΜqB_ 8َX$bp@k 2jto*fWwWu{'uruv {%m'CY5LEcvrWq'wPRU]QBR<ױBz^cQA=cВGîDHζK `db- '`dI= Ec ! ʶMIRTT:m0BoT WfZMEه BO_5-[ְK-Ig௤f.f a7mf"#U5zضiPۘ)i9|pM;xse N(+M&hm QWQr^׵Cqy!#qYu7yɶzݒ'dU鞈<21ץ8xZu)w3 9m]B!#Psђr@:XH[I(WIvSΦK.ʹ䞅[oĞݝc0D RԦcectw, 3y۳K4M9X]GVg(xmj8oNKO'81^zBgssQQf<&~i95&;oZ(Xɋ4I E?ya |G5Ȇ eVHYX\VhfiM]ֶw0Gw\>^Lq&:{wwY;Qm&zBvEÞR/ *Dǯ[/<5wW]ɷXuu@̝^:UTsTYR K ~Fյƨ4qҊcc,ԓ(HdJ'@ԁC Zh{XR-n3iK.룑l12;齖OOqZ7ݗicSE\\ I9g9n ~u?(<7iz/y˚ąWU\Ϣzjol -B̲9z%3{[PCܧ{ZB9!yB7gfP$Nhm3]gͼ-]복B7x{luh`}!#v?t\lƀK{iTC,RۙI[Y,ӾHT}Cp㺙1; ]a{ Ǣ;N=kڏK:?^ZA;_;gsSM#V*$(XT(Cr^!߁b2/]߻̋uL/v1P]oẫ29koʙ%7Yupv{z'ǞK:5bU8F[_?԰WFFsD1WUEEȈC]}?Wg^?_??C4T AA,!'+ 6 GO ЛPBpLnHGȧW$Dq&FLmDK1K,ĵ.1Kr+LL38Ӵ;t$\?Tг(-D;G9H&T@ Ӵ=NNUQPէ+XU`JUhIש1`$Z9CY)r zAZAօh ݫo Ɵ( ypճcYPzW[ߧu1Ja5|GH!b5%"~7cKdJeuYN^X<](k\J23s2-c{A 65/K+Lꗵ1үVt2yJѳl+Mkvf&ܷmo-||3|9Oo|S\1IR "OlEt/(OFWu}gMM=}; ?=P&y'@y"L̝<{W<2LwĿ$Qœ_qG~'_~AQ*%3TaT.d *+S 1Q~ GUJWBY\q U 0I\/b|14WR\r6Ph[o.v?A(lXr]tl?ŔW-aGB‘%L\1&(ƣdl,E! xYDpȎʇ} {#fQSaM+d-- lQB"3ΐҥzȀ#LrU6,ebLy2hLcVZp(e3fdΙg&p C7f::pH?@SW0qsny'|(-2:[ٟݻD,_;|^(;ϡ d84A“޽M q-&% &@ ?@^1D%GI(NvNe 1KxWU UB?ĽgU֒$H9 LƉ* .ՠ질WܻL}YKד"ў꼾ew* 7*I¨Du]a#l$GxbFIy"^6!.d*Mt*B vrzOAw,s`$[,#-̱ _rf A`kZ!Mf7jP5ٛ$MÖr;3ک]Q5998~$PC|tI PEqs47PiL13L))a_= kPӤ6}$ҽ,Ϋ(Wsxlf<2; ϔ”*FԼ'Fwb1)_6+m~ʹGa]Hy]x՚ndH,NQ8d_zC-GƍYĽ FXS&S+4"LkG1X7`%S+(AVbkJM)-}gs2흯tTzUF0l˜mM=q{am ~zafi9$I,1 uzh}W]Zs>WFOo Rl?;nķWP7vDɎS7P;6&׹e.vʅ]ތ̤ʖgFjaҿ 12+/S P0k+¥K0w0y0:Q۟:DA)[SAt y< Ҁ02,-۶#0  /:q+< JAxd6X0áVpļpS; NY=ڜZ2,_6h (HDuDr@ i9xixca=:25:[5ʜ[-)8Ʉڳ+DVD)>)_!1Z{Q]۫EܭŖ#,da3>yzMA.JRFAWX[r Ͽ{@. lѻn8XHs KLsA4:H:<A&Id)1"145N.5z&'2~IT:5( &P"J`%ӆ,-!K2 Ͱ7͹XLD<O˰EV8Ţ*6ݶz ԽYltrM X=YcLc#؉Fʗ\E1]cLյsJ!l"`+`lb>īck?l[y sƮo3Ȩu/ j6 7Yٯ z@$}GϚOKCԂ&P C<H 4cH1[DáItI}\۫:J;)ɴ:;XȔ,&J1CS)Z:)5)2* %R0à0R`"0ܮc.+>V>e0aͪZ *b*˰OˬOK@K(]јtOEa,9`;Jh"iwLɍO6@;\#$STWTlM)YtXӺôBs_e ,aix;mɛ ,l \.Nf:#GJOJ тJ%|G~Cs `ҚH?.#@us&W[P)B '; 'L52Ј :MIKQXؕ=ee4(k#Y,X~A' ߐ SY0VLV4825)-R壇E mi BC:8Ӆ9ӬZSz6LSO(iԉ!eLL5Y6RDYBMM PōTUCA##]SYUE5T,=deMA<Nm^hyWk~*١\T<s/:֌vj7YNKOҮOV9H-q7ՠ/0%0ݰC޻ZrqrɜH8A- ڙB I$I!2L]A؜!J-E( 2/;ɡ%2XՓؼAЩ0*`<`afg@^0car,эevF2."ϑe ڈE7ĽZ?=:ZV5P `\߈}EѢkje!Ԣ45 bz,\5#]<5||bV%\KTcYcAӡQU::f2#ȔռR?!>TƲJOtm/Dz&")n]|?i?VWǴb5㋚ *2ȣ^es{0P䀛Ӑxd'.g1R)FJHБq*2ۺ X}:X}IC_tL-tA‚|-B˚A+%2Y@Xehv\ᥧhјb}.Zͬ5K#UFB!NDZF[qkmME c:RZcT(㺲&bDj@cbTtY5泪/>t EpieT5.]A d`iE %Lr'%u eLkLaNlzX]GV]m'ޮaZn&  6ҎHqefk9e9o__`5n5\nv'`&*! 0! ,  _Q(,Ȣ6WPviNX,#fh |hP&ě֌Eb5s[>DHSVUۡ x埖M=~5I}Ky2I N - nL2jePW0`Oj=k?noqsuswpx0[ʇw"ٯ6%S_##4Ug 2?O j ېiv0Gܦq7 jάyFݮV?*oqFk^^E4"rD1 gfo3$J/A E]cEbO.󰹌xrૌ_C@c@ktOBgn{GW)R Fktʪm§f&gTPˬ^Amg_X1ڀbBv!#ҟBa-o!|-7fVo>Cdop~@r~0GGOo~ј-.^ K:q'ލUD^ߍD=W[G IfobxqiaxGx֤&`O &_jMb$UE)i=F#I&S46 y-7Ns&IP_%?tU1OjOz)?j-W( #ȀO}[-w^׷9_#݇b0ߏUz?gk|?z=0ze]`'=x\K#rrcpsWefx_'?+|~ ??`  \0t#,pC;AQ$F UqPBqaF!goHzI"R4#Qw%H1JS+D,rQ+K/s)2s<+1NID"'+?=,*R62}EE=I5,WSWOEPuGRTTFpVY}mW'EtGEy] Lc2UBPAD@mU&sq\3OiF}⥫ע7A`A`X ~ꊦv%v]DزI( ʘ`d[%JN% .Ye 3eZ6BM!h@1+'7D#ʱ}d:i. C亮.̵kX Ìű,fٷ{ɲS˱flM.5::\:3r\N9#HwI$uE}|};dEgP|?l'$ :+|(`]g( AU- (0 nY D$J4Id !픭͈4frnLc0)%#+tn*PYh?,^K{ _uji3]vai-6MQ5CdךΞnNnؗ uQ7A:GC;rz788sÁ<no: y] >S{? G?% _UIa?Ȧ?Q~@^iJIA256 lJl?0/QFko)16"yᖾq_CrXQ5@,,pNƬ!eX6 YYbO,EJ ArTSQ@H2[ Xw0Inm̵EM{HO)?=r6A$1e KkW&K.QW@H%5gR$@2A+3U2\[z!%kEab \2)s94&5\"⛦7gYz/tYާ[ztprsɹbJzÆ | uמB, r`N*Qj,2@_.QGb NJIM, iL;TzPߞxQ%gX_MJ!,VBFRU)rqQI#j( PAF44Z*<P}muCqlXJZ ?ɂz~ZKGivm;+ٔ_$%aBy~Jͻyau˖M[|1BhB֓A)DDI4o5SK5qGzxJ=`,@*6'N"8O8юdKlR%;3Ӡ;abFLL M${.inꖨ- ! s2!G$O @ lA T%B4' B-f 8"jBy8zJ@TLh##ζ+** &FЀRܒTzH*eܕ0zBj](IS(WJJ).b:$W'R hb@jz+~4tNcCN\plptq>- RO 3)pC,t6Bt5S3ô Rtc {ȄY~`Lʬ,Nob@>` WൟboWuY7WD'-+4Ԑ(Z]eɡ;$CMVc:@8Za_gKbbfxlB$$K4iEjZnr^Se;)RKiE(%h-\KXF_FtpNnt&10PC7Nl8xqVۏlwO3r1:7 z@ l[wO4xVwyUaDtCmwUw%x7ɗQQnQYØbN೶$ZU~ULٟ8ZuTYATMŹ{i'Ӫ(̍[ /W[JFU)X:^(ԑ"O&iVH $;*kseeFq&CuzW(n YvhY{Xe5e2e|Ɛ%ZP Ƣ{0.sQU11nz:Zîg!-lay{Oy"aػGkx;M;NݔkӁK5F3sjlDD.BQ8Kݚ5My5[z1FR~ĬZ},xJtSaMԽOMV!C ҄Hq- |z Eg:r]h&P4Pl'b%)% rjYyR:IBve՝W[ޝʇ96RhbKkFjhM~$=MC, ~,bƼ'Ț@\24q7:;Xz̛I!,->@Rg?RBpmܮꘋ`>U]S[cu̳vkJDCOow|xlJ[S7MJv; ~^ k(./|xGe#:GLUF:}}==LyVdżqy~!1}| {=KlIL'inhk⌚TPq]5EQ$Hc׾'v\g1hdz{ޝ__ޜ8hW)F#22x&@hg$*kb  a-q?qJqlmh?RI#0|VU& su K(XENz4#9;ʓUG ՚V53M;{U>'@H4@<x-?'(e[1KH i]VV?khm=IMnSO~g8Q=TP-?s/|}?70"-b4"'U bRJ-UtKP7"J?ecⶳVZ΋@5T@pP?N$\*2)W…A1cpma@! @`\0KR.5s,$Kͫ Sz)c!g.<JGjٵ M2♽SKBS\۵dh $t&_RnYՔt]L `+NXteA?h9]҃B) X?]kFTƓ(X/RT?[Sh-?&ۘn%HĽES{)#j=~0}@wQFɨ5.u)` Wf@]{wW7^ٝw҇.ᨫbT7E(d,OP`n .>69{:_OntBy| FQZghbi7+imxu^t-m6If&١6wkٍڒ?'sG A|E2T|G0JESiV.<G׊zϕfjez ³9tz*q| c%fڋPj? OzDCy5jș l&:^ø'[ b?w:].FhE|D4?ΔL72Kuv8TAyB!wӉ!qC8I.89F8A:F-#}2Kqd@Z1T+vjrR*k;R 32|0A9 Ӣ{\-&Kh6f p; ( '1:riCh`? p;89Y|@bVö8&k;Ӽc({?Ҳ( M p 4 6)) )0H>͐7+8Ҟk:ŠQ"S=p+)>?c59J[/c4i2 4Z4F">u⍇s3;Ml|)Ҿ!% R<`<3<!?1<#:A"(b)KH$9̷;-FAqQq*$*=TA@ 8E-A"yPT iW[D#J ȼYB/L+J+$-0;I :PĹC1n14:6CìBk qsʋS4ACZ2H˜Ja |IDM< (.ԨE8T3XE{_F[9= ,h k*AĪm ÌLw\qq4cQ&+9ZxF+:sP;辜G')pΔNr{,;=b" r1"°$l MKK"()5 PLԆ#pآeHMȁ<-Q:ܯEEH/":$.\]Q̗G.ě瑑s+S@AhR\l$A܌#ZIRq/9x3䬚KBB.IiӘÛn1 %SNuAT;ɼL(ǰ"{=sFTJxƌ|FRYXG;la#!dYaᵗFa#{!NEt]Qţ}bFZ-Q|^ABf`ތf)1G|ia\&xd˲,W> Kl?@ =rmǍ>QB]yGg3Te+A/WczlOqsRa֏%:$iulw4DNᥖ@ م G@I $$"y}Fb;}RC8i_娫\ڲAA&I2ܠߓޚj5aa*$ҫ].$1'ېu[}kf[:8Cطd&CvKTT>NTUDłl:DH] 6˕6C'̫I,)\ݞu D\fRfhݿ1f}Mxfrfl+5F"_nx_n GҾyhP.')/omK`hd kN`} ^\?+ s*zx rzc L-Qd,csƚcLb gjj&Qx2wR<=\bjzWrbn2B}pфk5a~"]8CTNЙl;@1k3k}K0xӐ\$=>SmܣQ6LPfudsgDl;\, S-аL&ҽyMQm`Re\ZulP=_U Ͷ116_-0oWz10*g}8s½h6 x/N_߂y'yt`.طBsb{e.7z%8d ~ !6'bIxlxFqDjFbʵꊶ+u7/ IArU)@٦P EX}Dtb0 _Pj_cspe;5>1 gWsxGZRUrv2cQxoM8Kqv##Fj1zQA`e% QԐ BR_QG#j0?be1̓I^u8B_JC'Kh:5!)Mo}e?ѵ.C_kC kmh[j~\}/z`|Fa1x%ɞ2Avf]]9T6mvmm??!c?sNwzFpf=q:߱*Jg|K.. y8)r`!=!hRh)E"he晾^!HyINgJ#NzߗEHҘ0J~aJeHIT8HmGV;m),B`  2O±ưoʲ#0'7ʹceпPt.8#urOvp/'P7x7\~[S`z6[\6~CR@{wC0 BDA}$L G1űj #O@(HI!h'[q+$Rހ=o`]8=UJ(zWuK)w 6e _0Ht |a Yd [đ,cbʅ7ޠ ]c떺ׅ`(?¤e4BP(F+(EpK^BL{YII?0TcRtY5gT Ah7(GTXa/PAwx0L) D^pVL0PlIhA{ &ŀ^E5%~YorJҟY4ie>fIc M?ݛ(Yq]|ZcB,7iMz,]bM9,>dlx$bG[_ cYk%`IZܩY &ba.o=gdCK0٦g]fc2 Mĭ$'6) _s1#ԮdVڧk{P OtG((d{0q.O,\e34-暀zv'01yOFu~mV|@h_U=fCчW/)BcTO;9|~+>%v-~h^}n+ӏ0I(^` ?WP6f+9gQeMem|aj$TcpB $Ndp*o`cH`KsSTZVd{Ǹ7Psh~q0pݰ) !n h jkb)%) c ~܆YNg0 Il:ώT`_L(¿kb+ult.ޟllB-Q.DVVQnA1nC #: 0J:=*2tj/81ctVgKjGN6j>5Q'00q Zb^_,iOaAmKOФQЃ !p<.؈ etW/l^vƔ Z{ QdN<k)x_pSpa n* ~u;1r)Җ*W2i&P /m Pt))p*.$!y A B)0 A 膵e f"0P0 ♌D$I0B`_r+Q!'n93.,BKiCr3#b+rpJxZrD0hRRȌ+%Z2VcHgbF-"kbEv 쯨"&\(*`\5kַP戙h.0N fcb/_fT Nꈎ3 k#(P,q9R֊!ST.bIZq8 UBst5ZsWpG /3»5Ͱ.bQU\Pp/ 5X'?x3,44734 7->Q;UxI\+w1yO{#C]#=d  8d_莙_@`4  4%:v/Kh:O߁D')iVv`AAA}QeKS iXHg^0vC+xZ^hdXLZv%hph6f&ZYm/dngl)%$R//o7)2TXpFj$B3q" «XR u3KllSw0 ~5uG5U,_ucvLu'/2W4@-rɑ4}vYI7yWSXW3W3O}Yc:56'7Y|=C{ q{U\S$uYz7?s#59Q. b[o{~7_iW`%҉RZ)!DKbĿei,scv0|XkI탲Ԃfj-DXOIK+Z6w'buB8zCcT0h9"%S"R cf娅l)NrfJ%Pf&hzdh8#9ΎeQ ϐEDalu.&TwGUٮ_wi37]uDqW}te |l0QX-ɳYgy;:?;xI#Rt3C?{P<;bQcN{|C:ʻ/#'bE>[_rc;8M#j%i40%b+Җ BED PUXy'tt2|H>1'YRn fylzl_'c'z\$!3iLOɬӨdz} 2SE፜;p"^>bWݮ:Nt#tUW\vwK.p;fݰݕvY5u{+qs19n?sCCH5ʗ\ӴӠ5w?HZuBT%~Vl"ems܍/exE[pJ"Eb ^>?W1̞zhtg3Ly]ם;Maj9[æ:oN|N1ːw7qtG5hx|~#Cy\~_[2,@@+aA@JrHH&#? 6"9RqCQ1VE']|^XƱl'Wd~ȧa$HHc&ᤞ(ұK'.lS"̳$#'6Msl"#S*ϫ Q!a\T224Qѳ#QtO3!61B˺9ΫHU'eVUuljXaFy_ťmw@LUWIM9rDْXDkG\J&d'  ALf1v++*Τ- \@@j 꺮6̾V֥jPQn:C4>3D=4+R4C5/kv⽼ÔgsϺcF16u5!4g\=}b_(x7 ^)Ɛl:C&9x7OC>geBck\|4a Q}ɿJ2ʁ~gG8@D53ARf A" ^LfVB rW : Gc0,QYD4d,$G|j#|"DBبءZDQ1˜k { zUD;Bz0bQ-Hlubl)hEh2{%2)Q2$HH8fy($|L=&|{a H[P)2Sʒ)W*B@u(Z#d-J6b%QW+&?Й8#@&qdӻ7Y=x3s΁S`;]+;a՝^guϗ,Owm2-s(J3"+A&Ay$&&a`r=$RB"ZRdsIH 2dX<)-`N ;'j]JS>$ GK j)v-I#3XVh[$Fo\Dv+UX6TYT%Fa]uʻ 60(YZxaԳ^GY< Z.nts[ 6Uz2*k'_c05 =Wu}VX5b[g^:#ȫ^ם`AF0Wxm2/{g}JR6Dn"2ݗ~w10_|Uw|^|/{&k_> 8I ۍ0\8'㐧 9"˄Υ[#>ب9& -1z0[N+Dٽ>PAABa )œ2SC{4;C;'ҟJh0#I44;4)c>jz^R` .8om?#._Hp9p/A7 $ ?үÃ&@h a8@s@T0rz0t0u G yX>?98 G$Jiv{OҘihkޫҶd A`!T)䟒.B,at,4h;Lk)ˬ@:J˩yc<ä9@Z#ij̷^CǑ;D-"*Sd"7Z,G,KDԵLLLP5aVaE9^Lʻ:,SUYbT.Dƴ %rW [q|7NGQ¯Lǐ|3 'H'䁝<'\'\t(ɨ9dM2ȸ6rJ|9ODLA% Е I$I  22<2\Jd,̨RJ-:%)(JQ '9K[Z7#"Kd#ˌLF+* YЮ[xɦY%2h/ι<txnͰG0Ë[ U7dA,$gg}vEAc (ėIě}W)#:ʭʵuљJ؋Q#<%1[Y@["[KkBYc%{S;S>0ieS:L=,õ!:*LR5M-@̄MLmifk\(K} Rd"b–QT9[]FMz ,WNTo l[źOی]QeTMɣ %EYF\\Y[4oUϋA/_U^?xʜ􂎈h@ǴwֺmY@ߞS7j9♼HAYo8[i:xܞP;QBC/s(|'XՌQ)!# YH\EaX`t<^\L˕D*ZoZ M[3Kc,LZNex B"Y%:NZA(a"PY.EZN <^4`7 V dȰb) ][`e\m(T eJ.c\Eqc\]Y2g\Ӹ$v8;VБt݀֓dvHb Bi\@rNf$m^QyAU z{-:fZI!!s߲#]X\/߆dvbe__3A6+Kf>`VpýE9@?m4 -]v}uSd"ᢽ>YR)+d Lb+bp0sb}b-W[O Q^93Yby5JN]Vd9㱸\A@G(ϦBTլ e+gfgBSqv%Fy#LZ6C>"DW#o^RMT h(۵hbޏl Q)i `~bN԰7WA9sjUAHo=V/@3j4ΊcL㐰kLe㛉U6R3ʌ+bRn B4$eq$(ih|3C)nƇZahNY)d6Kvb"z׽̤f#5K\NƢ^,iS۽odܖPii[X\8T' VjwpEgakH cj[vV殞V܊b>T|1qwE."Q^ۨ?ozw`)(w&; :g'Y$Y6~e `@Bm-w)\xԷZ$8O2n|C8ByJnmϒsMfus\-\ncPg6xy#bwEݵT# `& KB_.? Xt5%Qu?9y'ѲB*],S 4?ѓ?gBHhs9wB"UU*9z"",MeDֻUֆnW gZ+* X?xrOW)ʟ_o:{?:7L;_]f[:{7l8nww8w]❴ZL:Y b{X Mw>5J"oJ7M|_7O?)V<RAR<<$pC] l< ACat5D!yEUddqcg~ግŰPڶ\R[Js+k-k.˒ZLe3Ag5|6tEt9γ^;AlAO4 TQSEIKGyKA})R+MiOON-IST5OURT!Vմ;YaWk]u^u}`XV uTԝEFeeUgQmT5m5cNV܏:DH ]^O[z^ȍxݷbDʖ2Jf)r  *Wꮪ/JCJ/K;Kư"Mekro΃?28>#֜ҴH5NK&ZÆmӂ8M.:&nd勮ܶb/. [ڤ)W?6't> OIP; O4K\aupZ]nFeGu#~*J^IG%ף+K0KweʼnV|< C|gUsFZqIUnjUK-h-XCPkA ,8,`WpP< "/8Fa"?s}˹"X ]xy^( B>HOZK8PC)Q7aODZ%<ddq; 3 /JvP%+~i G\ }ZC*TtA(ŦTK@H-sPdEL+ yyc\bZ%MiFNt?j(OU"?Z +T! m) R(O*QYKR!NU\p^s<jy-bte&ry 2ڵԕ_e|Nnay2Iq͗^ ށfι"D+1yxO E|BФz1^" 5E#>eS{K5oCջ`6m 1ouRI'$6<۵mٶ ;Vً4֠򛄗+댼yȍ]v[ꇿZ)0}n5yL..D.I'ġpzrČL`|RkƼg,Y@Dž%R GY ,s\l~\,WpfΔB , .0r'&rg-^O/ ω=kbHHrbH҂P+o:lSf#-n:XnO\Ӊf1#ORmf9v/B-6)k5Wbc \MPfo% h mqrΆ$oa|/z1'JJN,DO:X8ZlQ*2FŊ< BhT.v[TʐRЂ)r%[o = 2sN%0 .ԩR"Tn !g2rlqp]p^p/O(Pέ Ηy<ӣ f̌+2%t6s\lث]2x_^ (p(A)0).&1RcO28BATG1˓,fMO+ql HdnOSc.f.hi ƭj1CGLMF+$k1tO*FHD,b$%h'  옃Q% 8{LQn-5J]8Ӏ$L8X~'#lPAr%%ӟ"l; % ʏ3=#sBPV;9j? k\,W>YX(vK e5"$<=ub7K11^C<d]U,௕K1"ok-'^Lr` /c8&jԈ5V 41<: L3Q)vzczQf0{C]MNf @ esHrqpUŢZu0`~n~p_Tj@x2NRVV>="YZXTPY?~3i6$g4k)k u/:N0jEWX'2@G)Xy@p@_! bA*/"<;”'/-Ȱ2cb,.2u2/WaJ)g7c–P9#w4~8y8afзF'ږOU:yH->^8B=d#}bIX sQ<p~6wURDdoXaВiu#>E=ֳUS>| 5?['ly:"sTR[o'L_Wj-4u@YHt@t{@Lբ#7}-py2ω#*Mt(uvstT[+xd-:!1ivˏwbԐ4j#UךV׏mд P:yRI3,T2wF,z܋•|ٓis y'iTyCU ѵIؕɢ1B1?t>(Z4,Y+{,Uw4M^{M?dOO`4}iMy{[)#[f3m{;ţ:}c0zS1_C(;[p&3YSNV>JFV! $M!<x}J,|oxOl}U$Aj^?˹дs5{:>]@5A=Y8s*dܵMO߻=O zGbyrhj3^)}φ?3,-nM-\1_7ŌT8b}-_˦'ǜ^xgc&_^;zWݹ %QuM bt5Mclm?RIiLKeKe GHW=( + LUJUNE$rY"Xkj\W؜:Y,$]]n$ OM(p>%?{)ʧ3o5ͦF?ڝF+6(I[]J}Z[{qwV1#9uzdoc?}Q~2'"}Gh>@o4Ai  B0P@CD10dH?b1;pH>I2Db=Ȳ|>@$*J$-B,' ʤ$2̓4WŃ=K;8ND10K=.ӹ?4@'%C6nI]FQuݸ8l;KLZ" AR1u%HSB*P2 "Ʊ\,]zԕ _JT/B+ bzٕb*kk`7%rۨmdw.}@-hư7}*Ԋ ℡ ]XX~"WETW4J:δQ2.J7tfص.#s3u>nY=gGoi iڌ ?>^>lpCSlm\ٵQ~ݸJG;nT%䑾OD8lPB|ùq-Mĭ;BV}<5AP41%BQ[xefYsU(OVx=%mزdxuMm] ~)MEb\, *$JJH8Y~Y=&KvVk%M~W_ .)*5փqbb,;CNqu.)p'eG$CDsY:g}ϴzx?OqfJM`5fPfR&Ȇ\bp9FckE1WMFH<[nmHpA8L.E1&0ۃH ̦tTq >'J4QQ`݁'ƒ'_c223;4u7剙iQFo&>ҔRW*5*g~ifN.ӦՂQOM"7*+wUr/NY.tӀ[mH002i9;?Ć3X:)+[|uWYVj,OF2 Q,3)f}_r՝KN@VL2 9<->^fKi_l %[63e6ge{p4+.\kg. 5=ۗe~&;3uFN\r7xHc]N#V՚ѨF|PJ OGFIZe'MxhMilI`K=M+GdRSmM2 azm{51l@?H`JU꤈/^4~ոcMCѱpuvtP8djtW\l3} g;sm:)h'#ʳK%i2hHVT<tTFLjtoNWuC=WVPƴoH Zd)kUAn'##Tkc~5/"#15CԷӺ/`1Ƽ! C/+3Bö5960o#S̰ɷ{l-6*?#yw;A`)/=@ ߎ;ٵr /'2:ثJG3~C>YT-KJS;?kF9c -rv&&;93>IE:w0~ 3@dk@3-@3Y2@L@@?F2"eFT6heF`$iA2x8lG"//w46!;#0i<%B6'G\++,=@"=ttH3bFlCADCS|A$7C8CCkC! R5ãU!1q;,6:NH2c>?Z3A['dTJ3J tJ4c8|N\P&9lDX?H@;,e@+K@Ţ&$Jl#WGcKWAkK5a5rFɟT?\FTț~Ik[$ht/*v""x)0<ҧM 0У7© ,) A\0$H}~Ȭ#Cr;Cݔ<6(p2sIZ(KNyC49EP3JD-t Qv1hjJsOP 젿F \dLJ`3 u >ьǕ"tjlʹrN{}S\(ѹ?MӸG4DN,?N5;u!$ͼe$<)|B()aGbűE͙B=t5N3QU1SkU+8DWN'$,ɢ$Î5!G:ء0"_\9=TjḤ̂m GʀĥPDԫmUS3 ! ЛFJ۞8Ē ߙQq?S#Q]#"d˵KD\dDVM"VrFdHzm'j1ML$W\"yUt#?RbbsG%7V}XDoMX5S8MH#OR Mg̅nyK%Ou$QԍJYeRJ-MШYKs=YYu3E-TدʵU[s'PLŔMUFCP(`uWW+Nj ݅FSIl2Y DoQ3-]""*Mu%Mmtuz4yA+<\z"72>m\ݲVq5N%Md5su$(2=ֵ,%[]@*QR(*Y쳥OQ^EN^uOOŚY]SkCTLD|FOT̞Pԯ@ DsVJ$/*Sӄ8Seo]5{U=L_pmj_X`mL ͹[4,ޓBu6ΰ(U5Ve`(N ݱ˲%5eu;$ ߾ =Y^mޅ șك3RZdR:-:95HeZ)RO=U%Opŕ[!_`U "5pѭa`c(iQ6ON]VVi<0R=$We}G>RӦS15H$Xu1b^nQPZgY[P>.,c6/b.2^ԃ^ERxOĄZlg|-pTIu ʪTΊ L0UI[@2*NalJ"-fŽif]VVg ĸ.c `fSt*7^)$e\>\4M]-aI;9 dTᵵ&pL =fn5:V S|HV `i9<ߵ_ adygyczϩh禀N~O\HD%bFhN; gލ3lTP>61Ee砯mf m񠜟g.Onq؟q?DV8:]{V@Hd\HNH U@. UA4ꑵWVRpFO5N7(kt$NGHt6Qa@p$p/1\d'@up le2ڵgޅUN m wqfPf08lfmWh!uu=HԏILў,>^mgG7޵uV$ t]C&dVW-*%L=kaaa ZFeꨣ8oӛG(NG ݱXEXuW1fS4oCNX6Hxa]@ W hV1[^Xm*o2YL %v9h{7j Gi] p0XOvϪcNv# Lkvno 輦wIrø1S xeüZNTe>s瑝j|Zy<Gye ]FrOt/fiyOSPBX8cU P:,J>rwc%VA_%\ ?t5_XYFF!XGyCi+|fYM_gӨ|b/*2G wM_:^XIU#c,}jG[_ۃڎ{o!6' ic,{2Bdr:JÚkUmhDMjYm:w+uoW \^&qxOGDuzh yOִ-}2΋繬=PE-, 9"Ȓ4N|(Iꢩҹ+Q.˒TL1̳ R̰͒RNGRNGe`k^嵁\Icn%5H)FMD1ط1ͽq\+f8N#j,gp1U˷͛n?Һw 5|"Ѓ=vw aл}uBby .@Dg'vZ?Y1pDr`m,EQXF1 mԼ* >l?'t8ӎ}-nH0[ڨI2\'ҏOSCTGDԓ5RD=O+@|TѴZyH'm#J}OS;M}ODgxRZDVHceXm^uqf`پBc~7Wse2Uj4*ޅh;.r޷zŎblo-˱m3O!-B؟$,?vZEC| 9dB:!+el>b?5N"5P)4&b#o1D&ڋPi"4TC1#l%wf4-F o/0f`xl70ͺp](1ɧ(哛OjH'6`.Bլ1JwH)2 rnDiT:gKΠPU%Wk)]G^ʗ_,I^3dňE|*[b4Ȅp*Gh_o Gq0pYeڡqۋ1"2VH((eGQ 2ͣ֕h}mRdUobj;ؗkhlS = Xg,ƨˤ_,x#\^}Z%/o?X? )Ldz"[N}י# ҟqBV8tQ僪'4lbVnzY (O2Hʳb+w.T,Xցy^&}d< uab~VHM9bE rgAC^yzMI~FSÑG͚CHm غ+fD [OP D4œ\JkqptӹkB}LPS~$) Z*I[=tNS ;H(3[ʹ:8Xwm^'RtY((]\U5Fk@;8(Џ[ Y5]w]GxE*1IZ =^EU1IJ2"8֙o[Z:+$3Mt6 9r,;.i2MB-G[G7fo†Kfm/Zg .V-[6n!ȳ+ue՟]ud0t=hOI+yY֗Ti:vmF"yknVQ7)^~ꮬ>]P9ko]9XJ޴ Y?Luޠa`́1JY]_# ]=H"+2T 3՛{-=fq1gW]R*6rLJlT OEHq!0BQ{Fb1h’'D⋆P)%ǟ뵮!9c8`i@G3=b,J 2|9-6lM=L)bR~^잱4# c+@wV*܃ŤG<9I{C,ܻXF]L0^N zz/_eiD(ILԁ?Wl@Im5Hbͭ8*qxC2sU >=F}io0U7:@]/Ι }OZk[~H/"0Ɲdc?@ NLCĽ[+H齮r2aL;ugg j4kƓ0< pCwy>}u`.HI/ekKTo%SE:`nrp\z]H/'nCł1vé=/X# .I!k9(֍HH>ED*JH:D皉fNN Vi0N Zh 0%ړ'rI.Ά6`,lzDNCuvEDb)t >&',=&P/*:,"ƆmGn<:IdzODRTDDO(ƔT^i *V+)Y%6$4m(>C`,hP L" l2:chǀ) 讞ꬌ 3 L2J ҖL*O)y-0i`f~I~%%/s v=03 61rS91nRjA5\hlFR&@`Ξ (L(07n %1lsrs< Zf ]`äGQ[e>bB0% JW&zzP_V==$=FTZ z,"]lTWƐaڰ[]MJ]?$F<g (45#$~N|{K?4Ni<ɡ38hU!Z^%KIkcHVm*NVeJm.<;Cމӈq1]K%Hrr A&ؼD!6>n=[v0>ݓUC7q(-顕eHƏ%59d,>n7=/Sv;=6NGTK["I-]Lbu^%_(.ƉT~YLEUq' E_=k6L(H`E(u&FDw#͖IvViUDcƋ[Z\CZ?Ax }^dI=@c]?A+`N"W 0D'㆏WDd^,kZ$~[fz&iSthd DښVz >Qt~,ck PX5ݣS9} @suɡ7,#[=&EdcN굺PP/ۅu;Ҡݥݔ d. -刓#tmb?$%B?bhM)+=hM ?дr(S嚓UK$%jJ]5[TD_W%2[+Tu\˯vd1vaMx)snVryXk4ilV˩5`sCߵwy02YM1I;N[g?=ߒ+rl<Gm?juC䅛,. A@n˶%At)')8CoO#خ Hh2>3WL8QjBy&GP3GH⤓$IH_ ' r#J,جu8̒P$"ֹN=x=7 DN>o ջe;t /M:g( RaUKYj5ERRQUV9OWOc*Y97TLcY6i[6gAoW \ikM-*]us\'yW@}x_g]/8#:;/- 8qj'B!k<St+=Y (-]Q3=l44sƃ;=\pM06m[W;8WNhQ L͘C=ƉHg}b#ACJ37S44lQ˯3L<`Ʊ%c[J2m=NS"BWdy_Y}vΎ$ 2L1 '4U'g/4GWu2W 8n$6\u^9峤D~ҧ4HfsAgzDz}CqR\K)? @}bu G!}P(@U:\ Y`0) `uJAR_PEIa,,d, 6?HC(<ʛ+!GNEUר \lR D(H}3̹?>{1y%M (U[bT+gפPVj*Y?,p;h\{=MqB.%-hU^(ރhoq6>( 'ap'oM1$BICx~~7,Fi3@=Z0&ZD{qUCfOmp՞E [qҀpV^j/sMy䦄b 28T`h?v~O#Dž' tnKGq$tqyO$ΩD *u*xkR9Fq#ΔN44G_MMP nЏ7'\3M 0%D߲J\w*B &ȈV„SVO\ErR lx& ~fA Ra%l6kvmklJҶnj zM 4 (/c @@{>.L@.`XSLqep1!:1a;>AOsA(ܔ8Pܛ'@?K"{J +׌$ fa6ޤfi\ 3/1kA}B/#PGj?;Q>{l6 9WdxQ5+P#hCc?i,˿<|BGlvФv5b5 QVиH@!H#3y6$& B ! EZ'I8}A|~:ٛXBZ(iXL\ A;O$ /1F!xޣ0abK {[q/Sُa#גx1H4%My#>Ҥ@ɚ$q:*Oú 3y4y98y'8tɇ<8zÀ}jE(zV˖!b, qLY5kYDtBH5ߥ AiONŨzyJmY)EA ( Lhߏb*OI(ȟ XLxߘ \1,#֏m l3#q I  HHMϔ0:Q@Do] -6X4KH ܘqyMx!s"x4 Xܪ֡ܝSu$ @`(4Ie*M4}i7 (!FY`~ בvG* 5P5lr 6<#s];abUQd܉!R#`G$vQv 5>=ߝUiS>WQ)i(kMƕƽnv |fوXD( YeF )/ \ڈR,#ʋ|E\ CaH9` XIfBA6"eL D5(Jc8ؔ([͢JKJL`h/P_c T 鈞&P(Թ7a]ŔIfMXpE8%` ZkCD` *%[ eʝ@Uɖ&:HʝTyל ?M > 85.\|?=UI=N6""k`>i PZB*rV\wX *pPHH6 "i #` ǣ:eA{.8@sCy/qY8z 1:?[eۓ)EFmEi΀yמS}@cR0d5 "X% y HHv}#t 6# HE{턗p1%ѨLxܑ 2 x<ȦPUP$Fnȋxͨũi $E}1 &K-5 m!R8gy`ʞۿa|[,6(?_#PUPb?zO(Hz"?y|rG'ؒϡ"&\s>h.kD0H PfJ`& 5Ʌffujt|z[\g I#?=9=6՝Xޏe(P3A] e1鈙!yB99;ׁyF*B2Xp)wx{~*S xW~XQ΅TMЊmu8̪A0y"Y}s]Z?˰wf'C_bf +_#d\@;;'/aE%J?7˯=elT 7W3YfQŦFBaqSnOjU oKC!&?Ļۇx%pxcބOE/"}@C w_<p؁}ټ/?h?Ov޺_DZljp k j´ ԑ$QyFLQ^FxhHG"㔑+&㼠ɣ;J3㌸9L$ 4TD#PM#D,,y2OQDL:Sir m@<˯ Եv0,4'YC|}xZ@Ҭ^\2׃I<'ʐȒ6OGYO%N~W`Ð+m K2,D HrM @XgQ u\d7BY£+%`*ǤК*j%2#kp]S7 N!$(2䁱 ' v7TA)3ŷxgv?4rn@u`(?ܰm`:kZyAsѐWms7m%Ɣ3ً#ޔACCCL] RN3 ȴӊ 3#Xb,?Ј}qՁ+"{-d8f)E()}hԲ%Wĥ9" 8jlbChAԛ#V2zP=d$%jEP"6 [T?=")K):T 4%73P˾ ؤ2Xm52}NQ(2IX- pX󦦧㑂Fx,jwVAѮ{Q- ʧKÏ(@) kd@!=via0ڰno!5(7Af*f};Gg(3"c~VӆPGkhC<P|5@2P4!Nt ~KmՇ'!}趮Mirt(ၞ>?օWjɈZ?h`DK`[jH " m,gt,FyrMM)2 I%[ΞR o*7#=XJ3fK8 % Vo@%QP5*L,&"=)Y/I +ee$bCq$&+Sd yKp颖LRJs+uvQfEvVD.Cj[.qDKL,TD1I!Ҝvç4g%b#(߂)Xëe_ݜaF=(۲7K].mgVH Oonsa$P^DUg&(eW0MEfBebVp+VL/eJ@W Z$AyjZg FgID[TDP z|@[Yk ,qB44`XIafDRxCD.FojoLg'ַ! .-E UH ) _żBzO$ $/VpDL&$⾄ ,Oj0K2Bdg*[FN[ĴhF*D'UxhJKGPn2O$~<{Ίf ;g2;o8;>n.7tL*@CtgGpDJJ06.,n$dPIqIH ls)Xhd *KnJU!輞2\'AAj_%'(Ab4d*kg@PFP2 tghǤ=PnWFPƄ$+ ,Xm:Ch2傺+r)X+>SrJ+*g莎0*_Lhj+Ef[- 0N%P(p:Y+PnVY1HƦP-$Rjd~Q/"M(XZO1.gTfN3("[]e'"c"DE)X~ŒzFy%QjWEPFhƦ_X`2B\Y iBmP A/2\Ч p/,bIn G]l4 2ʎH8I P!%F@gde2`f+#LI;LX(,"Nd-Cem&êX*bڶº&t+RdX$+H"2HLjPdXF{H~DkqXqfKqdzG s6o%R Ǿe?DƈMFy ɱ.J NHvN/y/Ύ12s:)$(n2C\Ll) O06O|@0BĂ%,UN^!TB EZ)*Bv=Xdjmd%%]b3Y/f'/S:{FpPX䆸ѥlN.n5iΜN {[R#Ef艒D"sh/h).nX0ƺ-iUR5DΉdGVRJj :b+ +2L2VLLhpQJs(ejXKWh+C2yarH@qU7HV%bTҁh Y]Ō_6I.qt -_@VqvTFqo(0VS%b$D,ETd](DHC)bV%ňl+v*M*5¯\,,q( 2MFjpжY(~µgNIMOzeƱ#e䜥/g#OS]u:@nȤB4$;̀l4\9D,<,t#\ <ޡ Y5 HRe+Wn%FTbX#֕t X3jVfg,,Ң,Wn%#ERNb.R΃6f"1"CgZh*zHAZ)4/'U1J/L Zė +$Lqjk򰤌کl;bQx@-Gfc[$r?<"jy*yXR2Zo@VtDvEh[H'bb$1.pgj,l~(/g/dm+N)_w;EIS#wzC`f[ȟ@34@jAd@pO2I<5ɼs*ɽ<>{71 8s>N{@%ʍ Bb_:j16f,%. X%}jxEF]ezY"cjZv*!l/F(J莃./KXPF"H*X3>RrK䮥5硞ePƿ:JY tP>4$Ν/$ɱT-PJ~zYɜ6=q BQ9[ш,Y^NI+%8dݓY1Zqbhݭ\Q/߉3KWր$h`I,fd$K*>FI1/$%)X+tOB5ntuf@iAlL<3L.<>s ɻs!oУòN5lddgX_DDղ iF"6(.75F21'fruBFOy_<`Pe)OE!s]b7zBgEA%,-+FpH(7DXucLk]CmDƀKs$Rd O*jL bH7 ?Ͷ:PC?0 6戳Cf>7s ]F#Ft1bC2LkϟJ3I9/QC^s; aZxigWo)% k_s7/LV3$}_o)bhz!1`i>(*y :jsR+npRfY?n3 w=,?]Wv>|?~_A/?3|@ 0QAD&0p3 L% DPTOl8<FpiBqt.4TDI"⤎-ɬ#v>J)(Дb'hS4m@6sӜP'uBMT2 sB1+.ƊԪ.K-*3;IrZJ %A0I/'\*)lڎC( S^vSf<թ(V;:]Yn5z;JljX6ʓf$xHO37? Y]\ L)pUlRL.b`bبɒsAITL+KS8qKt/t *^D0&4By#% [:njK;j8`*@Vmj*򸣯KV-c<24ܖmܮۣJ73oUJ4 uy@@^Po;&+aIsE=/[ c^q E{Qq< oMMQguuevDMux t@ DVtK@#;D[i4+\ZEa%sn&)" ^ 'eQ4[g_QA?„'ȑC*dJV$DY"ZmFXZRJEl!t8-2۰Wܐ8xlD8WCcJ+ 4MCpVE4?E1#"Cű";?GMU4aAf,Ʊ3RȺhdN\JzAAUg bl.@48SI T)"6"VpV>6͙(JJWhH\ 4"-HTDf ;#쎗y)&I XjӇ*R<~(ǠP"y? 'r'@su#6;.!B. P$\C"xo?A i/ e$hŞe -ŗ^ r2=N1_MhrO[ `3 T8B%G"?*u39:G (ceBȘYp QfH:60YLBi*U@# YAjdI "흕Fԗ M4y\q% fCٵRxBKbv%7I1ƲE`ۦHP0iZ8CSB18N؜y%e%3nJ.eI-6pwLldI-ma+n6hRITdBQutUk깍N ͙v8G*ӹD~GYL&O Pj+!xOwj (Ɔ!Z騊k FP>L/z>yM[ua,` $ fd6Nɨc,QV 3t)S8+*Vj&AFX% gsCpFbP]*&SS^k?,6JS%L_2^ؚ9Cp{1!~gRF=vpNୃK:6""dF2Uʸ>XaGeY^$+UIVzó±F}'pճgə2\"ͧ)4ނIf^bI k 01_ W2pڹr_T :y<6Å^o"}Уʠge0(\Cn,bۿ(כaނ௥ju¶hu̩%$Ũ`^NG+Uug2̬0?eE ʶ&ؤFьHKg^'9U%[u3- (q4+ fꅘ+HEVƗmvI^ȿ/s`Hae!(Zu\N$)ݞafhDɲY _=I %#JnW({͗A*Sg8jA c-q84 _qV&[!ڗ3G,xB 4 "Y%蟚Bhz!Y=z  )A۔mCqiֺ;ۜB;!4%kml30ڛq0hieCW88"8))idZ3B46/ YøȘ 2G I0ԡG!(ߛhNDE:s} mr&G X!( à Y rb 4 d# G7 Ča6b9Y.@/q'3uoª#DZGZb>>* , zb5("` -;|C! ڡ>s!8!  [!@Y9YՐ 5j2!'k$&B™&lqX$(̼l=)*+EˠȠ<8C6=+ԺY c٤@ ̘XIJ{$7П؏ "h cJ@4!*#i̊@GG*Ț@?yw6ty$@RŖxNiG$VC+ Y̐.PMرEhtS XIݡiХYb⽗P "I@;yn# l-&K+zrmj҉k2zt919JS9yÎ띗Ԩ05H sSUk Ϳ90S[u,ȿ,Q0QfI X}dX $% IW }Z X d q>Y %[]TL !?12 *g+,*Q\A #8Iۋ Am[]% q? )I `E+* K{ @ЌWЬPL{L$q un \ Ʌu3ᆚBV j*YYq_ʫ;"h!*,-F0S0QRK5bm# AڂT0S۹U/.,y9)B~*c- @76h|<Ԑ#G,8lClBUAX²QA0.!jq%V^`nJiic vLAUۊg+a Iv!l@(MUV (U8Wn1qn0WHD:vxA;l;ؗMy^ȓp>iY.F`YTm6(2FΩ9_3+YI.63+~ ?8/ Vˊڡd5i m deݷޔ@C)_ȒmYVԕb(AaúC[*qj1)ڠS^)֮bnrʤRNayb9j,_m kcͺn9uz-"EDy@`&ڢ+%q(4rl"qe$fW36ڄOP͎jQ̋WNF/n;"ft'`5n DP2s!*Gf e)0"6l  h-ףr+uy/߀ƌb L): ItlY c7 @OȉqgEC]@x؛M >]MQ '6 gq-0,\ArA][+r*ˡ(W#{+EF'[!)n7C[AVfLc <@ߖpx8MI0;?>\sͿ<~<3UFXΙr G I#?֪#Z}ږ恤Ic}ߔA;ayX8X N ry["6u DfMD Н߰*7Yȕi p'gGXiJUu ZטJ>` e?PfB 4U]?<;H_$D|?ϲ\=_93'OtmGcGR|k?͕7Ҭ4V_$B7שg6\_[w/O?<‚1865?973-偗kkhs7Lu}NWgc䲀}B Zք9O7]t7<_jZDzxjh,*/J6E3S8jڷR*3L3$Qo;^P)Ї)CtlmIRS.Β›KӊBR.STO14Eӊ1S)OTGN3e85/X}a]O5}/_(p3gZ0.Vm/贆pY]']+u[ u*_}Ȁ.O35fk?rM%/$H]Ko.UX?Md8-X%;vlq92`J満+h-ք4MKrMrֵ; 7Mγ8Nm>0lV5"9N oҗJpy.Ś@7'=Ta4Ņ<1bWD=,BeU^/bSd 3*.S;SgBc Kc!X:^^`6Ov\USXe4ח:Ӹ2\X8 ~5Hhqɏ<]K `ORس' U' WHwTUi *57R &%WK-̿Th[M6²_hP?@}jCWWЉhVeLZ@|W"HlESɪ| -=jWJK'T]R|0$C-@hp ZKOi MSd82@Fn oG v7 \kM@7V|@||gyilğ= ;DŞ"vj]> Ap.MLט &8"̥",;? 5 a%Z, )Pڟe1y_8dL-ф2:x^sJQ 1dQЎP"D1C Q~{IqEӸ@9/K:?x-Q f Ƽ #0 ׂɓ(&M0$ :T陙$N5j M0mjUSa"UƱdj8+Y7BUU sDVȻxÞ$|ҘҊQIEgbȝ>*nZ{] HkC)k^g{g72JD[gL]8w4iZ2{nvtچk4ۈإ63f .ZN  !Tk-;0ď~l PO /UkUgq,?RI԰RGO)|K )u= bw0Wb]8t%t`My9MGY3՚{9!6SLJnXl1iq%fؙ>RřKyi9u5Tٰ.֒K[>1r^Ks)5lv ko.ڌh[m-v17?\I ) Z @QrJ' p 0< jfQm. i~.ḡd(Je'b,0 uDd$bj(.,.lÊDB/|&SOT#Hb-&$G- '+`D\ pizmZ *k澦Iɾ TeTYn\;Fa B:z(B>NMlNL *EmʩNQD>O'(+ F\`FRvYh6JxDdq8F0,/*'i$QI>)D'6͒cT.8hKpoد &#(5)1 Z~Eaf"IIR!=A fi~ RQ K`˶cF$DM ;I'p!"!'7(b-<'Ғr)b z" "nyg be-,+8WRy,`u-a' r8.B$&&8yiD֍"xDh&:F@DuD6"YmDz::VuGTWSRŎL6L"uJ(x,BW",RxD]Tn'k,,,ynBcdcBuHDO(^N03- n(m&v-/ z2+^iczؑ9l@S>m/hQڷS@Io>hn.`ĜIbEUF,I"&M-̔!@ZȂwE @^=FH`f4 ZH!.5HQIdFSzG4§cbFa.߀J3Os9p.Z(XSDdo3ĶbKŠNDJ*d4LMj',y!( Jz8JEJ*TWS74l-3'T,X2VT҈%*Ō\hxN1bN=RGs0 a{G"|&v"|,̕O%TE\doT #9c[#h!J>anf-Q\bj@0~%OXUeUEFJ.nx%(EM(*6_hj"bR{$n.QTT L)sQbNf^q5H5)=k ~ٽ?T85ϴ6˜?4A[|&}՚9c{t`GUP©4R* ^AF#[VHԑeVPtmz0ΔC9ĆDe$' ֽFy GEThWJK&W9s",|5P:ꢪhx@b!sHtEw!T*7\E#5ק%dZ4{bޮ3|N hDT|N6a6^#Z8~`ߨ*(7QRϓHuł|Z5`NWPP #,7C5(JuIEw Y*6*-G0$pvzn-өJLG|Æ@ lٲ1OŞ3d} _ϛ`UY_t9w>ieR:KJId‚UJUNȂS89A@cfun8~8 VLlXZ9fKjӪN:M5`FRWXe\$+š`Um.2 BljZG҅eTdYhDV$.2UEb~DMʨ*xbŻN҈.(7ŮL"< } de5W2YKB3? zgZExWJ>6Q%%-Л4Y(&%7LLxꛒ:47 up#Q" k8Tb yGF8Dzc yكud#C]qAݑӼ[ٿh8p4@=ƿ~n-hTX.|WHW"3<DrGTb$Ճ[{J!yu1d[ܷvd! 9gG3HUPթBBY!8s_^tA0[TҸCrfyO,S|gjP0Za{:Fh>O9UʳKL'9LU /Ozn)-kh4aؔsޓpZFoE\6/KHVsLe3r2FHy $m PpGt'2?O#%<(-8ڮ8{p$z?î ` \\p\0 ǁN#i P"Zg>2xo*gAQ]s=p^6>'SW`G$ C>9Jhfwk1pxV?.s7XЪ<'tEt;lC=P4M3/!Ҍ]iq44v,X-y[. Հ,E.gDu"'Ga|0ׄÊDR‘`jx7c$ P69Ay\eBnYc4&l9-ܓ-B巉'>E~NMܘ~%ߕN}"&$iMhÀp8Đ蛓bvfYsL_!.חc@rx~C7g |8egp:(Z?*EI:{#A>KT "7[=RT czQ6xyI:YF%ia+P1ۑV}QQ8 L_b~9OMxJ"׆HM lO^ >XwP~⣀`?׳Mq8=k f]yRf We0Fa8.Iị\,T^g*%M.Gzd!`f_(fF` Ѿ& Qpԭ ַx֚6˛B4"B.$ 2.͵ >:=֤`4"P;qx5ؽ6Lܔɘ"Xa i7,@@34{1 $BC0+Z)Ӝr# ()ABÑ4/33P';;l5}:;:$k ;(Cꏲ(A3i.BD iݧӳ +:,Ȏ0¹Š;  <dSU)S '3a„=+cC pd^= :c8$3΍*h$fSFyk)+YƸ& @s]K=KGj r>IF1rҀ"Ŕ6a"2ȠϥL࡙9Lk2<#Ca;} i:F ҙHA`5s Ҧ˥X06ءb*B7BD"B0@B9`09z"?zd\+s&\&ILѧ4}Jsi,y[1:H:DzC1;|?=D㮲|@D<şr}sL;& 5;1ɊֱaFB+#0ܴ+tӔBMb ~yxC\}* |RN9M$!4HOoN0Lx+7B+剻7ʈ[qK UipT&J*@* c ( PYMB axFK5Ѕ!, PHp $shAz 衦ɥ% R؋x 0ܙ`a8A\%Ԑ 8xH809$3rZlN<+$,+¹lse:1A52M!>8@(A'':&2B˲;$Ȩ5H;[(3-SC;L2Ԣ6QIeʼ͘B9 E,SmZ8u]"rvbuP*:ZJ[z`Vy8BC0̱:0L=;ԉ[!L1 7d#Џ&¼$UbVLvtN4"mlBےsـKJ 4ZpEWBPYF &蹵)IЂ@50)K^QaqAuJ\p BAx"aH(@%Q3505P"jm»rjZ&*K3+rB=iO1KLMHa*TD2@C<(2S"̑L(YIѝ3>q{OEdcS0q T(#`X$GD\ =A@܉du@l6d<̤9TFJ.MMTld;sl҃'@kҊ=Zb1b@ýjf㜳$#Pi辍Q_XJ0 YUy}˜&+"%,pYI0fx0Fuugfo-Zm^9`g^0΍@2?!'mLf3'"梡S8JuʼRMlb0vs 8_CpS9(pdb&ZKġgWg R f>0g[82Zea x;і^)f/0)l@!>7kB.v"nurF3O``GVYWbGfb}SDB-0Kf (E f aq|e/:*j.0-{^"$]sBF_E$l9FuHg^KqxS3tհR.Bj._¼@~5WSKO"ơ&L+gn!R"i!+͘p^ -洏po5QP"(n{,=5>MYCQsV1F2gD5CET߶\z^Ė?7W6;CPxH_!c8V·X?$7>WI]lMKBc_8H]xX!ʻ`![ԯR +WqGX*F^֙u byk=$=_C C $?bhA|EH4eDbq#Ԃ!bwL:'BNw@O$+:C$@$P1Y2E:CKbʳWrsmƋuФ*f΍3ZmZUJ1@Ϙi݋tvCx5«C6_og⶘|"Tm)c+>bIeJϬm{3{ .A&9[q\k;rÜ4qD6]9VL='sznv1wӥ9yGW^zYŽg>UIh"EY[GkR?th=M2ՙdfʁ:H^Q!a4i.xABCTt7P?5@>,H-D?ۼ ͚Iښ*Eθ P^D8KcakNi^a͔5fNj%Ŕ6 MU|j.,V:cQ 5 s,iG-XidEQR((YaQp-&ݘV t)f 9n$I.ZÔpRʍR` 2+ ,[&*P&`0t`,'Nihbnp?'ϞN tT!O{A M8tn $ɞF6pt6GbgSBͱcW*%\T\~䱮u*"6i$mPJʨ}wtBG >MO3 5#f bY5_! j \J?]:_N^Oδ%ļF Rj 54  %Ղ&MYKbbQX[kj-xIDQBȴh",J{Z'`'m"ObQHQk9*rTVFDe\bUiM2OWM?ҘF2%H5v a *'oYMVF")6.mUYd!*iu-ضpV(XQ1&D"' Lh vӡ`}CsT-`ov}4D\{~vv^po5`A ]ݢjdx;Y[+E۰-A<./.);A#<_)^XO7DGG}a) J1$,HmFdbEmf,F+`*@OXL2.JyJfvgs$JxA l/|L]&Q {jXUiЖF Cm>,ZFЊrEfЇ" - 6P ) k A+Dl )~%c)jf+Jg,R/߰\'0jp&4r%zPЁđ=o:XJQ >10U[FMkA6cȐZN130SF䫴1pkiI̚;.lc;GBntAɺ37<:^#֚l.J3@H|!AE@ROBJ(+^/-+-#)s.ra@᐀Ke%/ 6}Fre`Rw-D4nXGrPT27cX* z0-BR&]nz*>Mn7}KrS6ՠ75236T: XŐ߱ tI* 0 <3/t gpKo#<s@Phg3#;osr5\9]sp[䚯IUl\F9̷_3?v@1ThFR_ #6ZgjɆ"c+ dO0(N\1c<,+X{K@OhMgԞ-¨Q<(7$M`;(CNևj*V2nSa-v4jR N=H IF+xS,#*T{eS$M%:>P%һ."C-2>R?Xt?1X,Cv3H-bvϳ1jfTvjPe3WW[z:Ouwno]C4pz2;ZqQL3T.rڴ.vፖ4+"B-i/Xޱt3rytF8S7+z |XdJfߨ3Ȋ.5ȕ$YfUdn.jr{>$37qd>q;u]Ѧ<{m={{Y0{w`ɨ7lu1;nMh(UwK+BCI<W{tU?Wm+,KrݡXj]11,SHވ 3ߥ+U1SdVxzJˬJuJ3PH=N>߹(0*ǗVY:7WWzzw4XO[֥qo/rE<~AHQB4']!a*çwON0LKo r.7N#)p{-?++Ld kڲ+*N%XK"+ڻJw6[H kd咖VCx$m/ռO$9 twA =d7&ϺyŻ]aiڵ} =CpNTcH!- nN1>S:0K"L9ex ~"Y$PH*a+KkAS+dH6#4v"Kj?4=.q.q,$WN$=3OpLCQKyMWtF+@1A!YݮA9˜I-+ n=)r)pk XЀê.u=)nvvdһ-.HcSeZeS1{'03 :/00k-/jvH򞱱siC?=st`^̆Fٻw=9۟WuAL#RXO.#/UwQ ?ǩVVE5wnU=FRڭRr1QE4N-vF$BT?W/s]Z?QA ddN?Na&H/,e?S h]?  U]4?5)lthf'Ȗln$'?C YLPJN f54*l1χ#?EGp@=W8?\Mt.];g}?^W?zt 4[9t*ȋ;HZ 1%A0, A]D&p+ aACaFJDaűH+Ko0mBt?y!4_lsGb(JLr2K$Er#LsTQAF2O*Jg@1Q4-@' HQU޶kl 438k:m=åۤY4C:S89Q{1B×@8d8Q”*sK11GC+T1k9B+j@<CvJ,4x,!B =B'2;., 0(I,Qh\{>P=S?KplZļ3"GD2Ͽ*#E Ʉs0==E{#V9Di 7J*kbr+4+E6 ?Rf6B`+lwv2d(I/Il3>ŤyK=4HWK\24yĊȫ#ܑ>EBǫ1rpIJX:l}1jRA+tWBMc(;o6TU#Bʙ~|GJ$D|IxhNP<+iıHd]+;0;ńp𿚧jDz'dd$eFħ J̓L0 =,۬:k/K4KLN) v+MN1i;-4I!|^$^BUP[4l<`2J{OM2K4IrN>4Y+iCu3/.GL=̉MC:DCaQ˱Z9&Բ:#APL?C;94"#LrآEH˔-gC|U:A]U$8`QE$?bV0UdaVd|d'Tr5d#%3ESrd;ȄO##R X^W{aDuVO3C\R xnuMDID}wMUӅ$15Y )S!1DŽE)У'e4ID5OQME)ݡOPC#4yȫVZ:qWǝw@3_5I+ʼ3CeKL7 2p*E+OJ>5I' BvVՐ M:,)7JF(س'(bV'ԁ?UܤUX9=Us9$L<;=˼.֕ٔS.U1Z.bDƔquE=dVU} E@f]f_ >"рzZ0bNzEYI@l/D4_*+AU]* ̈́cJϡ:ȋ=mE|r0\%WQPDoY,|U>̓eLX4LYEnVWwZ4)byuDy>mSFYOSD2O2ڏ >4;WKJ=jK3 #G%t͆ WpV7D{޺޽Ğ4*K3ԗ'qz"ڀ AM=RGږCœ]eO̮[I.-BZ3X*VUmTÙeԡC]\U' ?cfcW}`]fo|Րt!"V{N,v~'- 'έe:-wN-42Я4-t,"=L((|W dY:\{4Y-m*\4]mPDN Ŗ #e>Ek4:<\OD<Ԏ\_׮hmަW|^fJ"\E~I.m޾F)maj4?}6rE-' 9:OVťw5EI4/'dY/OU4'f,|&ɼYX:/50 ohF=amQ?,ŀao.UID'bvrv<|P34>4MՏœʼU4UΜUke4P4SC/XNS/2̨' |D+`,@غL+4m4œ4X4|sٴyٳB\'! OD/?jD_cOuw?Ӓ7LA_dZ?7m5gO$?t7V"Pt5OOV\OevWlOmSeNknW32M4đW87# ZBeUA?9=9|9 Ejp(FO%kQ[})BduJ۫A:_׏R]:[O/ =OQqV?˿7/_+ @?C  ,LdvOBSؑC^Hcwc9-# }*;1{y0@V_!,)lp"CK & Jue}Eُ witť\(@QMj-h7NNynOvhops6a9o\tdC3 &CSR̓n :9GRs~49s7BܢԱ R=T?g_O> yPptT;7\~|gqSjeU'K1.l;0M6A/*mWnxʪXrԄ#%$ ,"U6%0Mq+݌V% gՂV  (C49#'U gB^yo}Lk?fl-а 7Np->vuw jC<^zX #!Q X`6J5el,lUݺE lq#ɺ(DiUt)KT"n-[~1ceƙ<.!}(09@ Ste&snfgxnRۭw(!;7SCo2jD&(O;$w`#^S0&5^:KuκrUqꆡ;x o%2BV:h˦DRNI"("־ .\͜QpF­_S6"'_T;zm"6ޱ)Zuv`q~-[$W\+QxW|dJ2'R@C_q-TtK PnD2[x[]!p9R`?ůAY9Yf:˷SɲΜ?wQ8VW=[b_q\}nw#f񙾪†U'{e3 ^'8;3}Hm70mnzټ7F(e[80|Z~a|'s t(- !_d|.& "w̩oTCQn4g 6cN,2LJ80 j:8gSFu,D4sf^{)0ftiP482+Ï>b}Ȝ~b38(f.mINQ:H ܯP Ba#ܭ#)"2CdBP PEErJ2&NjM8%J@.tiGbq]J?CN" 8zi.!ﺓ,\)c|t1KzAL!L@DH Jy TNbg UuCP "OmP.(,. YR *5=1q 2T+l8|u' (11i)jmJF5G0S. s + 1tq$NNuuN,tj4s3'=XSdq9FsSU[o@3'582%Kgs;cSB7<͂T9GO>:6j,mHGh>*ʠ}ϠmFid@H┘8usW4u6tgGgX0 ~ \vszאk 2 ~~(0*+`_V*uZG*fb pNe2R J

 [ qO[Z?dž 7OH#fNw&,g?v;(8 ;Yol8 uBƪ(/,yf &R(K,UZKR$4Z(ye-n)eoCRQv7gM[EIBbãp6IbyI~ \.iw X·pɮrڬ+HxZrHmGg~^sσ e a Z๲UAe!lgEULs01Sq?Kttl}qH4&} zu'WY>#Y|kksJ$Iltճn, y6 7slk:6,ɗXYO22զqfsG0u789W93\:gO8)Ca_ C9C_SfyCkt‚YxDxk~|5ImGbǦQ&Z&PDSĈ %Hx QW#zYE8{D-dZ D%OC &P3 Qf*Fj'Abiej&*H nr,,㕶N8fjOEz#pWzW*Ȼ20L~&zդ[0֚1sΤifxiu5Sz'"̄4ӣudžmXdyrl\:O#s^nS^+̤5LgBz{G(rl#g4tc};2SٙU\%GG[Gz$|Ýi1~ G.Cgv[*v -;ù>hf9CStoe(ò4ڜfдe)c&ژ}2!#l*g-9̬Aw- u(+tb9!xOshBqFb;L 4|0sU2!<״[>12pjG4;u#gR8YeUys&lN Ʊz}*+87=65fӢ8=FgF4/;[Æ9]G \5#:2E\~:xU7gwu۟x1]F8`;,o* fLg f"bz"RMXk ^LE܈T+~؃f*䣈2cco^ .AS M?8:Y%%II$)5g8(xE)--i?^aUmm?6ZJY{Sm-6?w*<^xTc<38[meu}NdXMX/ OD+qHktZ9+LEb&8R|oSԦzb -:A01!6DBg&D2@4γ=D(D6$ҵEd 7y?.8@G$Hԏ&HR p'HK|A[lG|0K.LJ6j%:Ӻ!;6npKOΒ$OT ⻴<4a>QhPgOKI%2#Q/kSRueH]bV]W5b>W0($mg[]jEյqa0`Xwp]YWUh6-Y]VEZ G}VE `g5a8zDR:@'Ao&A>JyA#eg.KQԀ r_gǡ*ˣaxj2ZeF3\DτΫBw_ lg{JaWmlfXn{~ϖj^o{5EW{ݾ;3;Xb)s45NlG㏼JN67bı̃uZͿ1j;2+\t.)|Tx*/{kQC;R,rt;'҄iͼC5x+o6Χ2ŋmM>Y:0<((ҎO9B,&UfW*S_s\ˑS ֒[P-y$R"hz+" X_5Y&-xWpBJS i8?ls;A#q码A Sm1HqPl`duK1>ǁuU(dě#յ6*["H+u> DBl*_/"?U xtKH 49Qom dەf[Fk1Cj}ND+B!Π= y5h)x"ۻ,$JUK g +赌"ה:,"8r-hQB XQFgL~Rni9IiK)?na%rWEO% SR\mF%U;R%U;MCa ᪻Y^ad9YQG[+4aJe#HdV̱D(eһVB6ҵKbF[ ʠr+CVLaVP0ndcd}4  @?`IKa6G=vG LpR?6C,8P׶p|SmmMuF wm "`v) M5:&' &[7f"vU:~ӒMuΨDK'Zm>b{Gtc+QaSpmw:,>%R>r HGyl1]]6}&SD=ITΟ|LCI#JmK)cs 9tjdQ:>JwN}5@"p-R X5,`!#UΧ| Ul ImXlC:ofTM/]ċ-g6\w@ --Z5jkh)jڊ4BNԉn.k >;Knu=?_{L)*ecwm܎J8~}-Ա }1/0-hi /;{Ӡzj48: )<-L*84 :a§Y+0Xc:bʈ'!/Ҩе!F˷z q( "q;۳#8$Jқ<A+*қ<}:z4Z9xcEE Yб*zDY k05ƋAq,#&>\UZsFs]!?WyV)l-xC s382'H.+½B#oD.t!$9 dI,cT@aΜ>|?gPA4.jXEˌP1*2;͈ٔ. +C96dF0I2TU!RS'F9F+@J=mbr9P+,O-*363RYy%lҐAκRJ+؊M°|\).= ^ Q%I)x8[>0"n\!#>hG lO| e#,>ƕ|ྶv-ck!NiZAdfm1ą3H`Pʚ麐ﰑ:,$G񁌐cW ?B ѩ7`du]ĤyƜzj3iC3/"NtpҨ, %jBuL%@4s#9B !.BD:DW4[D8,ZZY$òp{8WCkYґ sųLԑ/Dy5Uy.m] u- yO\d5zϒ%!Ės-_qDZ-p-Ö-Ҩ/=DH5͕&H"L I͛ YHɘdjZp&qٙB3IV )P8(I2@Z=xX7. 9ȴ1SPTL Y³ͽf0: S>1Ln(MEsK<+j;0;hj'[;د͐ [D;T<1\P!q$3)a[<4%S( +Eݹ-5d_N9 edI+ j0OS)-e02O=!9h׼uU]} 3mUE7H;WY GWPZ=d^܌R7{AUX1St}G ?p `+͙aszUzN$XEh.Z-&zhѨ BDӠ3me5Hb^RNEC uE5CU&:NCm#\0:;PLr܊30Ժw^"2%M1) *ELSE ƒՒ]_ͭU66:NM/j YTc4!)aTd,,_il_K[_$Fi6gPkX5ؑPXZsXCz`-6cll6VoV#"m>bZH5恛ئfR?E( !F(I Y}("A@$(RvY3!jj^@Ӊ;Cç. [®ic&;Ӄ Aq6ˮ 66#0ۯS!LcHjcUd^FP,19ա,P'ْG<>Lչ*yk#\Leo lnhK ibZEdW~C&qkqktMVSP|9ֶUM\2CjEe· 5cl }M>+uPm`k,&xt~h.vn|YfDqDx`%H&sda~>U 2o ,5}`sW+y&ߑWM#aM!!v7 p:_Zk (_ 68"#1Y(-v5*Au"@"*w^lbDMC 'i}6WNX[F>Y˗g j:K!b7ڧ*q1skgLnLY ]_ҩP&MrO <*y1$(3)בj3:1^.C&Rl0/+FT^[ +(`!xC C$x<&.qE! Q*@K_L!#k+@|rdSd]%?Tj%?Uw>Fk5Bl:M#v6^V}WIYlOJapl*Q?^7VKVOEX9FcMCF?w'ujׁ=lA@Suu/v3<>ϟ ?;_o'B G3pYA$ O~̓d/+РY9n#hQ9đ|H$HO9Jr(LR,Dx!LG2Y3$` ;B4SNPL&ϒ̋(k+E44=O1"RE*.;L0 0-K)$ZR,Zg1ZI\xRV SҜ\QfK/+ 0 F[F[7 D\ B(W1rv&{If~ߩJ{_j"`$|84|(jx*4e1G@ӫHŰӫ>-*1Q+ GzC?=|G7!3֕ ښT+>cTUUNfRT/N JWP*V tCN•"K^cDmEȶ"䂰(@;a %u:X~ $LE K tRaDц"<4.F4Z*SPF@^XQ{an raʃ\8rM:sxti7'k %T[N?Œlmc qD(& 2۸Ӱ$mfxMѕ ]_AB8XQ[[yRJcM&dЯK)UjXg*_OQ UE0ϘB&P* Gš.@U` \5oæ7$B&/"y*b,0e>$̈́ŒbKb5Ȑ.E1VS2/*VgT@K!x~)ꏳeM)4߆5MPpS laC >E)ߒ-PiU+0KX3jXi*hg-K|E "YyR*bJs-kX+Vt+MyreBW#dmCҤTNz]VlBcI WXJ upGjY)bQF[,B,"ظV*0__=t?Hoϰ=7k#ݓoKn'IoɯD2Vkt=Y݋wd`"M`OxK niylʬsfTT>/[7+oj8r+| ߔL/]xHoL2&}~L>vjawS%Fcm9*6db_P3d:ptQUrJY|eEVJuXA[;J EsyQz`~lUJY=$Jaղ-,4]TWaf*25k0Bz` ?:[5kۛc_ÍfG$U+lp#(|Òx]وݜRޙ#b'mM'#mpN: Gn6`gNk &Dz``@^$xt0B;^CoG`N:/=)"0jBbF(Z”Lvlzh cPC<-I ԯh-`S nC ~4 ro nk/ޒ#ҷ vߣƖmoDr:$Hd{@~_8Ypô{R=omz:I6i'"^`NAA,l*+dH2 kw,tF SRܣZ0rQngzxɑn\e.)Oh-M04|.t*!&7R̩ N¨ ܩ K)Jv#f/HSw*be*/(|\"E b61"uNJ"_3uI?3"t]CHQC,$ TlNdv "G`;tk Ӓ=W, ㊔ϺC"g9Od, <9^0*9k c;iâBj-\$KYt-7vkA>lNO}a zDKEYb .Y墣gnPzSTd0|PRn+2FҪI56_Ge.vge%ܩPJ6~,0 *)F4cN/\Vj+eiSVFa.U1*- 26'UPo=mȻ2nd,HRGSedS#)Rjd]3 SnSB6S Q a|ygEBҼn^ BXd5Ⱥuz٣X=19{I"Kcc\ѸG;DkՎ>HNfDFUwx:K׮!t`#X{UN#DdJҞ N N&KHv^DA. &@6Usn%dQs]6,qGS_E/ ̰LsEeܱ)H+ϢAE,A, ( gEW-^%GD+h\#^6 vȾVm "F+2q:_O6Qs#mf)8LLNcH(ȂQzgS.cjF0/HB*n-N1nN↜ bX:_yuv7\k YuzDY>C#DO:Y9G`DS:Z B#uEeY>7W$9w͓p?9WZ7 6O޶GC Lz.^t[_U٦WBkk͎XDrN clp~Sn`Qp#/)kEΨ,E*wU#h+ETXJi6XAAAAe;/ \76Pz;u1J&&8(O,'li%O?1GnXhcE`+T0tcBp~QsSqƷoLRAdOsE;KIYWk:7wtum:xEODEI:ؔd{D6,ZyB!D[ 8o޻[5{WG{#o5 ;ɣ)]K:GN{LNP6L$L@ޒkӛ׶wMwTG'VC^Qf'tfVۙ.Pl1)4e c;iGZD-֝.*F.#]E0J4Y7So)l QM/,㻔/2N1bJ$غ&(%O9PZ}Zz|1D]XfUmG6"6OַW(25 B /e;It$\Lyi??;3]wuw9i7nKiuޜ/7g`Cp=,N 6 &O_Z[y}w;={ku?lCCp&7^Rb `ћWה= ]*v Kk; `a`} -g)NH-WepЬ\C6fXok،&#lDb`۫n.Es%k:^/!Nh1t$'Pbc5nZ{a@][(306A(ڛTC1UGW/U^ GsCdwa7U;;>]^QWTwfId>Kz `7lk;>sE]VƼӸk>̺S7^^7C;T ~}ԸJV* ^P4  tCTi !yQ񃁈, v8O(g+e4Vt nlJ m@7m ?W*(, t* A pH\6(ädAʦ,^aSȬ+/L%0DN?@gLɩ#Ye})?¶[%Iim?wZd#/Y>U!4IPԩ.GX̰1^}H?[8UQ?`)M[_!ULӠ!t{}?^+J oJy?$dQLGB'"G@|@d1 d\G DO±1tFLf*G'\~&H7' &DRCJ?CTc#C)Rt'6LT7N3a8<*Jҩ &Ʉ%AT1A' AQt=4FD #IM/N ROQH>^UcYMTD1 #0uKrĵϣvYfbZ6Qb=hؓ/\ô],*ݩhʀw,ðHbz(Jn*b*J!*",) ~_z.塉f ;$c0:̪`փ8胘HX9\8 *ɛvz`chK$FW(zfj3ᾷ־;}v;q2n5Mp?!"'i+AN qL7h/hE/gV}jS+%Av=_ LcCD3sHdž6R/ȓ6E^WsoGWGkat}2\yϳB?gIBQW~y_SjPUZʝhy=6ӣBI+dVs)0B#Դ\`sИY s[ܠx??kC4ccYILNa 0W",HB6K &1xDb#l#$eciQ2Dhؼi#"O[ZPC H353fv7P هr:G$\$ N$QFX8ʓzoC K12x JF %(Qu0 3Gѹ?\pm띊zIN*#< MZ]@+E$rXPiѩ0^1&2"D 5 X(BqAp{'jpOIk )H*VS )V6&vJjS(\rIQvp?H龙+._˨YROAB9] =vTx/0YNi:O J Ε΃: jXb`1pE##{ yP%J F^%O?YIRPH@e!3m1X<0"NЄYD Shm,GF)CɁsRjL=҉l ҂DbJ}iyŴkÈerCQI!,_@b#auz%֎(ʿc]쀥粎eJQ5BI#=wDIko1'1,M$+_t| L%_a.A6hJi %d]IRUpJ~8 B?S`BE觢;CzU_[}-N9oCpcxf՘{J< .)@"vs{ z(,M %4&Ppk>ZK沽O@ SpmU.6J AҩIE)j"1j &NL-nXIRp Dj\4E)v# B#ɤ;MJ ZD<[y  Xb}߻:\C-sbXxإKhR㬺=>Z;ϘpH.F`TgQe;H27m9ks /7 ? BѡQm % ¨G,u '3 #3T1[CS, RAPU1 ̒C BIIG+Q0GBir˳$JED@3Cp=K6b9RDC7ãK24=T D$J"? <`Jbb$ ,2=r^ 

[4ˉ!T[ňCFpåJT)S3 q0Io**GQ k//Gdw +41ڿZN49#Ǵ0샺4 |jA*IEkBX2  9ɉ2T0Pԝd( oag %K)4dR$ГQ˔UJVLTD"ʛ Kp3Kd+Eʀzr+2QLYKLP+vM|K #H aŸS-ŸL 玌^TCPͨ;T]K;.*b0¹&ktFqΕI~\ :|YJA<,Ǚ:9^2\]h@jR@-5n,PCW42[7UU\*THTN *ƒjHO!ꈩ~ KDR3E!WIdD5 =&Y KeY0KD4|l䑊^1AmדؒmȱICTcEr Km5wcs;*wI0bg)Ƶ|:jQHQaw0|S=h8H˞,:7&h}CuK]ʒ_R%%C"""y@ʡı.-Qg~,b|R4%hq X8FoehRhzT@ө"fQU?)bU!cuO &W򦪌;IW[~f5bkפc\[cѧwvROi3@3V HI]||HPV ݴMoPY[ʜb@S'\d-jUnI̟i2P鏾axe,P0Q+5l5HKY{CKmE5QJ KmpvlF1RH  XpX 3Fbb fFyo06pom່0&X "8pCqzjEc;8u7їUB&^[qӅ<ڨ-q.FVjc;jj mlQH$ t)θ-O\XB1)e5Ւ.UOIi岥j1j*1~f2 =#|OFIȽp5m(ǒ뫤M&Q=bmw3޹Ƙ62cw 32 قuEg]H D[t$H?fF_Kf{Dl;AwL T"= ^+F305eaafiZɇhYcv@in}3M-&u-C= X}ӳblg(>Ġwp|+cz t~7TH/-~?EͺiϗQ1 @K{1$B!(PMO|?GD_舣QiFd(#'JR%-K)_2KsV}=(ORCe.SZ-HVaP3uJ?7B_;c#onV2/pE ?x;`x[Ebeq屘+=: sMbNo[iFa|k6-oyO7ۀ:O)?Ƚ?x_O%ۓ, -y>^fcO64 INA`B - 40nÐU4Tqil/ @|$a9**bM3)伭&K JjGˈ>˄y-*+ĺ%xbNNgH N jI,?KR=KT:sCˤ]%?"d. T SQIt=TD9CV YUfB%uZ }^!z@VMeY$bi֩jm!>۷-b5gV-GKܑsE-O!1PwҐM,3Rt6Ͳ;"H%@,8kpA= Lϰ1[T=FhFnȶNCϵmb58MΜظB [4gy2X瀹 g9nl{f]>@0˶^Sq njl!.˟w4<9O]/D])wu՟zWX6woݟ'| jQ9?/=v=T*JM|L-T dϿP"%IgPju~)~Iz/2T/b%䞉*T}QNUb C @] v?ֈСu, 0iCv2\뜂 BHR$Uy%옠~LaZ_сgRjXd0/yR4ɹPyioq@7vvan6h۵/!Oc;glCpڡhfŢҌa55#G&c:-MdIC%_<[_9Cۚ_>Qq%wa= E5nɐC9Q m0ٻQi=ПCyO:(w҂'qAHC !˻LPE|i{^*=&} aP>`J$m:RiCaȡ_9O6ž <֔$j JQXV}*EH5UԜ"Faj]A: 5i*zڵִ@J".RXkjXTR  ]Gi4 bfcK QV+L&>l؞؏/}[mYܸGR9Zo Aq 5ŹW$4֏%[).r[EoLȶ~[,%LYypNZdkö 7z u0z7WI8  ?N vc`6;,?.@?!< f"9g0f(.ԵF-N$0wjii%zLBmU3(u#:NM6PK1<U3J5T# A8'`*_:'VE FvP;W VR hb LZhκ EJKi-d4s!ؘuJj4GLѺ65z폷`<1(國bͻnm|8)nis7bNӑgzܹC߹WdmfYpW²,3 KrSnme95,>1f: -qQc\816@L?);!B ΁s z} ?I:g : =Oͬ"t;NoOKӴS҃MIe%LI֧_1.Z7&v̐Qx&,ΦLj$V oX EsՆֈm^o uօt5܄z䴳9nWnmSىyJ;T{8RW%G=Ch⼂?X*}ooaqއiK2d=lvg$7 '7H˵vHF2뮕,8oҿ-3.6U)+Toϼ@l9 U0V3@nh&@!pxD…a kp ap)P 0aм`Rd^ld`쐥¬.%d nh$M4LoʌS Sm"R` sqpm 6pfJnj2Mh PƀO5z#/!I2b9 ,C>n$fݍqF>͞M0qq'/Ҿbry0 (a ҍ(30 gx@)ҤNGZtgP+r2E\@k4pMAn`~*\iOD .{FPM$p'(oojn.s(mFOERhDh@%\ErWjЭ Y2YhWw{7(d Ÿ!j[%& &PK6Bjq1}20'M`δaE=SЎ 袩iNBf3C/.$-R oƞ8!oi"3Fr2f@k|k8=<5 Tc%&v3vpI~EfP篬o? va$`H N$2qډ2KnrwKDI 䞈461kJ@ G^O*a1`|()+Ӣ:n;^i&/ 331s&SJS4AT;51<,YUZޭpM UqV耉Qf$1^Ѕ30Ӗ{SYiPu;UPn'5A`k.*$]GsN}9 G&1iPff-O.ml+6#B(t( #DV$,!Op.8m~m/n/GbzS%+}$@:hy&x )Z !G |FDh}h5pDr hbig(Җ$mjVŶ?G 0@҆aM`{Oc+B{Q $ $J[$P$:Z$'.quSN3GRE#uJ"U@TO!Ute_q5vЬhQ4ZXh8S[\ZՃ8 %72#MVNҥ(wYפ*.pWьaK:J-^|(D<-d̜&ݍ`0.. 6b/04# ǘ/006Tcaw.k"BbဣpF <@ǖpFdQ%"hC xaL҃'f֖ {X|{0 `h瀫c;ࡊ!&aHBU,#vޫ od\G< ]i0tz<.31wo *fOwZmLZLO}W)1gSR/S:#w:Ȩ%,EttŁV3VXWoTfliwPqhu'ֱW qzh :~rB%rՌRH%KTEUHTJ,NuʯdYm7C7evEovׂWdlЊ O9Pٯ *qś-RJe<*6!O!r%=+HΣviH2H3ZN-Kt9 v2g6A' ?3KkZ d!M,'"ȻO9hcr!Q'6On۝սUbgn#f[gtn,eMs„ޘ.&N !8_3 \pGj*1jUc#48\ǯbyV[}U&(hӸ<'AY)œaSê(Ʒ6S1<6/ؐ m_IB$5"ډI!;mAm䖦xoy39 23Y NKVc3΍6\H EXÌpB?x X7<-;?q(EQ ?ŲX@i%5ny7K?tF(tT-SiT*sTPZdraجk?ezB&D'^) >+;(ȣ,9?Z<u}NDk>Cvmtx !>W'qyH7 ?݄n]0y?{}c{j2LiL2t,JҷAiʱ B ˹;1L$g=E1Y9EOp*MFA$zFHgQ#td% iH J-K2!/Jg3,3aM8l:Nt t:,645ͳ5 D GN9t%Etp9ҳm$ QR TBUr$YEj r`{9ALԳ)6S9tgYiV5Ck4ؑ#gqaQ҅!7g]{%ih}}w7Hx%{YvIBTz_b)IClG:Ydj9njёYt1lД0䲦pz)6BZ+r /3 P@,ݺF3KMkYm}7 ۀBۜN*_pσ/<=B^3{wXhr _AtBYGvef~K_u`:Q)'䦠Xj|FLi0?<bGMqaQ# rSJ->,Hh!"q"qOKx15]G*Eqc|c# FtКa,X2a}12?88 puQ-#yPD6PIH,vk,NP18'M%8L'~M![e ҔVQ[gəVDkfmL>hYnIѹ7g8[9p8LC=`v㈜|Y5 .p_S*%= t%)['HI 7D]O,ʐveNR1R:HI[-f-ЋLU 1&DR_QrÈn:LC,[XT5ߺ[XjyPHj Br' L`V"lN0ZG@(&EA}sڻB :Que) 6[WQ$sYUҭ# YM #5# Z r- H[ Uc VdАmY6vas3s#YQYٛ;jE2[40 KM,LRr-l_iL%n`6Zl}Й+26vhi۰53^ku&oI#z).s˥B35lb7M<]Ε(D;|jm+ eCulf- zp8Thf$2#A3|S#ToWVzԒzR pv-Ʊ@(U$͑%وYY<˙Þ0h^A}6nAXWzBCjA9"VX`ռGw{G`? W <^ 3uA # 4r6}*G[Lϖ |uC ^{hR!  )tM-(H`9V H=6ۅ: MoqŞK\E<ɁΝ8,\x˚2Yn^RcrzTxQ~J) tٙnʈ! 3bxe?0YlŤy=eZq!ҏ](e%TӕV'jIÚtƘk@ @+D c~:AA8~\g_M ֏\bOBG/RQMO4}< -b{{} $,ل-r5!+@ZìI53Qw&\-̛̇Q̵02AkY&ؿ) x.&8ثT/RK ]%9'2` +0ZeћRjBt0:lqSCJrZz1+:9:;C:'j0R~BsBh/*/c ;D{눐KDG<e851$ ?ǂ/|.>7Nz3-7$QyZ=̐~XkFCIJ2 Ԝ-v:Y0Ģ"zɿS &&29D jdE%P0%X'a Ѳ8ʮ띹h/&B10ۛ04CXChqCq:C:' ĺp;0Q /ЦJ aJ Fa-/D2N;!lx4O%ش=4)P@$y#>6)YzQZ+XPy܇HțpŢ\c;,8zQj az,Jxo@ xQKDmSm+2iAD {0"S%4@|-&\?ܵ;sM> 2".뢖j,t9DZL ñY:Ԉ麀t>̈ hZ[̊򍻉 ((PZDM22ۈJDQi +-9),Hem(N/VQAj+dpGP5и1zT[@@ @FyZ6Nd{$$cΡ@F1=4gO4]XMN `9Vq3 K4a66׺="T6(u>HdzSXttE7G[tJȻ-,m $x5p-2QRⳍ '7U#8ZmP7ҖTe'ÉC% A 8G[$ \ʊ XT۽6( @S%0@K Ӛf|.KuܘԛB3El\KT] ñCCqBqYs$\ ["]FDPE\}`e<Z'Tԑ⸉ /2-҅ffSk3-{-kh8*+5IEϩIO\e} "?+}%FJיHfP,Pk`hHºrQ_<k۠!a rڂح+VzF/[a(8.ȃI-ǃ}UđNjOϫ}MrP`AQ+dbx-k0XX25[$հS_)/L؟_,)d%c15 *݉"T00C˰Ѿ zF']uO]1zxXQ;7P'GGƋucT%ʜ]˺(N^cEV9ג [5b25)*M^*a~oVenj5 r"R ņPuX)a*i!I_]`W2_AGgWI6+!4nڝI.,-Fzߝp8R $plY03&v"M@ȓ@MٵHѭ+I"#7e#34p^ުlҰVhjs3pXc,bkfKlGbvpMd JB4F=ͤcu717᳛r|V 0#TA'GcLD9]KH[~B\%f6mEWd[Vpf3Ma晘y,m^ZɤĩUfFM3Ro,((!c`Zۤ4 _eWQQ u5v>$JCY(>lYNu!%by)"\^W o8 )ږ>Xqr6b8/loGBl7|jS ȞrY ŵǟ^v8qL;dܜ|\ujHf%n-4(nJ'A c… E_1B=C\ETI."z=?sm@?\7 2"Y()-czh9Uju(1^M$GSYX09sD>{Nl6HA&e=B /DҌ2Gd0HtN1e.T\NLL-yld=C]Su]]GUn^n! \ہMRmfSǩ+f' W8hdIQλHp;ғ"?"CF 33r $VopG)hugiQOo%p,~Ux&~' %w?0$_(5DJDI_C1+%d?3wVt_9CC&$E?5wjXW_{%c  F[_kksn=?WgJ_lE;`=.Lep8;k.eX|N 9Φ29 WM?Қ;wCuyۤx|}G򹼞cөmΪ5?WK}#C_?܆?o? @J+!A@BP&? PL,?7 Cp/?$ sEqf,$Qs\H-’,ҳrsZ52ƳDܰܵ,g901̨K0a?66A:Γ-E8IBQ->S2N@/EU(҅QE1:SP5H%}QQԵ@zB@Veq[5JVH`@ev=dW%z uZGY YUZ [֥Y; Y&x%"UDOMl9aGy 3b׌Ӵ!GӐi&98Gcă`ahygXgNiX0'fz{DΌ T8޸lOô$Y+Z-QgQԪX'41FӲr01k?5M/ֳ$l# ͵3̄Ir;l9.շۣ8lJFn;\b<>>OžB4CBG{6QC#{p۩x.;GCiǑ"~a, _J& \ rj9+8)zR 1L/i 7A)adQnM<ֽ. X,ժUpz 58l<`(5XW7@,Dj͉W c"] " (G4G-#4wXs]8NPYљ}EDJjO \F#xo3O,E]K AP {ϡ 4K)=ԌD(k8?Q~W&dT>$d 09*֔Ūc$M9ӍTk:3SB`<ŀ00F,`0~ґe5} bGpb`&)[8pLWm)ol-pJvvP <<^$?.pNبݤ@k`o"NT-``yx/%5ܮ}I`/M?wE_LXAqzKe,4I7}hB#a8X5 bB"\4%ě̂UuWP brjDNP_NY7cϔI̎; "J&Nl!J1mtI评,rMhTzPE ԃ4M[!Ա .nLoF f%sg$A5!((oSC>ki+ N k)'͜tDc` )*`* ĐI^!`䤣mjD!r ` NwB~蠜qB( SP!f^0 /pt.ak2lg3B4>R2,0 1d43Nt3v3z䦟D23tqPG 8$~#p`Fj *: }m:)g >,<#yǾGC./~jw$HDNy*FFj\j&F99w~If>93r 4@2g>toBS4n4#Ǥ0*IrlNn= 0ք"! SR! !eq44l58x tHM-aiI BZSAcIԃ .RG!IhD*ҨVI 2t뮺T 'M2v€sx !B k2 sr=0Jpd{R&FKɖU: VTNt 1䭐+@%.g& rr iH ՇQ-֮6dE$KK,4}A898\g9Os9cvӡ]^]i$!+D D5>'3BqDDjFl-Ӭ;UtA7.0c1CB[q:ծ0qD6G1v|qN"SJEF4Ol!HU"XoKoTN}j4I5-nKDKH:SvjunʘH gaPZmLo0NKdmp Nw.i~&JG(.W*dFg/S9T|t5TS*O+uB*JTvJJֱ z @mrG2P ^vqP3D>L22Csoswe180]Fw9i9;F;n;wcBgܥJFz~y.q"=>0{&ûcu<Fi}\W~\_Co8CVG,LQgʅCZQVNiUhHT9Fe FH[1K^roSE4rtbFl+HJDm1ȍo6M +)o 03nںtt3:$f?,jD*v*U9S )Zpg@QT4H. !2T}x^,:(:y{ԄoJH.3g-HBO3i7BJ6}DJ!CDRhDzT,^3cc;xjG~xj\GT?ٜ~,2y2J2Ŀ{"'4mI65B*9N҃,NV"e{W$' ((\/NKE֐TXieKK Obqԅu)8YTVȊYV )'N+ʺ2 n ĞfDVo.f@dI9x8_m0nqXSஜ" JPy/2tOPzqrDJHT䶅hH/5fZdm/C?[# K6_d`GrJJFFy;; D6,zFgn7o]C'69$HJFKjQ-|hTL%\pPYiE#!!Ug k:*!!$M/!FUEZh$fS9'Nnes 0o(xd!V|Y {Z5- %mfVWnSzr}ⰨTK%-#8'% ^0k!]2P?0W:Ns_"^-F#!<Jed9s;1,B?sl>6bGRs1Qj:Ral?Ɩ?ikmy}`3W1n=\?W/06fLۡWWQR:`Pl?fA(k(w S_맹^7x)JRW~ _]~~AdH°,G' 1 FDlWCQYE)DљDG1ԓH@/M<*DFS4S{D?ɜI+M|ܵ*/ͳʏJyLE3TjOi$ sy8H=D Bju xnݩ>a2VPL;xR~hb앁WXۮ%*_'雦J]DW|G+wX\wE_T/gaee.&*X G6'eLu?tgbXyћFbkd G?$ġv T~Q})Gz `%8f^Kh4 $^ׁ13&a1\sJLD ZO#W2ۙt'jCmvڹhuh:W^ݩwjuO'T'z 7Q<:a ('A E1=diE{8Yh)|A4ߔJGw4<@ɕ=-Cj@*;guUHT5:xT}\յy9Xny~V[<8&ȸr`+wօĻc`~V[]4 +lZ\}Y+ fWIGḪ[e݆Mhȭ[Av;&eGW'G`h&RWp9U^_sK[je\9ژ:xvª;ڮ#|Lvj><4q\ M!tg;DNQ>GLA=iWnR߇Sy7%dM@Cr\,ÇED3<p7;>K䶓i6K6rLa6Kr>>Ɉb;@iᕒ9;9B{9H1d(Bˢ( )2&!q+))=BI-dT*)5K2T"1 1A,c1T\$ *yR 70D!K!L<EsGelPYhDZaG@=)xGas<+lĖ1v&au+¼5̩ـ̓cۭcYFci..##=EZM`La_3-j\(=7'СH Xܹb)L0Ĺh)mtȷH̗>D@|A{CUڝRCs9!NCJJ(B9 ADA(- IB޲3P',&:ө)1I%2 JLJqJJ4ZQF H TΕ'۽t "%(0˴qq4Cq"IgzD իc%+N3Q)uDL9yx="A>Kd=FrJ>ȡ#ɓ><Ԑu[i.܉\h fBc_T۴[>Kss</q~R` hBpsYjE= ƦcC̱YϫE8Cr4%J+ WW4QAuA19 eD ,RD$ԝeņQ݉}. QMP*SVۻ5!ָ,?IΖL>k3ڙ]H ż;d X%"S.,.r2q~$""aάSh-7`+6|}gc㴁ϭYnJAD9]p rVom;Q6MILPm~} "B|'\X5 W3 CزĩE*5Q}Y<Ϥ4,U.#:έ@ yE4HU9DU6.xiDDf̚~`1aRx.dC縣=C:KmذC5jO+ʣ6j̎׍XC׮O^TceɀޟM e1$^-u)I9ɟ6P) !DeDXE(1A4 7fi̴B9H1^Y|;`z`bL]lmr̽-NyVvM*23WYFB= =uFafFMin֌".G"=寉\%c. Z3rՎ. 6#i筝D!q ̖k]:q]sMcA_ -yWdk,P廣 ַ蜝):dSezQ;2FQ/d WIu?'Ѭ4WRcȵ&cf|:l8kc̷YG4ccW8qcU g\m獤`+S&_ q>J;d蹓fPb\fչL \aQV1h e8co؃oɸ1mκ2sƚc5tZ6AjN gWk]yϝjϝ&A 1'PaQPL}v^* X q]}4 ^VWII)K(/|&3QnNLewl,rjH=fjyFjý(@I_gds-)&go#Y< Kg;4۫S)17:ξN6cS-ϣ-k_7;׷NOs ]?S8W#/Soaaӽ5gdC@As'rBCqW_} wߍn]֑q%!/y׶P6_ݓ^ǁ:eki$q}OIA% ѭ ˖7H] K^ ~O#gF}cmt?(OA d)@R_ꈣGDQ Ri$fB? wmTV_깤kgO'?7:RhT@}5 ?:}DWA]uW+#gZ*`P o4B oU7_#XZOMdxL]G)r1mq[D  }5A5MTT>o>׮w`XZjYzi?9m9qO[Ou5F 8,38`y]54 YɆQQ=3UAmU td\O~Qp:x䴨E&R0K}4@s/Eh5QXg jipx#qgdЊ,)T!i?( Vb GPّæ2_4;ՋC?Yᮮd i\"Rb-+A˦.Q*h1Ps9EHK'jW/^HJ!g-@8Gj|qlFyc>z#QSRXǪ3'mN]'{C8dE7Lr@¸lk)99s4R|N'9z\ne;2it]MrMI Kd6\BO!ʡ^tJVOv$nFIP! zk;6!c4Mb'lU/-'Z3WZF' .2F0gx֚IJfWg9^1P?I(lr+COR(`IQVG\,rń4اXI}zZ&4(D8Tb-8j 3Û%v5Nab UfK Vx'אJîyc=4;O?e꟫Y})/Lq(9aoxH$ys.\N:;s-кWE2&k5~]tSUtw1)\D5D M戭C]ɽ/{-=՟guWjL ޘ;A`CΔgkG/@H6 EmJN6,lA_^]D$W KɮFBihtJ`,3zJA@C%u^"UDB0%CXG BOi៶^.EXQlu^fjt5Kv.~jAѸV6ikH=-hcfI5b֚<|B{:X¤SdIbT y[|Tȋ4S*Qw$/qI!)^=%w)U;ewu;<ܤWΉ.\DgQH{GBֽKonACnd{CXencN,l"$V4p 2 408!' 0C3lR 0^.f%gh Ⱥ"V"bJ܊ f^Fa pf XeZp0\%pr)nд8i8g &dϣ4\1IpF"LlRcJZ/D (8Lk ::$!c#m$Ui0'n @@@@H@/lOׄp|Kn fD&qOdf٤rmGNmvtg\Ͼ1oN$DOحRv/bG%N @AQ&:8ebPjp-0!R jg$f,O#X%(&3p&].^F43{/\ge&h$]eF"%#BB6C9"4bC) *⤢Sf[UC/4H8j !c J8$H"b0ig>>f6D 0982v,`%i'rw?Yng B[3pBRR>R$2N5</jF:BpV41"F)9Ejԯ\mt>fSc{'R%" qjQ# xJSd^إqOrpG˻izN6s2J3L$u/'{1E''1D[6OIkQnR1/?d-48VT62P+E9(!:l19#R, [JU4@S=;*r1#6R;oi(;(v.Edr&L]%C 4 + ]>(0Z0+O FEJY$41AÊtr?r`EDDznԐQOC p6!JE/K6+NoGrM=2iSJt e$dy'AMZIS6>O6& Of+UP)cH2Gc'4b 01S8nj 9p'F+ A$3CTCCΡѥ"\V=43D3X]%'Cb]%J2>%ivw3f(sr%"Nr!%DVH5Lm\Ð[>P+9i%_+58Qi`{48 M/+VNh6+}g-G zcxMGQN:rTtMXVgdTeevLJ—VYN){͌xdKI`g>g 7$֏ߤ)hBvvqvVk' VV1v=kUա&;NDLM os"i(is0b$5"S&h5UYr@&'jGp0$"6ؒ%Xc?b\%7$3RB6ÇcLB+&5ruWqMt"R+ljSl0V%@LBwW{_aiGWt@jR6iy~Pm0VIbIvocNJQH1}{1}Bs6DeLQrS|͸tiK$'5g654C/$?y9Ty@/aCQ$-`KjRZcvx)$V]*RO$2;֡xS'[t8|$'7:.%0Eˆ3V6ؚ4$#lv%A"krm(VpioV[uq:A֩ME-O]Qw`x hُOXR-zv7tGԶGj,JY>wߕMĂ<7Q{THO)a2qYrtM}Q`Q뮣֥:ݙtj=gj^C #6uK=QWDeJ֬Bj"" xo27eo?5xEclrztKh:N>ZQ5vϦ7k_B{[ZƿST/{P3sIWD33"GYlZAML=8K7ߪea}ѪG.fO3C0tE7Cޖ$99:B/wi%jT[F%4`k)l-3XL kuA]A SYV$Ѹ6Y&&adΓLr0?ۋΓf7w9Έ{GpەۙB_Z3vz;UŤs'T7V{6wzV:kwO]Hoai7me/Oa9Re nxؼ:02Y;dooO:Tde䲻)tIhG)^[9#aRYSYwjǽML-yܟ%8+\mON7+`#[`Σ?W\̙bjr2"6,5iO^ta5ܝ+ܟ_*n7l \\0s̘X3cW]X sc4cI}&џGz%~\%ϸc= ro /5rEBSC7y~ x-AgV "QEbdb7d BH$TW*Gɤyd5g9Ogs8FE*"&ChbZ/-?֛Eۭ҆q_;}5݂}PEa8tUNCd3]3fԖDmJ9ǣĮ)¢{HvmIwcMq܄-L}stS}>Q9NޗSO?}~?O<oQ?=QAgGA|Q$+ BYEA! PIK.!0;.sS<94OBm^ sW-j߷-sa"6 "յJ`35f3m&r˲œȪKnpl2 ]u0Ku]WrLus75'썮3 >a6<Хvue4>*X27ak{mWTKԯOcN o=TO;R;hdô#ujJ1%%Os7;l=McDPs|;lr|,LgE[̲EM~=P/!6ȳƿESO'GG9V꿹KRrc7mm_=c>(:ڪ>"rβͧ"2?m|_])W5ע_߭)_K*0$* =Q`S )`%J \,,kaXز7MѿW,*VLqYkeeU3=N3_ gUxϋL=#DSj M (F juEIY%$SfJ' eoEb>MI5'H*0-|WܒaHB8.^ER-AEQ$C hǍ;T2RE U8JWBB ^)W6XC^I]AFIVJY ɋ \(&lI~/`S+K?*qs! {~oN58*2MS*Dș/Q4QAcXQ`Bb% ҪTQwtpt3HY ։F+Pb#NCiK:8j  h>((fK.I<7[QwN'DR_qJ*ăM)*VI EUEH[Zs* DQ*K)G&J0SV`Ղ+i\qa*6ૺ+fS!Lټ{Bu w̑9HVI2Y@+ZO-2&hM)O0"y;,+XV տUy%п-1sbz@xls`puvn#IC͜6vXubGVӘ[44~8,M ; h*zdZT S,BD%zꇐU8T[- 6̔Y88U䢅uP!UȘ#濋S?GX{'(Z| v!8QKWITh QOdeYUٶY|-6n*-aôdRAi%,L&$ S(c1R2r' nX.%JxW>6ugѻvg%HP2Wj- 5֪{g S:3JGĪSK e:iHѹ/MN_ݍr*hp"w)VB)JFܥe3$t^#Dj&jTZ'"aJۊ:dA 8}P0$(Jֈgp+ˎ V 7fEcNB> _Iӥ;#i ȵD9IGY׷o`A&Yo\s.ݯcOs5ʯfaFR >2=k4a(w |nQ[qve* B N).,2UzmѼpcrW^?QF:7;dJ8W HzFq5TEC$#&W~6,O8xNQ=}*?jyc̚C^ X. <ÎR0K <:d(B -KC&`G54eYy;˶k.#VL5B.i.3SS4𰊐;Ɂ5㔑;:Ci{8<8a,O=CH{,v0p9C*=+aɨܕ,)h 2 Ѝ<&<4 &BXA[W:$.KQ'#MCN P !| T&Hu9n/&6e%B4hB A*0ܼ3TgUBM7##/㚰@)s$ؤ2SzE#?CDęF7D8+8 > )I:IÓ(It?ÓJ93%8}cDڱ?!?D[sJOwO{x2LlU=9LbS[%;#c,,bL<*LB_JQtycʹ@h 8$*'AG; ;SXGiTwA/-IL3F#Lid}z,s3d(WFҋ˲N}SӄHr0{10iKC9*41QQܸ=-H6_` kqKSeDTN=GZU{" e5^Zƪ}Npk![ j:2>E[:Zf-%ˆI}ڌ7Py@[nܕp ōe^f:Va-:tf" EXW&Ny-) E|bV8@rG+?,'V -Lyhj݉Sm lƆ}Kg.MnHm?I /=Vjhc1PXfAaM٬TM"UYŝ ZN[5Lo`~TD"O=PR)U[_voKՎNLeAΡCMdltHP!Β}t^bt" W@苯!b66<mRS՗6rym Dys߃3 sn%*54bN;'9.LYr#gg:^?>q,nnN,.4,U XpCJeHUĊڑH暔I7ČIe Dk3Ia6#L8 3)CFCUP|TT6= A[gNfQN@{#xsFGͼ\3Hc\l\)nhg1 >s ?0mvbw }8ss |x);=/m H6|:E{?6Eyui0FPOiEi񔡱O~{IDXYeŤ[g^UAwPVC_؄Ut'#Ȳ(EbdE*e\)L%QE,N%AQ*Z4MK9?zVy >њG78O2AdZơṆg怎:Lh -8g jdb,%# b1G c3IdœPEI@_(JIMTRQM? a$XLȡ A2X+Gؙ)5y7z$jTļ]?"jL%*S|)IJ*UP?UPIB%Hdϻ^hyETjLhQ}qFfO?4UNԧd{8$ffqJ; -F 5Ѥؖ%/G Ji:(]<(pԑ0Jy:;T>+Ne PH\(KcE0 )2vjS\MK~5r )_EƔ |keYB_5ZBτD@*UeEQf'X+d}[t/JHj%IdCW* icE80c^4Ǫ$j::G6d4~Ʋt1j/T2h =Fv21ȧ,(yI)sS`X#st9>ne"SuN{|$Ly'.zyzMn.:l>HLIHP3@A 7D I5Fq -b/Qbw䲆BdDd;ȤSX9Bd: (a$ȷBPOŒ|&1bmZPEPPtE:Gвd?*FiFHƤCvG*lC, lGfLDi&l#I<&4nH~7@(< 1L*3r 3>hajdý5 V45 ca.M۱,A `XNk. ':+GQgLdtCL:Xo&84/X:b /jg'MVeH%%%*CDvFQsd+`)aeFH27gDob KKRK,"b¦)&d%.CV a /p51#E#(7&Cd;8w$%#i.,8J99hi1leISspvGS2U%p '~DI@)nFT$ 7s{ $}hJ+P&b TΈsopt-2.0.0/images/cameraIP_Dirty.tiff000066400000000000000000002214241277570055300174710ustar00rootroot00000000000000II*" O?и< /N172-O|u{?ϲ7L0Jc^\2_I,VNc4BF 97G OP%?82 _+_OE$F 6,o.Oe0s?*p~S25-Fy8,fhlccL'sas]m7Cm۷c||p_$`njy[E)th.`K(eW/](9M5_"b\W_i8п `>)dcR>K%q+ץ080@G 0a!J0;Iu'숕)RY Nڊc<Č * sI(͇7 cbܠp1?O`=˰"R06Xq-QtPCJ1h@=0*,F.+X=C!0MH Jfc#d0:sSדȄ ؈CcY_х@V05Z`!k86,w \ʖJ0݊* 9 SH7_,^Θ H)ÃG5(0M- JӥdcԶT$YLt6$:X;f_v\Sd%t@i@Ԭ;.ބȗql+*yQiەtr4TcASM⒩ 4J?U{ EUH eJ2bt,_1RQTR(RRҡ+#"KbvI, LGwcƴ׵Ў?*L F_^HMMVF'L!*Yې6*ȖIHi8Y 8 Z%'G,EYSRI\G0YQ<0xnC_!,D0ǖ?_rҫaq݌|KyV+F?TTYSAWDPy wh||[W|%ŤD+ے̌Bb-2`M_35}h9iV7;C]Z-TS|v"@}5lOՒHƊ˪z? =xII*12|D-ĻU\|QoSFLi GYtx,pBQf*PBU7MN@X K0b#[sx}c,nY{*,u0e $i[NŅF@.#|,{Ᵹ!H"h|LHxc._c暩wKLI7R*~n )dc`@?zc sXQ=@?aECiWyE;7U_8 oB"~l 3F%is0!4gJIf/8SG{}Nh-/ oT羘zˎX(.Rzժ lW̰# fXŠ_-^Po& r|8ÐN!(^EY^C%|nK oA+ l.:*W0b~L$(t90e|B!((*xYLX#MֻmT*RN20jN!{~v0X fNlpNgƛ)wmNnܱ%P{- b:c* p.tiefPeLJY< ajp $E|uf{/0MM%zj+,A-O%116Ѕ,J%O&T:_0j(N d.NbU /4%)&BY !$&J(_%aMb F%TА|ZY6"0Ҁs(aҌ#u)"1oVTtI  k<#R s'0嘶ЅO+ne}4|Iwş*?OEO55=,3&O'0Xp\NXJ.̌ `;c&B91 4T\T".^f,nc9?!1HxKF2ܲtxupTιsm_>E}6T V,VClȍK`Hޱbjn[V.ii11"r2bXIBY$v4WHcv$ sjtVb 6G_0vܳ|`F$,n5ЃP{zW,EJw4b^XeFI?2 i>PkoOWj2t'h a-{?&(b?rY H5Gsx E1u.oM*Xt]lHVi" SKm. O'U_?3..A"rxIO(0f #k4lZhkY#"kݵSe&Ky3GFSK73m[ZDiOȦ*g^"c4rcC,B1P#ⴒ+)<0+$rx2"K ʉ8HH(h7$b|<=? ?#5#{> 4 .FXuk] zꂡ@n.mk5![CqʑAtͺLx#"G&QsQx F' "yuc62FNJl.SwN#1%eUBO=,T>$sCpde3Cյz>4i 9zs H& UDWX"(4ki ,O"JH>%y{ Dm*?ͼf*I*sCi#ug$}DslO=n㗃u1xjC 6:O  )hKr0UAZ_o=uUpGM(@eg@e #,Y`HжKo̥&DIr_0F]h0#A% G{CrFQ3lȸF M# ҼB<wq~3P$O2,F!u& 㥓y+.QH Gn#?p4 !) H33@ܝJ$v1= ;G;n\ˆArR %5:čsL9Fc$T0U֨WGH:4u)3Lx}3Ge3u:$^ Ի9?P*{, G(B^9Z$p:r>hS^Dy/޼i",e 1HGǤxrF4iU4t2HJTԃSCH0EpL1ۛe6`b8eE[(# ?wɚB %{>;1QX;ڷ\iCQȃ6D/ R ;\| ȑ DN-B#R?cXF菄{0mHIOXh[#dZB6$u#[`G,ը6A$r ZX`0B>4\G;] u^ i mҀ!Iw]SiqT7̎DFϪ=}j>G)1Zh@sդLm&ȊB\#;y׼u8'ǦZDJ3C_I? rU ξ՘ńG~,GBG0n(;xd$MziɎf?ꮡ{oM Gt ٦C"=l=5_c ki@4@I ۾RFu#@&AuQ`H9R"m$z/\+#LR`0كďLiSS&RsnŇ6HR2xїomMBoSb8p%$)GpxB@ 1H)@5zcrqͯM 91i<7L2jXጊ@^b@H;sbi6fGV[BH6aCtDD4 u9i C${Ԏ4Q 2@}9> ppDS{^]d ^r}@؇i׀$cI4Vc[Qpc8d%eeɦγ_}~)^3|w{"0֬^#zĮ@yQi~b y~څ#yzA 3~Q $::;*99%q؜-(A3"9сq(@1#A3j;뫌1{+'$'$x;H)PTSaB.RD@Sc$KB9s5:il0۟5P ZIẗ3V q2:p :JcRʍ`T@ gC*O9& A;p %@˩>z@#,pҭ-:8:ΝAҤ2ڭAq"9AQ& :sI;و4Q@%`!^0#9+='('!AMc;ҭAX: ).8":yk2#PP횡FQxGM(dĎ2Ui<6P'i1 O u&!E>*Al/>,;&)"<"@$V܉%9?ডDH 0k=NKܮq $LQ1zD5PHЏpIR<22R.c9B(3Ѩ-R O@II.Ք3CbOQ N"L:)1IY9P~V:86IPn;ȏR"U @k=& ͏:kR@"#ώ!):A}gtX8e<"zЁŀ۶C1BN*@V[91r J Uwzj>Z a$V+o!홝pT9 BA(l(ڈ4 4L$OrSgm t3NP%4T8ԛ^E(c"yť `ܓ_} SUOx@D%몢{(E`9{8P%0<7NA<4`չ^cC!v>h itu Mp[PxfLե f Fޞ=A"=<{g{4|([{%2#k˨E#>W=ӭ)E#z`ײD:12A4"==-I8'4q䎲6$9!2>/{a z.=BDc߈ܑg |g>YbZ PTQ8ҳE.T{Q­@Qlb!sD>i  X͚*׉^ Rzug :eV:9=pr/IMSOepiqv^wb@4>OuBD>pS؏pɔ#C 0t_zROzd*fO2n]­m{Q?80]vrhE$ƗD;؃lfA cwd$A_,!Ν6$`!}N'\$dOڑ9:`8A_HC aEqD"QchɲE E/Iљd3"GĐ;gjCQhdDKbAj GS A5fH/SbA+cK.L[dnvצE ћEm?%$(_ĐLH2Izy!+U~}fH I!3u ʏYrZ?˽y!'w_DsxVYkAw;@MbX@@r&;𚆍 l8PX=DGqbgkpIy%H̀BczI>K!5JMn4| #rc=zY%G6@Liz5;"BH/GD6A44'3hHゲIYδA bv>Q tJCSXDkX  db?, 2X0kGy*B):Y'hy\< lA$/g$1'k*t%^HI ;&It\yǤ[¡ܰeP5bm߫Ynah "%6tKsDe'3|W$3P5  XmUࡉb j.V`۵Fi׷q<=gK,i-.F$m],eI8@ŒHPQ%ؖ0? eVbx /Ic IB%2@  m3 (1w[9GDZ& ),P,îI$ ed";!>Sy%%8$FK$s0%S?1e>tHzEbը'p>U0,Erxrfı7d%_Pd?8IF?ّ$cl7C(8G`]"bXx$jIJ<s. & J!wmzP݋ ѽP055wgL}R]2=PN&FNCbP%y2` O,:TvT"ÜۡtqPk<)AkQbRGAl %ZRY@PeqӲ2ʦP"VY*i#N2k^aG"VI%=~3Il%قEn4"S(5¸AP/fMq!̦V CHXr#z`]J: Ēs*&5kK,R l-D#~BNLrybV1$GI $d@ K]w6kIʸj:k#>2?Uow4hPJIfCHK3e=O @1 /|H{;4.D?4%%9MY M'M{1 h5I`>AYjQ$LYAx |#ܽѻk:;̦\#)5&KҫXX~`NO "EНM6$5\]%"ELPEt/6LK/Hk>`wV>DXElD"HgKvG#.$|d Mܢ2]z.ȘF% z'6GH%w4G >0oo2"˙} Sxol fecȏN4AZ_X 8Odhk*"OȲeL#)322%fyH||Y HmoF ov%КȢJޞj$%ɖѮ 0XP"NΛ] |\nҮJFfFhr͎0%t(A! *?BE@/ $].H h#ln(7|D^vN?#%$B2wVle"P㎌AB^Ԫ(FR*#$x1$BbNB8?A"0\MHqEFO|2n!% >r΃l4F'':$."HlԅG'/d$, hң\TX.TI%O]p0R+腭$5n0a/di$d#"|08d3ˋ3 X8Fp"Xo ~S"2K8e$ Mbg&8R2"I9*$%_%"I*Ғp†oh^(Tc?;e@~* BeL=J'L>C>B2F:0z"Eޱ`Ror$],#1$O%lK#"P/ҧYG@\q%RL%JDJG8%POЂX괠D%~'t8&K$dA }XA=l f Gs3ݤTKIC<0> o##02?.Ç"(TbDoN2= (,Y63?&c‡>l(B!VHH=eO2bUʴ&,U@m'bUd("UT@?PT];H|l(uSn%BXa6 |#"sThY瞹'5# r] J2Ya BYN覨uݱt\<$ueB+XV^Cg Hl\fpnq"K"JmKT=Ƭ$i0^ =)TcXMFl$g jK%#W'`VGl2fԎ̀eU?6:@hTN9IHnC,nX; [jUӫW|g孶CF1FmSdV O3sB%9Tpk`35`%ʍu.1Jsk_x@ss.%U^v"%׊%Oz,Cd\Xw&$%di?5qAs|G0wuK*;ilV"<|7]Is3*k{cĦbL74́$g(>:,0[*l~bU~G/CuTGL oR=v ePMHqKT>?~!~"Rs__pTEe5<~3(.5v˜3rP,g[e=^$]AU^Hd4A>RO fHw3Qs DhS|6Fvh8w=2IFY*A\ЃqkNJtO@x@h%$׊a󄃆bnA"$rx$Q땷TzDo@n,Ain!<#7(vo@B3o.O f%ns"v]=&yGiH0ٜ3"%I_EB3+M0V 6(긿VUHYI,=dE-U6E4w8"Wh7hMD}$ X?*Ev|j$lb_Hyg jݹ/ x襓8IfhcSt{7$*kR^3}i%"3AeelBY!rGʲQH@$$NXH8Fh$# A7T9bf+B]C(P'=$fjƆL"YtFDժ^$RfWy\0.;~0"ԶKi0YEapLEn.ӘHI/U16:%Kup}(qNS Hk2꘤0A(a;"j/vbTg ?L BY*q[A@b'FZc$teFIռVV2\g†|nuSQ# + j#jjofYbT{2s.!7 AZ˖Ip"%'y%91nLDhl0 jG F㊘nl.~DR۸"KBX|#-*T;ŧ8Z9K%Ǽ~=0ˊ4HqfݨUCŲg3Jl2>dw"g(CILbr@s K}2KJڅH%{X\cfxݬ-|bX(UBSoo"%$v#S@h. @dQ6P9Q-(re$j NAw+xMH i83pƍM;ޫs.Ω<$l r>o֞Jl9o  2=ȽM)BB Ĭ,mFdIc)VOXfS]*jR<קB/ b/t4I G\5ʻKEϝNQ O\8-'K#rL(Rh-nzW d/UpY8 ' #,%+]}x~b~B0J?':Gk\ddQ eQz?(@AYY뙾k^c fbאfؼd. Z("~O$.ΫՃ&͂,{;Go-I2bAl# "Gtk^r/VU6@Mi\GF=6?' '_hcGj#mC>|J9q ƵdL­wy,rࣝ9TK(\;|9Mqk#ŕܤ ̠o)3 =Үs?A}0H7 ATKYED@B=},ZR&-m|G +#F1*H o*^9pG ]5 1 D.e])me6 Gs I%GؑpJ`b/ 2&h-Q+[ mLYhH"8\,#̐= [ D9jCHzw-ֻ($> Hoh;c7 2[ꒋ&d"!Dd} ^#0=*CCIkuD}P|'hXH!9MpL iu+fS7VΕ59E\!1'j0$;xn~SzJ4eKrNegKxN \/ ̠ 7pB?Ol?ڶ}\ D03zhUkE1i6k8|?`$喳lIzVXBp ?]hnu\-o1%S1R?Ux(KH$ADuHÂ??r_ P(^fAFaL+m29GKJdNH3GP? u`2?p`7G v ) >SrpZ .Ӷ̝v& qc89!a .leGs e;(NCH U sR^~m*N)̵pYB9#*.M UN"Uf3.hsA S(4fs9%k5?֯\V3^D(2k13b9Y;Т/\9K\aJ0qnv`?z/7r(VJd SYG*̎*kI৉bˆ6ׇgef_[zUd)k9KLC{9RȈ3SB ۙ=5rUChAvu.ŐoB8Đj>lt͹ϨVr>Й]q9Q ABG Շ7U ~w,eWw$n0#cڌ#'D&q~|MB.d_:O;U|Zw-b1"Y<՗ 6?¯*Uk;Dl/̏G˸(`:Qs*0Ze߿*#MqaN|7p!{7#6gz8ۺg>ۗ%su2;qw2K>y.ˮA;(O?;y6bK!KA0B("OXAJ}/4" ҽ:TF\D#x) Ž2b8;P:L4id>8*":K,9=Ջ27tS;EdaPgFgLdFjqh=\_s'Q7šq *p4&< Y<88~Et& BHI!6JW<A|ŰI錵x 8rvLoQH 'ac2h@2LjLy qlIɷQK 9Fk 0  h YтDC;Þ ꈐt8l $k88KC? LOFb s9I+@b);#L$>KW3ˣ ՏԔKF<-q쾺iD('2-ń8%J ܈؎HQ/4+F=##CaMD<PSِ( ȃ& A[,Lp&|T@F>PTtOJwKC7B KE3튀!UlDiyXP PTл=Ъ;B-+#H]0OI|aAb)ęI 3ѝ F&!*pY~ 2!-T tTωdGH O4Sl* Tz/'M2ٗ Z $l8!IڅS} js3IjثiWU F9GW55aqV0dm%T,E еi4Ȉ#Ł r쟭p. Ӌ\oREm%-%C)%]0)uR ]s>~ 0қB]}^5* }zEcBTH;ŜYˆZaB|I_4TZkiyXϘp8= ª|99$s+CUuZ:Q?(7 ]`r5CXsF&R0P83}hx:# !M #v\8X`b9gXU5%X$b{ڴ#bV,+0*!8JȏҰW倓ۭK-}f8}u/]%d$1d`5# 6z  qr;|!0W}C|EENe_:ٜbJ UFU6©KC3ɎcIMxCe㈘fkɞY7oQ Req-MȐ+8fV^\(YxS^iL-ؘۤE*%sJ%΅搏֭~2v= >1u4,bе6E1^H0.ٮ#0IY|By/>aa<éԔ|G TfWM,e ۼeɂ7"iݏT@CX()"_؃j)l&\sltGČ(&u?.&R 簎]g)~M&,C 3|ISQ~ F]V;]6Jip"XX"-݂Xn ѻCpԬu IwnCKCCy6J%P88+ ԪF}d| XƟ%-% i e$(Nh3Y2Y.p.}DDBlWАQQJ8fpfchi>;BmlJᮔ7P1l8vOCz۷@)'djαZ=AM֦Z;r ~nMu6fVV>i~xtUQD@UYO{~asßHBs3ldP)Ģ e,3y'9̙-܌jɕyLf' Ag?8YdwIrN@ .)t]9q <&uRܚXJk4r0t3D Ƥp ɏՎ9 ;~Z'e0٬8چTǻ}01Ns I(!)u&i"pxH|`oR$`w4d(rЫmBN'Nd  歷R58z@Im  O2On II P fЭ5G2} q2X51 Za8вզaq-OyaVʨE|sE.t\8a#9IWpOl?A@IuBcuTE#'R(#eldR@Db L@N"Rd@dWTh*1UŁl"ŀv:?UizZNB7J+fTX7# Ő3">ddrY2pcvD7?Ժ7L8jdHMcB9lsdQѿxY Οl35>R->,9_?AO0d7H=g::$H䆡 Έo⩺[9O $Q* B(R8B1jr #DQLPaGt0-r$H"-02=cˈ r ʋ'0 Y"2P'i*B쵰436 &Tꦽ2-@Ti-"t,ՊГ*0 42ԴiC8D < 1zI>?`֩.[md"EV'Fԑ9'wBM!_9}[3<Eȵ]؊DA06h-QyHv9yif ԉ͑tA*6AQ#7-JL h1e66fB]Ѵ]Өzr.ȉ񶯹䑰ݽ&[c,01tK5h'PZ-ӂ&D͟;_$KدƝK+XVr03'@u $XƔsZ@@tU'A,*Ev]៴J9.:vZKp ߯6ţEҒD"s%"3;$P)E){@̑ H,?~MXPo]x?PNQF͘#E¸ k "AqSĈ'ݶ5TYa !.lz-99Ȓ& ydnNdrN4o:Њ ĉ#GSz< [KyZ+0etY 6`TBb T *PJ/A>A<*՗7@›Q/2C>Zx$u\J adRR`hYLHbR7؃$R؂Ql0y E$0wZiH]*o!62HY0*) #B0OrE4A$aĄJ\|m` 2laz@ЋkXeM$FԑR'O7Ǜ+`oŐ a1$Q!$EBD1_}A$A1Es1Od"B$!bh\s0Tf@5!C( B,4n 瀐B0N P/l $N o Ds`k| bDp'ar|(!(b00 #'$OV|029"%Q ħRS ">*n #-P"$H&*hBD>$@;/*r"#;r0",K"ɺcY$F&73hh̆"la@0.z*6 Xo6abJʋ%"R1P"o"RnG((O҈3v" gDs*a;Ds*a<"" ރ!@$@}>a*s >sZ`%"HAa.2hφ" &G҈MB2T^@DB0"(Ҡ$R|oiT;'Rx#*eBE( ~'{b->`|*t_H2Ki.b--Hr2TODE&EI"$0TT `i3&@ 0So@ V8c l$DA(hE)28 OЭ).0 ܈3h,]:Pz ?Rm!6#"Ϥ ӵ9d"bVtbDOT)J6TWa/:$LDXkPoY!$IU-S"t^"̆![+!2*s$S;F$P6*a]ac!*e^4 /`U^Q"3!- G5 QjG((}\u 2)_#b^*tJB <*uApIddHB4|m"ծ XR)"FB4fe_2h+a,keF2N.8B#MIȏg-,d{MdTȏg0"V v#6bF UdDya`&e:P&QhV"nf=T,)BPI6W0$A/sbBSt#D4YtPk NR5RlG-GbE^ "06~,ԙ!PEcj*uFBaa\3$"d%,zFE_"{_ RlYv-!5ii!0506$TAFWг,W[ H[mRyg.#H1<~goKr Լ07R-,R4FjW0/0/*" BJo uCA *t5B"76RkHOqWr"u#R,SQSyzSu5"&eKUgc'-7$01m0%cH/Z&Qyo&0a;Գ1&BH f-DUв&0 yatXL&!! zb'd.v"poC,?"@Y}"-L 0 "rL@$\61^E\&Zd#V"07}\/|Sz,b\yHb$YL$Y_-Nٯ."KΒF" ~5w丹"o b&{JaTK{ JnF .5`09DR*FKB(:%X?V-%z6W) wpgv("ɢR±',`آhO~$hwieb"oR$W,kLjt!SKjDk@@x*yoR$4B38BP9PBk"-]50 ]9ib-"]Qu7̲`N*vhPtBzi5asή)7L'F k,ҧ͘/-\Fu\8,20Ye%}g:"t[)ք0$pG*"-7)ˆ߁}qPSQBe v-8*iMhك@8FP$ "z A4ըkTk{o"ǻx#Y ΄o \ȋ7R鲂E'Ǹ&X- <ڐb"٧ ({i  _"r4k!EF,ڳJm* H0. A :)#`- Gc2I` $JaM(?H#=)MtE'(hxSA޹饊`x-!8n]{poga|ScP;Mƙ8jgPťRM h Zɹ/y(o~Py(]RyLJݗ;M(W[7W'n_.`֞& p"(W@8]=A`Aa =*0G[B Q"((~(|Z qY+xW& XlUtH+eS j(Gi"6`)aas&eҊ\"/`y=HҌH40&n CqVA?bgK&)*iɠߑH`)#qX Vkv!;SA{eƂE^whp[喢:WWĵ[b,"nʊlG&E.'&6dV)Ih=c+K\3NPjo5pL\!!2p+58eBFHҜLQP S,34![ UpϫmBRpmD4bEUJZr&kU!kϦWb(#!"~{"2F>Ed B0F MuH4"s!`9@EY[ܾC GTREy4kNI5&, Q (yiµ?ŤS"f+@P7fT͙v"4DhOdE!K3î.cBpUh8d #*DE t5BnqAywdq꾷X^PUyyOnR&rYNZSX Tdr:}PLq'fQ4 i?ļJkMY4Ĺ4,o@8Ie hgR@OOHeB PTSy){[¬+*5ObSVk !XM*⢜?Vhma}eVڎ݌/#G %f;ȭJEswc44rC9"&8alV a,B!V*D5':t42`(^R>֏rQl3Q.܏im],K^HJuJ2Yv.A?E‰4 ?"XZI?& q_)B)EAIH]DR(0S C#Hb2֊MP ,G¶pH&uW9sDP&< < "z)Hq1 MdFHyN5CnH3p͔]P fuDȠ.ri CL7q< Ec? ոGSTF[]V`WK{p䫺&O|UIw:ތ;ylt$L7sɡŤ̑\ 3չv3yBcmgM63CnBRPJBw@`T _r)n$@oh"xU$uQxa Yyc/!x2nx4SW9d&*`Ca"?CFe ޅ e!⇧?S]S'lM@PUu년xU{qN މҤ޻x!7to06xsٷmn?i\eW4UviVLE21S<nr9 ބds[R-Ih(zūuz܇雷eTްTE I71d9M7!zbo~GI^2(pl,0Ԋp>|{ 9hK..ʢ?pC/"9 8rk $2A( H8;c::*C*;.jZ+[2c8UBjD&S2Œ%KY[.:U3q?)l" X;'PD@?؛TG?[1$JD ՔBDhPhהK ,M- :N )XHyBEi+gk$bEF0~kKaFDjdj@dma p7s"yЛHR7F rLj0(8"U}^G韚+C(.rY'#d9(!*O.EHhJc[q@pA#/K(˜:d&D8|u:L+Zl%C0N:? A_C֍{J` @# 2/3_2bL:I\vJ[EYSR Q! :L=XT-0yR=Ep5RX5ˏ=jhE`lǵ>a$_90ƈahH4 fx\iͬl׆h=4ʈ{L z x`~L3N($뱲쉸[ONH8;'aUah$r[3J&bgCUL1UJ\GP# 0 < DHJ3t@BR22dOЃHE>P]   [Pȇ#YUxϴ@&MRhQ0/3 )#aRTP%dşp=D@YE6a!x4Ɋ9Yh*XTNS`aLB=qc5;PЃQ _bԨ%L/RN`?`ͤIϹUU#,ڶJ0o"-'9ɣj)[ʬ*RDUE 7@=Vր(<ȟ]Y ț֘=Q y0Ղk_OD?m&&CH~dWj TB+ѭ@El? Gx󷔦Xy* ?cD 4E?Dr e\3<86<3>uQ{r٘CLS{5FQThL "`*L-> ׾mMA =UXThFUM\֚P]޲-x}8L$܉BVhxE(RC. IN_Q 1cזn$7tYeQ҅}Лs•]Ҁִ3Q]ؚWRmHK]$R\<aV2$؛e6C\nn0 \R;??P_ED|5 Z\M}1P YbXSX=5>8֞!?ئhElXՊDL=CY.0]9]0S|\_廌F H[eAu n05J#$XRg]ԑ# Ʈ*BS&2+4ݜtUI(ఇC&:5T/X)UAzU`;-dkdO.PmP](Q{Ic#3>UD=}VZ4u lom6TNݼ\0PEkfDTo[.#YgM26x(նxd瀢5Bf]=S )h܂G@)AUd*fݙ7:<qUx7UԨbzmE'XzWB dMl Md+$&H%2؇ԛ@I5}%]4(e 06.vKQ#aEkX7xvQO6^dml4@Ă`o%xH.`I9&gͅu@ł.j28㹂ᅩKm1QDyYN]LaV|$sT5QPψ]Ye\^eH!U䀃hqL_ WL#01UrfPKFẗ́&:$rHˈ~VeJ4*BN\L´4/@Q N\OƢx;-9e'e)LD] Q3uޔfL62mo[G1L<.m55N <ҟu@]lZdQ^ivu.8]f۵gIUUE]23g(z*4@$ ntnz!۲YLR5pd?ѾK̜!c &PGhb~HFdL밃;+4ZhodBW'cㆈ|%rE(P}ѿ#PѮXNIL'eo\ed~vĉp 8zN>$ $lGUG$k,43.`NݏbN іFc]L <>u4/FqD &.\7E q9~}ǛV؃rC3_P7m[hR $_PC3wKM5UV _ɢ9ĖN5n e͌$u@Pb}BfnZ/qf0YwR*u@뻥k( NX ӓ=DV jh;o8H_ROy 5 ~Ȏ$wVR jި<@Y.so@w!Lδ#998ێ^A_C aШa%EhY?#hB- $et H቙X3f4E^.M%EV*O[+e,?6z$Zreen".E7Aam7- ׋*|E)Z}?ͳ%`rI5baEcui/_Xôi:%).)ӋL=Y7{ܸy_DXyA֐}ih'|(L@0|(P> z@ȴG8@FE LFKJT*;F[HuCg"A~IKKH(`G.ELdL<$شzd4`A!$ȱ@('[D1X4z-꺲Ի\HN.- H:%Xz-WGZ+LRv9<`ԨF;YR*;Pnc*H[g<,Ϗ@}Ĵ,@"4c߸6|#]Z6dkxZl nMaJMF ﭧ?co~Ȭ<Y ϻfKNV"иִofS䨫㖶poSؖږYŽPkPZn10/"g~8-7L`.-z O஫ő`y gʟW0,~2z["+JY$ gD4\Թ| ԑҝVIU졝z,IQ8R,EɭkkIWS=r2;W_ImBUҵا݋_&AgrZGn$E$"41s-|*l$\3 cCHkb47",2u@ѴFӉkVt%r!iI<cI%8ϱ-)3̀3cHxVAEFvh jqDF(u"М!.E-LbTTK-*_fbd+"6'iF( {-aUhB%iئ ٝ~F Ѭ2fK< %ՑgZfe}WC(T+zN.W RZT/uk`}O-^]W)C׹: l k'. 6ͲEkmd`W(BiѬ \ pHkZ YdVCrtbxTk;"Ս; -S!պYZLKB^E< P!e|X4cybcOŦ @dUG0%RZG,.3-9fxY/3|@E`U/^e@i-{"iR+qM,W܊8*ք:mQO=ӅSE\+k4`qҕ4 !0 B,bZ",K &F "m .Aۂ[Qbx%6ZxBZfbaH-1<NqJ:Z"@.4kZI.[cN}Pp(Bk]rBZd-m"K! R>K|qIp PУ HNPzHN+􃞣ٍLh1QOl%_*tiq Њ,m欧"B݈<g`4oDo*"0ҦfcGY1қO%2BS*3" k 9Y( b!Jxg5b< N[5f{"+!ѡ*R2h*B[|ҧg!zag *kSn+.x;2T' p0H4k4r`01B lT04h&4"+?p (#2Na8~(o Ze/ jć+g4fHć4x? ބ Fe(Dit:< 8fa/Re2%t &2{'>3Џ$",t4reُIZODZ`WM,[wM+3nBZGtmNPIT҄Fg ,L".]j~Љ( * ͔g4sv-%}\TB-B4[p]e "# "/0p+ HTDIBK)k"Q,8z߃A&*"j8N-5.Igƭ06@h=*?r4XHhC/1pyZNz"x"b-OMt 106-6"\ErgN wfa rnPh.Zs<%ρp"OB9nSIY# 9h̭W&G7%sm5fp&":cP1 3 84 >Ŵ\0Ј2"V#1=:+ ;ЄYL!.ւOD,@0 SnCF!XZh+LaFrGdQE.#DM%mmdTs,%(D4>T_\\tHDd 巳tuF:4`UEjT8*ړ9"jni,aiZ0Gp<.2{RpP97)bD< :1ԯk}7,4'~<&!i9t;k/U4e[HT/(UT4vm0WÄy=< Vza\zT+b7c]odNC8rFsGsg)FbqU@ǂB<Dia*dH0h1;" cBҭ9b[mGcꗞ*έ"ZIᓦevZ! UE͞Z޴ 5?zJaIuz<RWFep"Zxz--&Ip9ezGɍ9v !a6!{yZ[Kәr.CiU_=ds%+~c@([fb/m{8υ(IM!XzgyOvo}EQ=+D8%or""ۚ"!1c+[b6 Zh_ 4`;B-%ls/39xnv&L!H@OXng"Z:2k"4|4ՅuZ͎Ϝc,~ZTESIS!}g . t[X }Iky 8"-XҚ|;SHS1zr:2zOE"*zLƚ[."ϼe͋d[ocGpR[F$S/0hҫ{xtGrE|] %d [_hr<:t4n BG|%—LڸEz@T<jzƢ&@Haגh8:{ jvlxБ!y9NZo z]7~\z!9חb,$#ȭL4 瑱?'Ɍ`[1(ܲ`$|;A|Eqn=9YّuH W?~ؗ~;2$@*sȉ35Pr$/c¯0@6=Z%On0ŧ"@f"*Đdp'!"ᤎCȐ/&"C,$LK-a/(0 B$̧14J\*r J9+W84,-nɫfI)2,'D;vϭtPh+ ?/.E6tMF53T"9ES.9XQa \0kM <5b"LIUlG\ȓDW5sl!ժC.9H,ډNq[3CO]z⠮7* , s: p~= Ȕ|@n %5oUxK@D[]p-2 䨐-#8<Y! d c6f t aP= ("@֞dz k*ubampsdMfC\v#! -Ms\3K$Ru6TiJSYkuC0v6խs]"RQt^]ju($˯|B"]_Px#חaط$sέy^sBO:pyn"_i;o1\{6ŀF9  p"LFzr*"c%|H ř`6? &:if1&VD\)@`yD$ZPP!BHp2Hcķ* O>gդ'xF"1DwjWFFtw %4!E'2qJ( 6]cL"D+cT\0*Q( 5"@,A?C':-"1X>2Tp*sΌjUѹ#s"/xHtSҚe66vCb˘Ţ[@gC "Lu^X碀JߕiA*>Q@`:$`Q)CD@?E%sA1 )r)ȸH8ĕ멚jSU/)`͡&ZejLl&s]#c8}LZ ^ՠJyW27ĻU[rVs(^Mz9gy-"?x!+ Kwjy;v^YpD(ɳy~LVh85]=a`5)Q G)茂9gYh%PP 2tL 00H":QAhO|9%N,)~!_HS%c}eCPEMu= WP2o>EiuOPb,0Fk-j,O Iy喞Dk즮f b`Y.^X`Vd2xr=iHs28; s~ Ժ˴ ԣ΋I:=H1ays %/Z;10'\r--.Cl" r".h$=Bi1׼/s)fC 3 p,Ã@ p%x7@Xԍ-s@ H$`M 4:P=%@Ԝ%ʳ>BP?YՉ `9)=D$ֱT Kz3Ȃ07պmDjʷ7= 2(+A-5 G%Qa(͒ @pT#=Bc6)/Y5Gr/l.s9@LbߒT (:p> ,:DH *iL:VDb4O>R rn3I^|Iq@?H[ Kde 3F)hAe,z,,,_xє3hߪ=X19:llsZQD܇Iz YA|؋-5""RsBPx. y.+I2ۈG6MT"h`MALYCsHPq AkȐ$l8pۣjJè@J"sùC7(,>X tr4L@HԪDKC3)^,ʑPQXDX ,rǬ|0Ÿ8pƬ|C90۰D 1 ]#p lH*P+,;J`24sM;B[S!9-tAGQd!S4=1` | 47B)яF2L!CO6l0<>ްUE>=% "ԾHLP Z:#Ǖ0P8  $hP >ʡq`ߍʙX5Q!g*DK) T9ۗːxo=usrҭ+E>QMIR3G0>׉p@s }XT t3Êu8OD=(+tSAA؇Iu< !isH'UN,}YYZv4PЃ\;GA-bBZR8Lڞq- 1>(Xh֠F[>' X +L1ƈHWӅ#p:WQrE2qqh)eɤJE ϛq*t˃p5FhۍL xغI@or(2dZT 2޴St{3tA>YធUxX؇Tݑ-™4͵:)X H sSFz s*x8DWSRŔS *QM T - u OJ:WDx [2E@-ەP?K]zZ1)2J8:KD\i,ԩnks pP:CAs:~yΊ~|΅ح.D1 "OީؑU@4 ;uNqH|TT5%,]) ؑC^XV[1]e;`7P]f-)ݵ=e#-I},jT-ǿ8qD)o8 \}!+EE0-Vd!rIS; pjP]5 3-rnR"CXQt!6/eI蘠YZ~Zq;.t6ATvM uؘYD-LQ زG'ƚ3pyA]O` 8kcf-~PR8ߕu%YPeiRc 4`sVKt 1-pېZ0Wab y\M| R3mC8pa H*:i ctcék{hx2 f1~asTvQشݘBFϩuf`^T-L6XoHd!Bֈ.E"@!pqh`@`(_ Ϊp :`8m0{H,}aAF>윉NCIE[lyŽurU;-N֬|g<|`,ь'f F.P<KV§^P9׋d yU)sq/KT{cj5qC-_(R Tzu`$C OKXvƟ;XjNt㯆D.7xuEvFSMW}-KZQfE+F33c).&Ô]'NlJp^ -%&(hyCmCh)L6-wx nF8V=f x[m )}\:ԓ J<s5jឨ'3?EHѻOޑMݝGo|{ζMS M)7RSnW툖p(؋"B[gy7hh%Ol?T2!V#DPȪEEqBMA2|]!/C 7vl1NbY\?QtU/Ou6N"tTTR-#Qzj:cQ({%fXcoM/oAWU"}0TNO6/;Y8+ȼ^83&GyƶU&:om;}zptQ*.?ܷCËܮdL;Qpu^w؉=QptzG_; 4? J.A@5 ,.n&JA뤽>G/X l>LJ2)3ID.+H'|';@b.ˑJ%LA1%pKLZL,f3I=+艩DZ."t"raD:(tr>S  t.Ǝ3Q2N,$J/FQԋ0>%tD0R/tB Hg*!e(k׌mżǃ&˶S)̲758u+y*STFL5dn@o։C ks c)8p \"yV! "x3x.K"q:/ffa1\[i>\F`"Ď6H:Lg9S>yI~m`8[;;b{wD Ρ7e6M6͕jOLS"wɴ̥ wU+2,*Eq( kcz?v۟WuA,2VUԵz ^ͷRXwR'kaضuڇA^h?I'"+r|kwBіZqt\yY:nhb-M>YAB4ahVMu7NGXt[$CBcw{7Elnyv"'`d3N &P*(fEa!,ֈ]<`7(pMu2gFHtX"Nfn!tuG"'cMI.8 UgЩEg{K%ϓCYD10bW*,WK vUI%vk- IE=LUΦvD^^4 bzXi= AzXsd$YOR.DŔBV!9"q"}ja:+d"F!C/g2%M!AN$>aN7ʂ,P.Ъ_Bdϧ|reQ (C6:@A0K΂X;lh7T,A⢢&$ȻqfzR?謤lr(BTb$͕TL!+TEi/R'IdMu)Zެ {17(*аk4)?QIJuHg%g Hf˙& ꤚc5Q;(yІt7 *pQ>HOuDWk "t *,gEl&);.$DL]ӡoDlRs !2+D-zyL[Ia4?pby2|U4.՟J6l7OE""͑Aӳs kN/;讉_zSB@±z2dB~*eH<j?ڤ<쉃]lEǶcG-K>eCA]"x_/X[&-Xծ6)$3]vU;LI`3uZ"*n0XjUa_v)WڵRu>)ycߌox"E%>!P8MY^K)q>D 5>h V*0OR#-x'=-Bk{y)WV>hW{xdp A}mޚ㒪|3kHq+..D2aKɅQY ueJǽ>} ɪ ydrŸ a(9Dh+.xbcf<&ҫNK,ckeI;p : p8/N|8DV4c f.P\\h>Edjj: (]J"l$dxB 3򬺳g6)eda h,,fI@/6z ϐ,d0FnzdO0b|"p> 0(Lj3ɸ(Ɓ"\޾O^j6d(02fE8Np*ꎐl<]&(hЄE4ЄV>&9KMf L"j"5Cj.7&;f̯Ӭ"'.0MEOfo3 "En)جڦn3,^ j^WVP \BX/xxh |ė zz$zVIVIR\W$k&(- qi ",QĴbtg"g#車)re:Ǡ|4:R![H)LR3ffZ>ܬj?$,"NlH@d4ՓƨlDp,m"<0TER4 ϔ$#1gF (F@դ:dl 0@./Ttp&?QcE#"!#" Ԩ/AGJ.K.\^+ aRn*R1?tq6T gy6g7 o?@]P3!njb -ƌP| %&/.ǩv؍:+4"=o*O)7."r"I4.nJ<;Sh<fee&nnȸ@=܆dZCgμ5cH"kר% By;!#TG:Hv>Q \+]y"ʒ-(DA,Kq^8Pd:KXX8N.ÄgUv K-&um0QnчfNj^8FMvcQB"tw\.Ìb/&6:a$ZpFEG!fP$*Vo^ٍqwz?a)}u!Q$_HRO"V6MQlx)O-5!M6"ĘY2">g[:J)9RfdL\qe\ƣqOOPRVH8.>b/+ht0kMHxQmF?,Ο68Uy6g8JQ^q[WO-pOcgÙ*߈M:/AX"ɠ/G_p=fo#'4/&ѐQ!AuN@רO⌭(7תul[?7z>RY,-#0 gJ.T5&BO6"2b C(ÅO+ h"xHYTJ\>n@zaVzE$&L`xd ٛor>!&".DDK&Tӵ `:&{&" ro%%b)u:cʠ"-0sg7y )"t m5%"ijna: \{eSIPƯӀ"+JAG"/T)b$9Z"!;x_v:^!*7M/t~L;&o -OnoaFUkEEpzҨYcI#r3&c:VEd\4"t"(Qcfac%1P!/ʅdRPsZ3eRTd0{BRVLg^/X26CeM}+ r5Uy*-hiK!x$"Ó(|S;LxYyF[%|eӛ" '(R":ZO}L̩=+}Jrc⇼o_DmtjEwbN?q'ŗ cb|v%Ί=wI\dUGUR#^Ku55"Cauc!^X\ɺi] J67łW*4V"FQَ>_@ x,+2VjXkBUI;}HrR~V`V^֑ O2VT مeA"'XSsM?ȄQ$AXAFDgcC4qZ,TMʔY'URsH-Rl䥎 #m V Zm6O_L< XX?cY tTɿF*=V\!5 (C/\kPNc5MX;x:-yK[s^հV {/EٗvOYw"!+M,hB@쒸+J"y7 "\K2d:+ . L.kG *AqD7JGgvGDr!ȴD$9 '"<梪8'igʊʨXDAQr  MAjNY5A ADR8D4NR(P:Q9+`< 4GU׍=WMPVa]J+Y+/i՟ݺ , \v=j qH+w,S赪!_g{_LY(-G4[(R{V#/!㇔y?"$PjCTo8K +Nq'Q` $$"{ 'T"rr?Vo)ˍh>Sr#PaI@hJrI9'ӡ`i2%4)Xdy3؁Lc,/ \X_X27 [1F~)\yG¹BS*TTr3[íh͂y$VIVCzkG&2ؕû[ 0Wyv:!hO,]ձ+j٤F PX,`lG X*[r4Hh!IH2r,.Qyb`-7AL+: J c1Ah8*V2E$1DuK[8 !L'q:@a&kP:['hj0}8ȴ Bpƫڝk@KePi@"=.3,B MW,jv$ys;VqwUIHZƑV@XGAΟrYuu@FXs+ɰX36e_ m)'"τX._F6"ChtP4] X"TVsGa;I QAKv"+-ЉxJ+8@EP_ZBbW`Ac)| ل&ݦY562I!5"#AJQ).RԷisW& -04LEa5V6Iݬߚ"^S˛59,Q}v'!ܷ)^+@ E?l 0?,[2VK;\W3$vabdeyN,eV!Y*p`Ͱՙ\icVv+4̿)E[nGm)p7K$[>m¡9vHCa{5% E`>f7aȂﱇ*oO"ÄW|mGEz `i)ߥ[L+]-qY 5U&'d=!¨  9%[l"2D4H+(|?Ǒ^Nq ruTY,%jEd$]ٰW-Ys5M:Q9ć %r: i_ɑJ#t|@ذPԻu@ÇQA]Yl<h6 ;7!+a≯ ڽ(4F9"Y",@Ȯ0@b0^") "< )C먡>[ a* C>4^ 5덇DKSD%2% 4D :Ӫ@`$;#3K EOa`TEDS:C$jz8;3p00pG;a JD< >!ّH4-!9!;=l*г6@%Hȏ0:%wzz+" Bۛ(0`ã ҉Ǽ#Ay1J 7y5Q iJĢ= 1Z\8^CǕΖ[.9JSU Pc2ΕW0ԿgYjA`Tx%Pٳ_4 Xp\E؆,( ؋d zLxJ<ҁ~ <(T0l(Bˣ$Yھ HI !@7S9;'BBA#l;J(5LΐZ5tBR>DJK+8Tnb%hE1Aq]ˈÖ;9)Q`PԫPK%r?=R(2\`(YRm+W(R8GpR(0AvH@|ۇGcСHM ([Ȍ8q5Jː]A뿊aB)\!$œ>HUQ֡H7) J#L3 %Ow T%9.UGA95`Щ;5D$ 8e=JJR +k E ˖j. !ѫ# km1me~9X dΜU?̑aYXh Hv&k VCݨ\Z<51EHJļK@8,ݭKpY`A1VQ KXW =&Ӧ H2pAHU] Z.{ϋоP˲ _F;0_x|V-@NCG\yTY8 9=)7 ۙ;"QCRD "yU] )Y0"LbejQ]">rtYDR0cF/CvWQ027 5!.$daԈ^'rD؋fD2d[ Nd K 4\ S9R,e=XYI$B!O1%D?`ZH9(%eZ/"#؉9/ݿ + a!7 t;;*4 y4-Zᾞ^}Zm%7y >LFl0r.E\hD`([{c* S׼H![ӈOUYb,Zz}br8> Q!Dn@r(t$`tg64zp35^:s; idSc_Uܤ_;_Z(I_]S&>2W`p044vh_{i-jםYu! mF -(Jw 樈X܍ۖԙC(RtVe1]H;G AeYxHˇHR%"5*6%:xPmy* D,e&OW5ϙ'` {TÁr[Xđ #ԡRÊaxjƈf9rv$ReyӰ^Wz1׺ .@ }@bhOrN W1geGԈp]|-Yp nPk;W g4:*!b{8ˆo9ne}]ll;Uhf?H([Hx2H_+J7G[m.)T-U*+~H.s"45ݳPFU5 Z :nCK 8+E FN5OF1T2D"QA+)%ѨL%c3&t4L `CA00U% ?40 c@z[Ӫx5<#]]Wh`Њd@{ _ acALCQƉ%8BGw5]B_hMtΦ5 (m_mh="4?|j`_ރӚ4cdr^]/㐨4Q]ǽ{Ѥ?ě$GG-OLK0ںEDTIpQ[yFFHVDF1mԓɔyu]=7N%XƁ{ - U`]x( _gw m;,j>Yw#/^+'zN$(خ?z4!~GS H Vu"4[^k=|`_c"AЖip}Vp@#>oM٫B\ =jcY14*O ]憐 P.) fڼ>Fg]Ϻ1|ƈx?+>B[rP1"0Fu*fuC(B6#tWgg^Aeܱp:>i !gHf2g8,MI&ut⨍Iq+`dXՄ^+OvԮlˆӼwEEp*o)xa 1 <?T3 tNdFaӜ?Ä+?,|rӢ;gv<Ǹk akg!!~0]WYuS #D>2Dʔ{.,DzD1qqX@OpTmG{a!4ŶNB ꂈ@ m7Hqd&C]1#-iͫMRN$3ʤ፟^VT5dN y'ђQy'`G(R[dHʭV,m̾W,?`6ѐ~WfA^ՐAQ[W ƚ0L? (."]$2\ ;Bգd%[U Kb ?scƽF#B*P &iafǑ6"H}=l6 m0"duH[.gP:Kk+b/j x6Q򮇡m\ƉL&hi{W? K)Ò YLh2 _K+dd/dyu.He˴HӶ<5sd ZO%t&iκTm`e?֐SP;d&Î+,.o _`tK`SBmN>sdQ?9)eBN@_%U!-3{UmzJZ7!7 Lg-"&[u6kLI beS46m4:#bEĜ>0bPql-ǜH6Q |#'X]Bu 'P6Uψ78i ?OOվer$Y5Ello7^WFڦjۏ$Fq'sF2*:}u߁F=X) gN@M\?m(]l >#+!*.dRL!#q.In44,K. gB `hƟ4q6 X!- j3@ʤ\0B ,ޚ#  i0zo2#N{|!-FpVw) $F2#O] 4N$fx@vg2 N qP lV^3Ć*lHDKvz,fo,DdbXʌSK&Tan4 aq! Cn>x X}b!0jv'ς5 ؝ ˌ^ c< fHIo6 Q$ºa VX¦:4i&p4&!("Oz"qKPΤ{nrL=r,V9Bj,1+,&xBmkh.Լ.ㄸCn+쐇R"L?:p T=yt3o` ҺD#H0jdJlDlU/I 0m2,Cfm0+ȐpsLC܂=RщID`PfiG#.M4B͔ sV t ֶ:eƞ#RhP&N!^#Iur+|E"W+d)Q6#!(#Hv'E4rSQh49Td VK(!!VUfVli u #SL̓s%=ʊsϖPi>J_[:|ooBFf^4TkOFDu0lk_J&i.,VR\l=DDXȏF\oJ=&*Uc@թHRqVP kWQRE MPffspK0fW6S!0T؂Fi$5 2!$N:+`+T {75V4>svY48Q3LBMDLP~wt fjLކC/h p` mBul&y8܌fHFcDEt_/kA:C7#T:BvR=i>Ler»&dDd<.sˌeLKkE~HшKO7bYR.8W|y*» ExVW"o9c!+n o::YV E[/@1@OC*`V 6b4;JqWY"KdO YOT#e!^Ҵ#Hg7.$ Uh%zX-/qW,NƧH rQIlnIfDw,6uhvv=mp#sUM 3tš5RNQ+l٠MrLCE=/ڶ6ecf8 FYï vt8@jೲAR}#J4 a4>1ƶop@'c"2{ z\ x皢f:Qh?G$Oc@ qT:pluMvg{do10@>~Bc if\~ `۽= `5r4KKxC0eAg!a4̷ Zsz%Mdєی"P<6KlLtguy !5_*7.:?qFݎ~6Gi7-pzhx>m]qQ]o9CKݛïw{~^%ޕTч gdX<؈a~ *h>Pt {>݁#xuĆU]ГM fɹ/49p~>fP4OQ`r3JX͑cׯ ZU6M#0CGiK&,GXFϝf~FbsFy"?X$ >D1W.0HF1$?X^P&cba$JdgJ-JYԺO;Q^)j)ڝV\Jt:?6]>R@U^Q*zcQ㪌5fTStM_1J,uSʋ2 Sd2RuY5n:j] V6 ?X rvn]^{[T/1fS |17. ôSs`Rҵ)Nͯ oʔ.rଦjq ƻ)QHĤV|Hưфv)IFq"3q;;"6H>+d"S=*4͠D::h8#38 >͢ ҁSl"ʏIu$r{&1/-DqԊR$k-rLTBެUă4LO Pn׍<7ZTūL =l,ƷZxXdɡ\]']w^-6|#ݕ,C#xQ%̗xtE4s=kYkW^ÕM(5#R)"DڛkTQb]/JiT/'F3h͐æKC%2;3s[H UžI偫1KFy`cjGUc[n%f(6fq5ydJC3%J;fAku`[ZO?\$ӵ%cbGdUvE^x4{`Iu߮߁^ڗ;>v'1W !wwՀ( W88J:'^l2@4 tmP# ̔ņ["X5 GH&7si(AOgKG,AtdJR I LB(aEI>Ӫw1MLEfD;zk/b]Dp!F|i1PԉF 1f URҧ,"P&.n.Б;R ]s%B XP H}dR5 N}e*3lUs||+rZ}36 s)?10 M*ed A(e XH$tt0܉I)*eD*Hr *4Kip '>LkM7%ROp ~B "4[Lm>hAI M4(ȘD{O=6dP=KG{#Z#O$Dv,ȶzVq=䓒HU㭝k-ě:V&] !%;U+6K$X q<%ҐW_[Hmƥ"K rM("Fe%iI*.5"zȕ"P(ȍL U0Q2Ȣz~!1 :K"vGA7L IkPK,7i11XB\=gj% /,dՐ[6`eye׬^b2d rWpa"NػKVW3oh;h_š% ̘,q@^e.o_i`Vf3c)ZǴ6KmƔ+"28Lj۠kbD 0pӡ+7gʼnR* 7Uu#V>Yٹe>5ƜGo%HZ4m[ӻXŰ]}jqYCⵛ=0e֊[XJzDuaͶGeC"⥅pZ="vU0t˲ mΑ+_b\2n+ yњv@ `%`9hjY=Dx鯜/_xKU>˝;ǂb2:EN!ư [9VkeaT&~V%7KFqfT0f]Pf#,"6"66ی ƘKݯW Xs.i 8C 8ј T52sXàͅ;Ў f2_4Bk/9@9+DL pZDKD1.mBͱ*yDΤAd :?k#ȵ5C2 $pe3o K[ 4 `+k<>p͢C+0Lj;ÈQG1;[#9'(;h/F cD+2=`Rc"Ð ;Mm$yYPِ :Sm IAqk- EJ>FsIY`- aDDJZ <ؗI!$8xз ; :y1ǜZtG; & pDC aÉ<AA T`<#I6#;ko"<̐͛G`lLjEA"!Ǽ#Y#B+d,KD 4Z:|sז`?{ j= LKzIDK]?51˧ Yΰ=?, 렲ʸCB03C=L3DΑ > Ԭ=h!#T4D`Yb !xSv #P5F:;Q(FŒbȁlpR#L- mz4I#5`!' ̵ uŴ71`7HWED{K Ej\(SJ(:%|BcS6>X@D|AIH1N2ԁ85'5KM/OC]!9 ^`JqnPa`c 1(R}' 5'₈&LpK 6  tOus49ؖO4MTDm^m4|X=Ou^EVDpI] ʹT44DO͑4 G_.So1reU\{R;LUk xF1 +Mp & #(5 v~ak\ " Rۥ֚Ќg"u&#\. d +` Ņ`c 7[ȪE0%1b4ܧ_N$9`+. p5 ϔ^4!@6%qs,_>\ 䂐$]R$K׿ͪtS n/]VuH~Q#!/ ^W&_ FR[QEW. Dgn;40IlnQk0ICKk"e*M6tZjR!О'x]MJXe+%\Of}4Xy =,,kLOSD O_JAP1T.M0,484DE9 XF14T薉m81MU@,TJ=Cd PøbT 5 l!T9#\"Mai86n,P q X61 L.!XVZeͣMs; yfjbm%ݵ914jsE> qfcia =4Y ;MK1 M:dcX__sP6o8\:% p}s̀>A: @VjBXև~2#&gU/޹`H螖kpN !#`0 b۸Q'Es^ap8Qn@A0?h+F`f!"]k4wj5tl"؈6^zXs/8EZ[$U318iV^4~r<_3-QM_TKÅЎ&Px?1_և#0?sP_\oZtn ZoDx3O5@^N!UC; eq% H[wnb!7ξ|gus̸ vDF6ABY<<`a5&d^kH'9&9#\){uBC{m!XMݩjdƑ.~D8 :  ]D+ l}`+D`nXsh_^@8oxcEJHH~ob␷  VJqT׃X9e $n]HǠQ_! OZKw&`O?Ұ<&%RѸV."I#HeQhĊ2?7m!˥d4%.EgE2~Q2&33CZe!W+O}uTBRRh(4] JlJ?Xdx^i#/H$7rY$]ik,Rhp؄3Pe3KԻ7>SsX%O?<٩v[LStc*.gB{O_wޗnToϫOgf<'๡QϾUkDJ2AN|U3N=E{pAEC@%Ѓ?-] B#pMŬ+>֔,i0Ѷ,\Mc]$#-)8̙&2MZ]<>(G̲]0JƎ,Η,kjP(BO*: >N4"L(RDjj4]OT ?L;NUI:SRE15ZST@/ !-!3R&W%7,3]C.Qt %λ%6=Z̜il!0ЉMQ!.^X^qa89`Xi;ELbitXx g`LI ɭ2]!0}5FqIt(Ҍ%ih M!X+6JzQiu^2]HK%LN1&ϳ>"hLCkY %>G*@NAneJk5"\U^񜞯VbLQҍחB;9NQwPLGGer\Z|%ů̌Ciyotx6Qq? bx4Pv@$I>vG W陸tYrIݒZyWQXolIB7Go0P\[%иšOZS}M(Lx(9)\ބTDeMG03x?ۇS&KR0I1] LaEEd Q < #׃&rezsB2Dr7tpHŐs(-XEh-@3(`(WJľIsWNV-J^^hK(a#>Dbh1v&[=.jF?vo x)>(Бv.ɻ6T#0\& Zƌ" Ŕ`N)>Vt'N$2ҝIK(/&&}O4S*eVyC "dV-xD {v[[%j9efEIt#5yb%%d80T ټ/Bd+7HBUnZuE%:CTn.N"̘27}8 3?޲&Er:xdc+~F}mytkM>,vvRJIIW0OH]"gk6[`aLV)t"tTb.r]w_~=.+(#>N8Q*0O3!.B+fף̫G1 ʼnP,tdcnx4yo:FE{kyv@Xelbm8 j!/A"alT9nAlp"G=l!'dmE`7H쭬=ǚ0,JC:pyn!bD΄dkZ"nE`QFo&DwkSHa.ӋтR%oƥjV .BjD<$iVJ*c>MC&InAl1J%wp\ʆBF1"OOrDzfH"L~mW\ V#&lBc֭e b%f_QnDd*l<#tglʯr5Fwe nNFLS t2L22%es.RD-^Xnb3褎"eҍ(Ѕ!%k"Haκ{MI#GR85/W%$h,G+#2hϪ1hӎ: I$8) 0" x&:k ,BF&' }$X#Qm!)p8,pa cӆQ3e wmӄnB*20ϒO~-X4Î*f"L-+Ps&1(m5jUJhEz Qo(S3(SЧ0zgv`q5<"dP+d2.^R6B vktI †Kl818yEÏBI76y3 3,uoo!Qle^UDtLxq tvCO0v|j#0QcadRtM0"ӕk'Ds캵Py!(v)[Rc4Pևf1&W$we/wV2 j{V YOm}cb%dECWxID]0*\vrޭ1$[TFQ_Ujե[pS fȪF\y3 }V"U_. 4x\m↝tvQ4WK~.ÎVD$fB%% $DDdiPG&L3FSQsSna:ggeTzUuOFSieuxwgl(#BLDUMC4808m2b샅4Hv 29609Vֶ}U n1gouupCDŽoJlv9L`.Fm6;edžDƄ=13 5̊4P S ǚW#%B :l\ CE'bl2vG%463VgF ,ÁEY,cX,+^$b+V"8s3y%n|p?2x`O/S;h+-Va+5w9:vE"9v"\fؐ6*Itp!d;#uwT5(-YtҌ%:(z:Ts&2ew&P`SNVM>dͲ6Y"1w n"qVn2̀c:h CS,Û%WK1x)M._ϻD7S\Ʊ28K35`MK==?K:ɐ;dY8T5Ѐ9 }[`K :Gm/%!5$)BYNՓ}hi:V2,3W+i#e1Om hyFm+{nQm ]ԞSˑzTRWd y$+&b3M=7m}:&W nFK+ %n<>E+vtE_2wDH3- m1Q|-0Zs69G:o.:C# sd7ݸI8#}\E?΃O@Ćf|kvX>4;\)ʕix%0zK{&n,qy>|*(M%vMT#9z~RUQIel/{ۦ~YH$&~F~V:vϚ}EДe D]vBpQwZ7_|B!Yz:1EǝTp Z> $s4]&h9 3؅0XAh&ga_yKs:v./glS9$ -pT5 AqJ)Ep>Mq*6F.XJ1xJcGm=Y\niJBHjzk-mSE3"%YYfӄ=λ_"sc}gBEI1 5ҥIaLFٗg8̧dI%ciTnIb#T;y?GPqgf^vQul~I_JPHңP^ Mc^/b3 yY1S9>H 3vP14"LBr[ٹE״`~G8'#E\}…_myV!~/}c(!_WnIx1/lwk~<_j7̟/5]@Ge<$=+zauu/AI$ɦd֨C=TJ?Kɵxn@9/8P{p]#ۓ[+=D2N!k<wIN 9Ԡȼ&"* (PSBY uH>[9 wLG'|^NJ Q~8!e&LBdK5R "W?$3cDmsRdg %%7Qsֲ%Hgeհd u,(ȾMf$]ȋM4$tHԕqs*͘oSrLHӃk&85Rr'ؕ "80 C`T?}QFCy1" OغPr~Ϣ.`iDVlNT&9ܜAOQgpmbt5rE<`F#7ձ5ehޯItciHkXJ#c(KB.eRC[7'HnD?1\Rr t}1V*ĉJC@IyQOHe%py: o6%ҴbjLR9zRԼو 5=NjhJPq8..<0(dZRk*6.b4V܁ug@8Q֛2Hrb=Az:|cnƻsTo1v,p! or(Y4ڜEL6۱!}K0ؒR^VF!c"Y˃ 6dMtAC~H$Rm+< kIUkT>UJ,NkXLI^4\)7t]tjZ[djVudm Q! }'k5tbWS6pAFT9A$s*Nĵ"5U9m;,wڭTw]"M*PƯq,O<2R.G""apE=wH(s R%!2Ttښffe볒`@@r&59뙝0.*HAS)^S S׿~b'W72 x l  _?p_j.Cȡϛ1Ѱ/h#JraɊwbqt "Zlf'd!Uq5Pwyt߫IvDS^Ցdw }8CjqkbkplD79!:K!VyFJ s';| joļJ]1;,0ѯ _#B1y 3 0/˕TK+ ۾; 9((y!9 9!p.h45+ C;4Qd#P.A"1_$N4%B>XApa5`A6#:@(;J 9Lňa3ga&9sKګ 1kE˜,B$Yb0i5#Rߙ?ps*:xĀC. 8ǩ;Z. @CǾ!DXC?b(kZ4A BL5 @ [8QҧF/Zi ?#I/_1#H@tg!TTAzB)Az9k+[h "+"Ǟ^70$YJXs6FF;$oxiԫCĘz۽Zv*v tOD)DNAN p ȮL 0Ǣ/4B& ">)Դ.HS9'3L?jx TGnj3I4<{!QLǙ55keV6lE[21l v5%A;6ܬ8L%$7piotfL(xʤJ][8Θ Aq̕\u A/*:w c~7=cttN0ǸKC>J=(HQ3HS05Ŵ;Y6B k7> 8LC'.>O11к33,*B a33~3'[X'2m8$1 $TE]Sp֙!'ʨ0@rc᫬ЋMUc\"-R JL86trG \Ť;''ǵg5b%/ CI}s!˵ .Rs4EzC@I+ IX .9Ql_ȘM- AVSĚOd& 8E ,聦א&ˢu< qakVjL=P^VF͘9s4զkĞ-Ր$Q栃Չ& $N*pB,w>?˕7z(_Z}_OU]Z_Kc)oO?w OpVK1? (b`cf5k?˹7 ᕤO~uD?ź7GL_c!\-" j_=qi|7ی r_>c?OUF?}gM;?Ͼ2~??7kN/ޜA,0)wA1D4$pC hlD;b RBF?8? (ꊯ ZZ@ȑt/ Ɖ2ɇ'A+Ĵ3cr,cDz/4N92F=q=O`D4:i<$:R@M ƌMT(M"L$5lI! {1?@JR"_H }5}SBG4li'yi䕭g/Ie? ܇~e6LAWBlHPRםr Ӕ幢 e-ZoL[%IX\<$(2,4M0ɖ/vUo?xYa\U9}cEeapZ J-iJj^?߉j g.9As8 l͸I6;o-kkw+x7ZVYH+![+ˬ/2:G GY(U]]t0lBu;L`̈́aTaIUwT~Y$ n{keCtWmʪy2bP=}0dPٿȚ e{@Z($#`yc 8KhjUZP«FM3uw7;)^ ! j) תjyURؒ[}T,ȩ`sN*$ h _݀qN)EAߢi4%P`RV GȲ}UUdkO嬿|KRR ʍ$GC"JEHlҢ$KX!^G/rEiM8Cn#ٷ#lϚzS`.&Sv;q5Bhp/=(FϠQ..p7\e !PG:St%*O$lh3C!.N*TZKߦCwQ')(y2t̙lwsYdm}1RFcy-!*-iPY0$ciR bC3TQؼ$*#|1qUF)/цkUDf63u9m_2 JUZIPHl(T_GbrȌ JCSi: vv&?M:Z5Q$S|KrQ`:)2˕Y$*Uin[S;|FO5D^9WqS^їqӋ.`eTGU'Yu j&ssbjqs ShW# L& (}Upn0qVLe~5 >xG.GD_f78b  0Xo#б띱# .')Hq ~d٭;dZ-A#:s}#x!ual䄴NFD'*%f(;Y嗀eղMT_ N;'0U~!,𤴃R21RDK*%fJ cm҆Q`,xmeuTߣ)1ʤj-fa6k10KF^JޕH%cg^[5mBZY? hJ8iY*NHGěpĤ 5A%i-DdO.-|h9Fs/?X '˚c m; x/Tlf9ό09 f;'Sl0[:_傰 O)rNJxgU!/у@qX|O,?gRa"RE$gfQ}'ٞ;QU GF2x둗cN9B,G3Yb]Trzgɜ?߅T!-)𪸏"zʈ{>fiFK ۻkkve%dP;D<O搨0^p^dNb /wHNlj0I|` ܧxEGΣ hFzl@6~/ ..-(#Nm/6Өy'<*Dhk'r2cU vuCL3)2nl>3mˉR&Jڢd26ȥ-lS9eZ%O`F,edxd&IG'%B@*:(NEf#~Bjf23NSFfN4!.lp0Bȸ}Lxאdh؉-g}I6)%J%^Vdk(\%N*IOG`shLqSDj0hX^ScGZ;(;8xfbU_eOIF\~kj0@t,a/R1",5 1"mv_Y tC"׃O#<`VP5NweBwZ7GO 3O0jjd*^J&$IM⮷WG 56V᳜aa&8^˶T"Zރ>>²VȵLj>\Mŏ&LJ`Þ7PU?"Es#M@qݭ&M˴%0V 04#4>.ÙF340llN%QX0t)3;7Tl4y1Cr%"keı *'ƛ1 2WxQXG!;ᇾ6h)bkL$nZ^Wjk+.H66;=(YEc=BFe"!%h^%cі'4'ff[A,F(?|:`Ta]iWn$E$>k'W?fG;ָ&Q;¥p3|"%#=4d B6iO2$Vn`f!sOcc/u 0;4` .b.x?)̜D7lnlt5V+-N=|_BrG)ڝ٩4JH`u}H$^`jv,tgOQ!+?{ځF6ʉ.!b  . ;渔*y?ї81i%FgYe4ve?w-p?_*]OI&"\mWi[SS~_*uYaMrPц8?J$kN0g},m?E6R;y ZqxcN>`KT];^x1}ޞz=F/TRu$׿ O.@g Cv0p =0m"V+01"4C;WJAg2:+ qx#tC%lRJ3-ഺ gC3DaM?9,r38a:N!,PdFTTRst@,SgOOC1L9.K]RaU#Yj ]i[UoU6Xt5B<0;o;A@P mw t}"kuPg{FV$X_2Lqf!ȫhKoWՈ.bRCύ#AG$m ^ةdH/'@k>2c}hR6UD,Hn|tsDdA D SdQ{z%b<0qđGY{ݴ.l.m / nMݭkn8p۞Пp:5$r/@GY jXP?@ D?3rh:F@Ì/K2O)Nߤ\t'@3|"J@AU4jt zt`ʟTke  *աkkv%"t!?,.JneWV0fwq>T& ` Ve"haP!<*;bQ6GK;ad)CiVrZc9*Rֲ Cxlh&f$eaYd;W :Hth3d;F;A.d"n=K8Gf: l9(;& l$p=13t04tK8+]V+M;aŕSn54fH%s"n$#ԣBYg @a4i].t A#PI^V sek͊b($̔_+-V J 7BR?>AF]!gtQb[gIB /_X)wmLkq3̀`K]h52H1HZ9&b%'m, $saQ\WLKfߑtN7(JvhR&4IQ&\["~]v7RѤ<]+QnBk]pC,1"92hd_ÂZĨŐ9Uy'#z[q`'3[Z8>N98!7 3Hl-"5=#L.jDгA*EgTc G T4S!7@Xe{s6re 3/UO/ߙNpsކ u@? ϣ5Gq+X^t”R3X rNCEku,R*&D|-LYK,8~t$i$WA6#HF!JK.<:Zql?ն 9QGa)讐 ! Q A2jq81;"a"dƢ qG#;HCA!'1I!*h! XP1iRs"{&zr0s0yۤQ id( "u Ix$i!8*X ۯ?; (2;33=tO>asYR$EDJŨ\\: 7g&4l[ Fqʝ{`LC"/9˅A&kTAPu =#1ƔsẖS{~ LC ̞ !jJU!=, ,;ȧ5';HӣF,O)[EMB RHD>.NiS)XV龚3+灒!c+O2ABuxxr bYUq&!yЖZ &عGny E !0݇pT #QGJ57AѰp U5&&y#YTkʉ54Z PCA2Θ] P'{l ֐"sEě/ 9(>d'v: 'ț/Sm\nM5 eS Aa:X[9 i$UR웃H)\O*h+4,OOhY5kþ_AεKH(4)<D21XW4WxC:+-EKv  $ё(ӂы HAG;WDeav^ڍ_*6tbڊM >وe@{bydHy{Y"܉R($I8ɉPYٰY$&0|G z g G19ƛ 8*F1a|D.I~Gjd$\00Lp9"v S' lFC)D 9bs'2g UMH㝂y9[B~!} pC m㎑$DڀƜdڌMWUVdHƍҩWI*Ɗ<H"4_l_l;4Q6pB(XO_*XOJ4DF,d$a"3N uX 9{aY\C6 }liݐ4 \对1ؚrXpSQpc 'kHU.!6؈aZh* . դٔIf?ݡG8+Ϩb`e !EеyH@v#[Q$ 3g!\zA$%EdK'2>ZT ЖF\l OrfYC )f)De'};>NFrvAk[S72}Tԋ%,ᥛ$b-__s`2On hQ4S43ǖAh3Uq/24B6&K+3BC4-l_`7H xhOr/"GyYa{X'|DX;!9ِђ)$;uV: y!6(yc#~? 1ipR6g-pq*86ӞDpav pfv@ K3qM@[.͐A@31dɝrNɝ!ET zmPfh'3 w1p]I]N!͝!$ܜ{]'vO \'0hue0}f5vb&CLAהB{/e-$*[p8@w,_+@(QG1D_CA+$D?wt,eRA DЋKS.M j@L",=/[_⫃}s5n?ͷs{pf%d?%Lgc?dgm_ ?7af3GCEgt:G_n9ow+;~=PLO ="P:/¢(ÉG`1QQ4̄;02@Ca/rTNt5I{-%F, yUG:+OR*1 5BCWS _ƒFRkS\aNR4h'T*PBaEM,ֵDGqIbmc5'LeG֖cUE=4."=#32tG#2\ 9o=Is#]烟 bXr 78 H!ȞDj^+z.h "LXD9 KmyiX.FG>:ީdɞc֔f$A1օ{CpWsH>qX Saxh]̟8ktGwҟP]\/%_R7 A:>NV.w۝+^ V>?_cm}˲ 'rbV^5r.Gb˜R\%&7A9'q6x1_mbjی%Fd#bl ";(j-5/"[i0&Lȸ̙%e@ΤE>X2bfp ?4^a l`"C"TtŤfpf$lRÏ_-@䰤 :#`P\\m>bj9M/9S_D{/\.(sZmݯs]@ TkzoNƉca; A%߽9ݽ-Ժ _TM]v:X!k PE΃!hQk}~-%G !KJ)9;w2OøV]t`0/˺\ mwqY4L9% l {[]`RvdF!$sP>)#c*$$LWvلnrY{(5ԛPB4Mܛ@tK2_m_˔e`#{Ifм ɿc}\ns4\<&/OH@:?n%Ӫ1ϱx'd_aK+h|-%w0 rbHU q㻛t$CJ}t NcKUAjnP%ږ~qKQ@꼵nlLN#ÞhA?Bhm%Z v+? dbF~4ȍh-4ϣP 臢F`Uh!0zf4ʏ_7 kV ҴRkaQ60%ϏL;v4>ǗcnI߯ s({zyb6Gsx?6L>G||cd [v[on<vr'~% 2IDo;qƹ Xo‰9)Kb)݁GlZelM1`=+4hAQ= IQJ}Ol2V8WSaKARJ`Hvm9'#㒶cLJ'hln,,bbB ,J80*|T!ơG޿@ PvjVˬ)*IHu cpv~>#&~ D'y IKłR>~P BKb=GFv<"}0CgKp9'gv#@/MP/Nvpwe*>G#Dyl^~ 'ШJ ~6?oD} *we b@s>pGD 'lc>CD`\S_F&`OD@<#g$ځD4(lMe>lVuDFEBτ^@#4h(d9v'v/E̊I(:S疻&8,f,n@jpnrPe`LKfI0.+'4D4KbtcME)pIl(de&K rhoP<茊Ͼ.dgh rwehbNVҍt#'1JL *S P0M&aQl=l9@oHwgbvL9>^pv1haL_2\7KJ95e PcHbFQG~E.0 ^.lI8JIG-C&MrR0242haOz#Bhl|c v14/܉n'Ȥ'Ee.J^ M ãM$A"aHh*=IȎpƒpv'ڄQ:$$PB!5d92bm"+hn0a'pȼB-CF,NfRdKjn@k24NNɺO3I>g[S#_<]S샊d32*%l]TJ[hw9Lo-(H.4xnd^+(nJ):k*2KF) K,fVkmX=i?DC}+N i& tFO`+ Ãcg$pD^T&L:;S[#7/W$B&J`G ]SFLW~Gwoo ^NvfKVqslaUP@HڊN=ڨHl&'W$>;AeAC4v.>qJnUn shm~}E5S&Q3Yu1/' }<'s̍[9Bpc I+rڣyo&F&&JmHfd`4~#%2dVjP+*lЂPq)E.BA I À8YOehQTĞP` EK恡3 LףR20'{䌇maV z+׀Fj08 ;$K*MurIKO.*}J5sKSV;v^ǝvRc}K*WY:^Vj !#KV\sњ\&pqB(v}^Dh=Y'^ĩ\ËcTr ش1Ha9'(p=(>bHw#ǿęUJI3vL(h|0zT9B@GwvHDpŎ)I% +b@ I\RV!gBkɊ\+lFkP}歫)lWEiYQVuF)`Y`_@f@Z >gb$ yT0rq(^ &QY60D;%G}; _ިD5{hz;Jyu~ :Q$KnǴ@Vj,`a.qD\>>@;r9D'oveau$h:c&BDyg5ЧCa7$cG۾~G#Bwڄf6_éLHۆ??( 9vGqf;&;w~>;Kafe"-K&K ᫐`dƾr\*J )&),"jrlG<ٲF}XcPTˬnV,iI*8 u~ Tg⍁AE}t\#vC&JbwdTcT@]FW5}NznJ3CLc1X\Aj=CJ4~T_EM/ZƘd ]`R>;}K. ëYBIك[/Y>;<uN)$)r=:D!(Jd[=ٱ6$~>vQk50W3sb^-;F!M(:JqYYx?SY9HAP 3I)=?•WJV5al=)?V:a ?·Cׁn bq`v02>] ?{4 4p'Mпzܐ/aր3:#>bWS-8 sё&GF(8.#4 ,S"TTGėFI|#"#j LEUp1\Z  Ѵ[H6g2Tܴ\{Vrմ$s\ z56훌8eNqpMD ]W]l⇎%M pt %*B6ON+{9 Yb(4ՔXaf{Q̷H M,GJ5AҡuPj +Y BWJX$I:R.ܔPHB5ZB4'4$[ p? s/}g1[e]3hF Ν5XA-^b+@!ItWDB&.EtĎfEP ͇6$]zc׺hBl C8y!8]!G8›W͒+{cf*"gf.J_mr˜uA+ YM? WkR}ml͠+sMݽ9ߜr9'6.2mm5Mi\@~ 9",K)0&{s`z`iAGG]=R]u( M;?͡IGb ~0J1Aa݌"mPbA{ÊY:U WV 'ȨUL,>yHL3] !2E#!F׵__زEPW$d՜ `R IuKIDv+6ŝH䑬/T#[ֽǹ#^姈KvCg/EY1C6aPj 0I2tӷyJ n>Tփq8'k\Ay[KIb5>c=̦fn<|nSl`\6W44Ӯ9 ZuhW]e-xuD%֫C}32 vF(. u6DOI˯EQi):y0 bL*X 0J&rՄRrGb& ;`$VX?tVl'A 3%Q魑 \0?k5KFfk7lj$N@<#dU#ܕiԭAj"luUoM o:e&s{N.W8|2ؚ[3w<٫p##5{ǶLA3_JBk =+i ݠ8r@_G %rɜMt1\eX +19risT^"Pj%Yg xi8< rC{UlBgPh$I-X3ۜMVŚeY:d 66{x +|2X%Tc C8/{ ۆ&Yzg{@fͰA [7zg \9X-E14X/  skK$Exb떝Ihf:"t)x!4\|`j$f";#^RB ܈l.. "qLLQ.@ ♑" шIJǑ# q."1RƷA6"1 p1L<]_";j~2(!4NYӵ""b+5[p#1x缐$jegԛd X T*|>$$2 VC9$6PLі-$TRZ_zT/(7%K/eA0؛ ͜Q ǜ}&ZW9kԙүaz4:SYײР9] WX\j%"!䧉q3RIH2:$t|ALG*)!͗ɖ|8 ;.-PD@NIjdB  ^=XB`gٞGxĄWr"/O9[# ,V1|%h^5ێn>t[ F#"i!3HEXQ@Wr.A ]y;= ͉i}ӕ6Oj -8ȑ2យk6vMBu "%smrPMA8 [\ Iu"kYxʜbp8%I [-:)#L(Ɍb"+9~.* -[KM "͉L*ASy#.JI$ő7ƒLz8c.CZ I䵢"ԭ_D*xc}ad{;4ml"ŭEoqؖi^H,PFcݙ" W ᗪEN̈ .Q'*Jz"PLF[{XKm{{gvrC C]5F A7ͯa@hhFQBfaxȦ -Ina5i@ЄJ률2טgXPO!x * t;CQdfFEP_29eA3ܹTS*9Aʂ:A6su-`OVUy)~* rŷ^<"èNBXldOҸ!l@X l Fk$x$؝_y+sf ڧq fްkޔH89dfU_2֖_N﫼qf z)4&Dh1IFF爒龜s& b vuyKį"EOӛ!9ť':Tht]&Ęa&6~Q4  i ѽYT|xׁyAVS@ qLzq`rH!VT8Sq3vd0[\y-D t:G/dR''s%: L!,$rhL̰)CDd`E!痏/Ea y#Tp:]+B /Lآ֑C[M1udiΈnakWh"+j%V_af^o%"%aMי|@`sEF~-sgo0v"Zk@QR@F IH̎h vx E %Qiv&e|"-)Ajƽ,sU:%Ry"Uyzw (i)k”jo ?+""6t 'Bu(tPBRl1,H5 <}>J 79UO-ZO!P"_yz ͎4AEa\/g33DMP5Wju!Kmnpf@x΁e=x^p~言FAb-;`OL1_|̣e||BK6vEo8Q8Q8oi_ܿ4x [Ah8}w Άx1Pa؀Od B_cO. cO$v9_9$KIqH:\_i7D!T_#GiO5yQ: WkOu?v7OͶ/o\_OuN!_#1V珤w-:͙<9hq MuV+%hO&?;Dpk5?CleZ!<~7BМ.~705_oco3{yRճ{6j@l 󊐉%BA 4P/Dkʲ-GH@/Pv7GH+?#91I'1g~̱-K#A$) )0<'&Ƀ23 âԦ s9N+b/1 MQRϨPG}4,{QRUZUEG ߣR9vLZW ҵ x%fVj3 !CCUػC&XN|A' !0H3'a+#%_y1&TD9"kR>[_v0/HIY?'}CP!n̬GVڱ٢ F@e!S\|9?ܑ.ᜪ`O%:"D @FD5p-u)L[a:8w* d -on5~L)mcaF)p !g-#Kiy?|_$Nf?;8>bջwGxhtoPӺ4"`UU }?O5@)Tρ*e8VReQyU%A[& $ 0@՟ kaVmM"E"Gg<򷁰FѬ XR}@fY_Ep(c59&ǗE`,&[Uq%6=k̚v>#9?cѬ0Il[ttgBR(y ( >"QUnz~Q ׶)%<ך0l«9<,6rfljm3jVaDdM^.Ш3E@O6 !/d$92L$@LD&b lTWQ?9$iQhL"2w kf( HPL kR~A`^Mvk  m.6I*g8`g2pDAn([+pN+v'.7-zvbvjoքH ;d8/ Æ5{1CT[j3`g@DB5} WbD %UA4DyiC#|TH ;&Fgsxf愊Ke.jRiP&€x3DLCD=H>̆KE\UyPUŞdpmD1o5Rnf+gfqN:30 ʢ4^ W6އʆTF^/0 #:fP%D:a^ Ȯ"j8 E b0_8#e" ńi+̬;okgP 2PxEQ^ 04CZV%fԣFVq$'Ig{f~݂V7~h)dZDJh%qF AzfHfg j1K%ny&$lc>FVdM\5dOHiLCr8o(xopVxU9o3$;LCP*FE9YVgF\,{31ce53^h_OB%S*?oFA ID)${#D<G8 TtM}PDBr>jhH2؍3(&nC%c#Pe>"f$e1S]^hdB5%SsZ ԭSa66 j$EeH7g75 'Qx2^06d.5oEJeVWAD=?'8AA(O^fg3k*07rJAv ca-ڛE2B#EQqF[fRBBⶕ~oCltt>6T/5G( U.GQΝW3NZC q ֔MԈ=DUrMp<;2M0,Vo 䴡UlhO-ش> P%VƣGE Tgޡ Rn@eGo{PPFGCEs@Pf6^(_WMv~`7f%UDq1?m3_WT"j^SX'_F^x5y^%9MxR3l6oY,m's`|m &LA7_(S5vru38GgEVEZY) "a~$E~Uo1fDŽ}$:9?Sg7 G~Ve Eu3f1Gl4HnHUpH*>=ND pKybT<JJʢLxńTfPnO| xR )3̢WkCUoP@Jr_G{[h} a`)9@]q4.`&_U5_W"-p-wdeYjcBt ՗Y"e{@ Y2 ֠M/sI{L| GB~Bf$piT?B%`J4kDZ/h# EminPfHu4u>~Ȍ, XXJIcODj|rQoUTA`FH}fLP 0K\x?WdkdT4JxpzNMǛ%PՙB>KKK$}POG'ʥGܨT|TOeAۆ<jEQGd ή4Fx\Q%As=<qHwt4mcf'Ud'aoӳgT鵵՗7y;_Yh嘳dJ&UbU:Y25{xPvJZ|c>RRvhPe}ZnxD:FٙMݼ}! z|`m2Y%ntfҁTUN4E8g!uaAZF><󒠈f_J!Ƥ?W{{ېrkHڭe!m Oڟn} RLJZ-ǶsU6-֨P􀇷%.Cɩɉ${@Y.\2y Hz=P|kMRh…k8=lJގ^PϞ_]u-W 65v&K6*Yf_gWo;q3 {kP#g~r¡O…ϦTUf&5u@jf0@V{:K84Rv4z F#Nm+x4GuG@>BK\,Aq֩ cɋ-=92];]+&HJ AЗ$21)DL/m^?˒#Nj vX-y5 uP>t@0dpL*B`i1 A DP7À4S$Zq_Q; FWD {C0!Epz滑D<Ä7Ҩ߸.0ܷm29nhk5VROgA?$T!APE ٵ"g";2!EQRU[G;t;Y+X#1M!C:Xu{R3 R3l, YVksj ֿ"șs 7d?w ^rd'^$ sFH8s2i0# &n&/ʟlF0xʖ)-Dخ0'g',FL0+X-3eĠ&V'b(y@1f0 .*g:XiZf諛Ӄk6uoW=LcG43pn5h\,#?+ °, ?\ܴ?<@[Ý,CϷD,wDGPsC GTW173#xRbֻNZ4umۃk^Gs v@9"_ڮ+_^U_Vܰã6uP38Uy?o `Wl<dX:&s_ ⒣RG©Tt)U$%m&˘X!bć6!P5ZmԆ0RipS $ĺ )}.bFM`C*dجZ mV256n3@fٰKBLHg"R,ZhjLE1+S$YI30\ g& ZE*Jrc39Q;.Z,XZT%baKbu^^{a;Z=8t:fd̗14 ?.gɗ?κ7 &Θʆ\(;)<F УDPAĠKjq g+xhEwn?S?(|_݉!/G)ɅVcN毚5cy๵1 MG΃bguMFv^CoCpeR(e0R*].x"oiSu4R&}bQY;kRDdOj6؊{`wYfڕ{Sjn IviP pwl2rfD.xY%xeU2mSyd ֙}T8'-_yOʎ?ޞ8bz0s>/PH"f9߇fAsl(zpHV*&XeZ?: !Wqg&ku*ɽGpoFSq 7kҹswRP,_XM:yꊏR*P]3qn m՛%کXAkxޤ"K&JRhͫnR/G/y0+o>zNRM,1-bFD928@h b>L.l3GLa4AG|1]M-"#{2z)R kȸB눖& % @88pDAY)7CD{Q̧k 0{0!99㝰tu19)*yAii%1Α)ױ˧B!jx:+ٿҊ!(Ѡ/Xӥ0 ,;HD8´BQĈlJCĺ8b 8?QUrE(T*8s/ 2K֜=!<SK Z< MA+A Ɗ`&g"2"2Yi# XH h錠283#{acޣѤYuX>35ИGH%8!YÂӇAM*W$qB ^%pxX=ۑY dm &Ә˛ 0$CBS'I v4*QDP:L-.CI%$+ C,)v3/jl8CP@BLx h*2 YT<2 1DZ$Uڸڵ[ ]ͫA̖\ɪUDm2r A `N[Y18 鿌NKy6U +1R,mЎ+1`![! r,yH I#͌tw #e|t z 3 C>\ɚ.$X>v d@ IIԞ V3EIg0!iM/@G\iY(\Xj&pħJRJ[9ko0$K ̣),D9\1%m.Ş 6#O*Ib/hBԜLETZL+XG38Uʓk C8V7qRYTs8r^DVnV I+l4=8p8lGV=DŽ#Ab%BUCˁ3,f W HZ#=!h HXӛ!`ݞdd,xFȠI P)Q+P "zHYR%נQȕQi /p; AZQY%i Xt:#L% g4Ψ])aJ`ij Mʥ75Jl0!:) QK1,'9!iBwL+3 @dեnч HLR^vg28Kބm]ڢ2Ih N3_k E֚:^ 3Z!:XZԂyJ6g5x!T@E*35kp@pW[@a)!,B*$mR"ݥ=C>~ jWê\ La H )2J!۝+9eΰ{[n7$۬[ڹCEA9;\㜻8^dcMĒƏf{Y828ίG ָ3RI~溎>0@OXu%= 1+hTfu?`I`\]G Y`ph8Z^_aZ8VIwDN2UܱBpKoG/oAJl %& 8<p <ڸivq Ѳs YکxAN)3jdΑRaNx˛dJ+Ik1Q'mR89~S$A_C aEi?P8gF6h?w)#3&) ?<&llH}FRD"U}NuS(sY'3YkVsrU4*t[9OQh Jq9_2t!_!s٬l i_FRh4`e:'en7PS801wC q9=^Os| {8vO/Y,(2 껦 j/ PY5$h8GyL "L,B䜠('KI2P[0#,bÌzˉ|Sp.>p4+C?6hT}Q" QTXSM+N@`C( 5;ZuyY{VG:tgc?0A/E?<Ҹ.Av%r܍;X'90]IQAH}[ y-P,vH@1MpYq a揠>pB'H"E&N5&c|?@?3#^RtUyIl,O\?LFh:X=Kax@+]P k/5 _NKYl/ S j)5B-/$dҠ]/lDPʌ0'Ub,Kzx`Cr_I^+X ^'_P X'W#JF@ SYU (<i$S$P4 I:gZhm~N֠l iDSlmNzm-5vL8鳛)jw >m5c۹@Q3:\R{*dAS&x^t6fbVK u "Ѳ82 AED̢_ё!h~y($"T Ҕy(E?¥CY'&17(.T`U> j ^'.< N$45ꟾ ^ktMYAe)u`  *ۚmzE_TPMY+܇U"Ї!#\Wk[:+ ^)oMiڔhJy}+9R#-*e`c.,7Cu q-ĸ3t~& 6}M17 -5Z71<$?G}kzA+{ޫqlLcL<%/Abw<T_5EB8!Rh]U&C#dCyc5ŭ;Sx *rg@z[ *(ힵM£mkbُmxMvା/doPX M%``P1ʈMܦVemٍ PՋнC $ 6G4x C C `2 5 -l{ZŬbRh2dŜW&el)Re&M"K". &䮦:<ɒZnkqL5>pFk0:,ivm.:n 4/Iq81`:k7O{Bq,v1!lALT5-]BXpV0 8+!ΧI*LrJ~psn:{dO%#,~lC ؋/܊gH.fkR* ? 10Onٍ i[#$WyRC#@&rSpq#Tgpfd,R`J^N u$XtI$+ n*n8ɮ 0yP܇ܒGy//l܊0!+Ɖ2- :K 36BI' Jn(xªC&VBN*D^"NQ1+ >r,*S*6F.iGB9ޔC8Ʀ6-9Ï6d,I4KAAUB&*b谚kԀ 2(C(*,G!*&+8FRO6+wmPU ~,JR >g0 s&kl3'!%#HP, 'm C2ry4y ry# '0 u4PMMpA%PQaLDtIT/JRv03)b:45U4tF0. 2+V0|͋>BY$ǖ,NGdYx&&MYJ,`(REP+4fE[qO:Ⱦ:\5;40lRl<&='>>\pfpf?UnVŬ,EW$# !62/–ꃃOf  $nrYE/LD'# b4+C+Uft'v͎&U DTt(Jhs3M+!>#MH /(M/SV ;m"Nm:m AT5Oo Q4MvN3 kBIĬ V2G}.NL  ~UPB1rMuZSձ44MtMwm n'!xpbM`bXn.5*U-/VY&^KUq1WUV;UԔZk5uQYcG{[׸Qb8053<>tv>~4`rC&*мNk:]Vn&2W00|&[JW.M/GѱB!H,爍h.ZPx,ʍmq'$rM27WUVf,2r2Pr1LvOOVs'pMp0n*4OuuV'Mo,@ܑYT ϱwr^/K t+ԷxKUrp(n8VMt2x+nu܍p|kFwj Gqnc&-G$Jwh.0Q.GDUô{wϚ:WӲ9Y~S]su֗#bp<~&_,E =yó`G5x$Ȃ2!)!ZZvCGg<w6S3r[r'zd.~ >ʧ-,GBZV ЬmU -P1K̺*Y;TQ4kM^t-/0roCpUAMwUn vnށ/fu upn1IHj;caNLC#J혰 cIR+M OOI!/rXIN2g$$Ҭr)hv,ewvj[Z]'B.+h+ru47:7U~UQ[58hk}<p8,"ؘpo kۓ&2rLgBa-p x>ohf2Z ~rE,KYUvLt0BB>27 y+:{ Gw Ra#B%b*loUUVm2bdpٍDrn6к!V]2uop Ovn6д4!YX&Z3a6W%B1\xX[/2y!p ȀI-r":󺙣VtpUuuWU!UP#211yn2DKm?WfHs"]l?RAdԝ]?Dza)f^G%iPA?@RC+Qj}]!?5l=axTH1۳y/)?ʸZl>+?yW+0\Mt?Zs`z] w_[M|B p>3}ɠs ]?֝"Ĥ=Ca迵*?̋Pe1,+)Ap' /(d6űT>@4!1E']^qF8G0tq@!A{:φTHk oxlA]@acXFAܣ,J#IT.La0K87g>tP'FP2R@APS5CҴJ jRE]BEOF5E@U^U-TSEU=\Y4Cd]RUQՕcbUvjvUm[UN\ t['1v7RՃw ޫ2zc]jڭP)VR.0F@N 2&&(xGE8 8ڷGFNSqM' hȧD)'Ӣ^é8דe6.1~Z;ɰǡ8R&<%v y1DU-Zވ"PU:,1w]+:6=rO6|X&Oǃ&WJQvmٰAL?~) pQNyg='ayXzORm{nZ?VXV?ߘfC |% AW h!LKCH)m?D0Wxѳ (Z%qeI0gv Ӥ) +hI m.n'HjݡtNB$ yp!*NUW*uE(YSH"Xf/(UrQJ5(8֧UT0Ţ?U DTueH%ThUrg5 h+ -%P"7&$;|z(wXrQSҹ20s+eۂZX0H2XB1E(%Zip䝠l =ͱ0(3 9\}Sqʇ't(G6}X~aq"g A h3c]-4'sXl6C~S B'4l^ ¼ iwу."dT(*0%<;SG?꠯=QU(j}Q}B*1;^}WW1%kc_h: ԵSfKa(q36/ b|`YUq>O'knۻ.m*&]Q5ҍAbCa2[Y ,Ggyot4 Ŋxz0,"$Zh_ t BpHC m%-4a ]JuCzU UiA;uJ_6o]\2hؠ`Qs§o;He$V:ɀ"M ,{vۗn{yXYlQ% k|'9…Y`Fwac\IGegsmz746'iYgͺ;}AD)Lᬵ,#Lj 4cyʞT8 :]ſ.剿HhdSՁvlXOY󽷝,1!61rSiJc&Be7S@0d640g6pCp6cp k@&IS@w¢&ŒaļCKʌ$ ,I!,;ӁB8 j8#;ZY(Å(8I)!!iؔYFyZk{zqH\:+1l$Cj7{:r;zr(Dqh;>+lH:C{SC"*}N P.i>CIu#Z!&A;%S cdžoWISײ s$x'6Qϱ<_`72:;@ߎ 4!kŦrlX%pŒ7r4]UA)a'DʽHS3ݧDEK8D7l`=`LPHCԶ&+mlIq6ze@l s =>VR0.4PE3ԺC=F$Y?L *2P"|@C/;.8z& D"r&˦WC:LM̤G#|A#y`D9are"7ěASM;$q͉ۧT#z*@Jö5H:I4܆KR:{Cz4S4Y%2?R#|>L!k :ÙRL:D:)Yج:W/D͹\{Mq>dպTՌģku:z;DDBn*tO8`;۷m @ll`RP=L6ܟP^UlRۻdXTS ܌K͠tP0HEoPS*;lm <ùNcOzX3UAx7=H Gݔ|(U3Ե[Yѯ%-=FԿlnNc?4g>ԯJrCѬ?:q=Y.6̕y>=Sak5`:WAWD3/sD@qe:]áıJ40!g/:|ED)!]e׹8Zd_0Ug`eXfQ;#O)4=J öVx8;V ߨZ]yϴNňQ;2[ R ѝ%J0̏o J$N+A4A,l>r>~5>+EbK.#\ Y2=3Lc؃`=M I0Q+ϿTQE+IoxY>-AK?3=4 i{ϼQ3 HF+$nFIlcP\rxP{s=XAM=:XhUO{HMA‡O$KTjxS )cIO6NfϾ,N@ƫ l%Bҏ:C]AHHë.]yJO".*)D>ekD^rEnTf>0-_DMfC;#jְbh6gKq`6ߞDDCIƩc^o/$NfW{`\~%k+s@F` p)c@B£qR3-Q-[k;ֽN qY@Neo'Q+2E^N'M]=&3,% Y0Eݰ3'U٤ `Q36=gAKd(3eC=46G YX=Q\U>zhAlBSEKfGE CEN H5l ;mOuz&d )]]:B, 7ƺE/,9ZU:^:gC:u\no,J0IWn+K=43cNdroh?Tg8M6EEd%>8 ])G%U:JP~=4bc޼)Cϲ$؃/HQol#W1@CLNTU>}Tb+nQJәշgjޥSo}Vm/N^ooTh֦@hi;Ǝ5߼R)jCq% 5fqzփϞ0#Od?зv"OU[?<9_i#'QH6L_ -7O/?7?aP5?Ե:R+Oj}?7S_c=o.Uu^p] Hl>iS?ӘV2MdpOVƧ39ҁ?7GLHj_]c;:E)RiA}\Q<j9D?GCԤ:\4Ww=xxm-)i:cP7W٢_tZY,Q@Aۨ g 40Ð4,U q9+3B4G|l6)D| $%%$Qʋˢ3 K43)#55MX#6|s;!?NABГ>P(mnwd#<,2^q+ 2#@u-#< 8D׹)rwzx_`ܷmfcվ9wZd^f^3>Ey^gz-}1F yK‘*_4?vړ/:QO`DvY7rN L0de6CB(T CUbzME)S]vӼGZ-NE'rZAC آ°ժְiL,債:Z1cƅ D!`xȱ"!>P .6آNJ% YjNJE%iC'IٝCe7pMIO_7%ͥ93&޼\aԃJSfbH&@Gq N^b!L+M AA%[KmНͶW;RYVe8c̨(QnjYtntй@Vv.AHn١BV@C4uSWi)#×lzS9ONSvAJcף΢W);̥ҝ@)oڭpę\CXis4yHޢFE~:t-.W!"0hC)'%TTSPOx⢁J*&'ʒ*Ub&?fV1̩8݇S2dXisOƪ:`@vTg{Da RrR:Fإ HF\7*w,My?Uq"B?=KNr?ApEZhaMev 3ӽxnV#!2fnm&I3j=AID&ff@2APJQT'F6Mp RE`Q@EeV\e6ږym[%ȒKhH$+`].k@ER@< PXAFCa v'Hfb.Li5ڦp AoaN Hұr Fz!!75zzl{Oz#j(r9"}vGY:̨tN`NTm/|;Q?UhIs/IIcR\X@+ei.@M4/B odXW$%gp D$.UiHU*V+\V+iErAhvhEi$Zk_"^XR3)2@h1?v|0)xm`tmim6njgL!q'!n0r!=KtpxE@(N&SCk .fqgTu5B^7u)Ev9X(1롁%k I>!KwrJ3$o".׌ hm5{_D#czhUպ!1PG`T{Jfluz8:YrG]Pz;~ DK.Ѓӟ*;VpvI?3<8 #VCVz0C sǠRpXE(Mdx]Axч%EfeR1+fZ퇧K~hXVR舶TxV/M0U-d$vt/:&r(tr5m\,:I GPg鏐pglJqm7lLz8CqP8ֈr魀srnfp 0WW/bņvw0IE`boL/D*lni)u~C~Ly]D~zx1~x1TqZ$V#5\#^^|,>;)O;CzY ;H1au遢D5SpmGMHIp<ɢ(9>>RVRzTUmZ:XZL͑"bM!婈('gWEmX3%RkE/ƚgVhU8V֒ +rCIJPg,+\*F1zU T1n5\r™<\Uэ@W23Q {/,Zg6o[l47Rs 1nLrꋌ uf"q7z)g "obDcBsk OYzM]#}fc~B5}}Zz:@;'#a({;&i`ہIYox%܊/݆u9n@h8oQTN)pIMwc5!LZhVu1jD~ƴl0^WlZM i W:l $w yhIk LƬk*7 qka^oڦjء~, J\+OF!Îbt7b)321~NK15uBl@qll96d{<ې F:{Jt`=S[$yb99Jm#c\ݪ7C~{Y>=ڕr]H}I|} vUx181'IڵT\KEYCk^& T A`S b?ƕ¸=++e-{M*K[;uw MaplSN`cfMiS#6\nv C?DMz'C_w>YySo?]w,+G-[`NNM". ^°2HCQ(p%pS[AQiF?nRgvRM7iEH%R@rL@J,.K$$ABg7$&I#~sAT6Md)DP EPT,B21̳ ;Tu7<CPJ*Jd 9ICKr#X5eZ֕s\Wmt\!]5 O_WDKIhv}\W}l*nG@#jX!s)p#u/G0!x\ءɽ_7:] *i㤈!ZN麕r&*2 V&ɨ OY%8%ؖ%$} MT%k4+ آ֚ZjgW.$k[F& g9&;418gCAE;Uiq+da7q)Zڮ t*ZsxHVt3ZgVZbwٗ]Id}TwyD% ,AW yZضXECi gypwAT B=V Y'5&7ՍȿԺ?!_xy RK dc rsD8=A:zK:!RbT?W~v $uVJXIe"eB.pCJ."-"͊ b5pV[.ke w[_30y0 !$|vtOr!v/s'L%X'bDB$XcRM2I&Y3,%}XTa'f̏9#6%02p#e\ .2m< ڋYy?zk6^*A;3Ϛ:ch9Up[Fk ibh?ܼ *w!VJh[a-Ig<[%!'0[v\Ddى",Eυnࠨdк^RRZ~5(^jU1qBZy5uPW/; &eA jN/ lQghE _KVRG.&C_a2Y5^ 531th5Zyի D|/[`H"˭zE 'ENR{ykd)*l-}ȒNE5!HyEICehVL~e䰨') qCbQJ{I#dѡZƺgЧXH _$eSGQ"`BCsv GiÃ0a&nKz yR IÁu$)SÌ{(ƇQxVcIѻz)R)-;FɨY `Z,dqE",Vʈ%eJO7|ŊɾR[_UPh'V*P: NTާ_IV[4& N%F5RWӷT,;DtM} Vi|3Z0}첵Y+M؟0˄d(JѾ^ e$z>n(k5n ~7"n.) 7$ܨ ΒqY\&.G c j5I5vJ%$M.?`2 0VXE~XġwcGxaB`Kagf}Gatx:CXUj+ZiTiir?tnP U4c(;p3yhw5 +JqS^ۭz-޷H#񄮚ෑh$I}|Y$L$7~iu{r/ $JDv#,1# 6 sB( xȘk{9&%8*i7b 8t2 خ$4) y1#&A q 1|(Cۍ&k_,Z iQnk.>)J`y“җ`J 3IN#<3ŗT<ZіA3%*҅\#!XX RF]s柁"+:s궉kăf"J' >3dۏNJɋ0!n=' 8ՀС@K;ssu85@80w#rP86@8y$rI$zL }r#Q7 9ZL ीHK003 H(@&0ɯ(8e˫(`ۃ\Ja',@ 2 6L;(q9HK̩ ?A C|M)[鞙:b|7)d*S Oj!B1*E2\S;DVJY#ϒZNZ;il2BR *! !2 ư"8m19[JR[c<L6ב2;G%aOw6h1pj2H@HQ$ P t sv dӊ7Ӏ0 .Е$JK RKRT}K|Q?AQ Ԕ )ҙ'˜C wylĒ#U U `S*{š2WҠM1p3U<U׭a6E~'qIXh…ʐGZY piW+sN͔zInpMt1(EψGTŀMwWa\]W,U)Z2[[# .  Q9BIJPTZOQbIݖӂ$ $P( |Y Na]ƺUڮ3)TPݴ:Ы=,Ũ"38N6(<Gxl [1&@cN N:&ELMP& VQ ]LYbE(Z3; 앩9-/[bDbrz+qI;#ݎ Q+u|rjOIqҪmv{UqaW=lg9,颴mi~{x>?3(#h99zI}e#SsHJX@%L IY UaD 蘅rT`ݎA 0S /?a#`ua1Xd 4j~2) 1964'ԠcTBƹ).c#- :dOLKDyDg ұU6Nݻ:KA-.j %b* 򅽂q*rfIJ"yBh!4*l*!qQW~_׬qW]}4W|sr.GVdZNd:}計ΟeJi 3i| |$qpbHXv Iz㈈\ڗzؗV IVI)v (+⸓ᝮ[U;l=Cᅻ ;ZkE b XB0/cydSDq %w\a\F ulm֕aX D Y: :!YA=ҕO1*XPm -jB&e4^{Sui2b*U*n,egkGuygEzfu/o&zzn!_&|?[uvVh0D(\C"OvHqb9 'Np;zIijFTqi7zN+Z+N+ DR!Tv??b~A b|BD'8?"1 0պ[f[P/&(^ YċM,H/ F-ݐ^)ċOln=_ln]1<ú?AVY;JwE_UtN(11mJ tjf` eEh)Guf,WA+sc?uB_vg-}:oid73]ʱjv{5ԁw#b[ ow`hb/nم ōPvb}"`q #"቉MH#q}wV_hC7 E'?w4G_yA#$LD?~dM_;)!fhЉ*A4S)SeV[&*$LmqL\IxHޙ`&{ t2vg1K_m?wUXHFQ*_}sTl6JnCq(Cͣ^H^M?]_9E{_翇=?~W0?3P'?9 A$<90AAB@6'J@5-\Es/A'''KTn !,Deȋ˴Nԁ'˝*F1K.L$KĖ@K.,sy G:D> YT P  0FhGԅ@;Rm+NE4=QNΠaYUgLP@yWS}8ud խ8 YG 03PQUOTրV;DUySZrV=1O7]`vW`H@-aRX|SՆ^GY0)GP9YȚ*fXXGBWfq-Ƭ$DẔhk#/D/줁 gF$1+r+;Zd2O En5VS|޸1mߺ;(ðN[6R,Fl܁ đ7 P( >E>DO[aL+C}ڼ\TS][ I,qhRF$12'4*H<>Ҵ2B|.f,naҔij_PJ)EߺQY)S p\ (@_ B$W" T?PS*^jum%:\[(5( uY/0$T:^(ua,K-вn?´e4-Sb$#(!G`ve +NHk+B"p';=y4^Zni I 6_ZلTC(BK (w\Kcxn;q^AD̩9#,w4f+qED"6Y]ɖK(uܣq!bxzOIt[z& 6$ОB'b +IpC^Fi;*p<<d.ҕS Re> r)HVP -HQ}S AE_`0jh9Tz!`nAVv%C3"jhJե9b f aj W^@ꎲ*ŨL~H @ = %-`յ~XgV #Z` dړ9)6Bc=oM4< '"5D_nIi⥩VrRVhGjs").nmUK.o7aLG7nFXL@Qks35&lM:3&d],suFvٝ"-qS$O`LhRH{T<єfVƷ)ьtsH]wO;?q3WjSz‡4T% bl[0u*K8ж$Gm|U*LmRbqy|Xmyȣkp:t 3KxdEzq(‹8dڛg\^tdM\'\Ebd,qGh<TCNJ ;rw$ǭ.hL| zny#LP'|䀣bKf-d/ P MO.]h(O 弰(Z~Pd,Xe00.cPjEJcUe8 d(4˅9 ؉/:EE,Z_sMT-[%hvp v\1zb *-n`~'BxiQIdiBCKjM+bQ0{BiL//8FhI`җo[`o)v+7+IP{NN0b;Gz,t*?"r":`< ίCN;(D\a Zn'&;O:q8Svfa8be>k6! ^YBKH",,J*{ dH+Z3{gmXJF[21#(I/'[?#dkҷjKPpb;R"<2(JښA#_DvvD"@u+#S$VE^=gxDa&fDzwzR Ve>iuẒ*Z1'κ`{`h:RBWtSSeiL]Ά .//33S8 S*d R65:]h nPPmR_ȬY%,SJuCSOr2(v`%Tʶ2N_Ȭe ʐee99-7j3Ae[[TJENSNjVOCGR >3irb \&D`t ^qk%8֠8|Sψ:mW7 <*6х;M$Z@SoscO<^tR0ά]ZcL@P4ݨ4Ejob-J[dd&Fa "%uFaMk tPl]lI)22Z;SHUZ&KF W=Փ[Ŵ3F6*@f|&n hJ#dž;G;[c~*P$rbX^vtV>0RMcF[%g"wA_g4frwJb/]F8_`Z({J;B;Kd:`꾬:mL538R3FUL]miOwąaJ!^)XOPVv|_z2ce N^PłίE`d #< ` ~`%7"2X*XqtOp/+?yR,+-{6]0[D9N{{SyC/3ØCzBi sg ?@:'L|P Gd~ P&3#IT]+Q*hZVk }'?vWPZ sqYWWUہ`WZ?@ڝV<rF]\̙'@Hhm3;?{]37o$/hLt\Ou;(G }Dov?[USPGA'<,&"6;DKE>=hAplh=DvjCH0(BHsGф]Ȥ")8>2#-D$G/Lr1tlDI3.\撓ģjIPUM9S#/FRa+NRdAF2,)'b*Z}YH![1_VWVy^Xv:EdV%ZXڊhזYZ `%]@ ΅ j: " 6)'M~(Z X1 6%j jڪ:v\: *zVs&ʅڷ"nҼ -h,C2㞎973%sX@FAy#k^$P25F]-M+N8{ˏ  =˷No޻.C8nH{3O7󣣎g8Sє#N&BO/IH$gLdE\+I}}GdDuxR<A9 d毫I%Ec%ʲ4ِ'5h4_Tv) a,: A6PJ̓ZűHJ2KNŞG֪'5](TةCZ+ l-҆d&|ŲxJ"\`x/3WqKZ-y.=Ʋž׹8sVkfmr{ =_)q`zi/Ѻ޳ueÀ8?s;`Yxn??ⳉd\GgdO1=:ݾó !q"꽃<(h4Nr,|%d8<)!{%n9e i8[ +=Cv+RUjsf_#O"dX5Zßg Bkbqr\F] v.ȢO]DWE2 =3Tb.Q35j5;/Q#iF"½+j?j2` 8 K'a-b>+FC3joG G_kޖV-[bo#M8ީy`31:ZW2Wr0F8HT@VSj8ˤ"x!ۚ+(0(JZ,;vk91,{962:S /Ԕb!JK2t'!F8t1A1pՈ= q^!: 35i떻ġi{9(==4Z5,X bl F.nn6W|&;IFBxtq | *3z2suq"vQH@ PH?@!#(i!(+ 9Qȣ%9Ԍ 3ԐzkBC:D)GHۭ-:W )- c9KE[?p>{"*`FD JpFh52dۇM\Cߖ޽ŗhơ5b4Nt /PǀG` z xh{w󯛳nNx}~tLJK'a +'$('L;1۞ P,{{㛒x҉Ӡ)1/$'u)$ܣtxB2y O!`h&Ҋ[҃8  >4̹K{[K 4As?4$ K٫jNE3%:',]99wytSDNhJ;,,hΊ$Ѫ",MB8X$gT:ж#AbMM-U0TO8َ=a԰ 4ayJ RpϡKcxGsG(ZGz2~bOZWr{J H  0A#P(JyOJz l)aArA It݂9۟}!I(5S'#%:ѕU ϙQO]!(rQِ8́|M68= +*r;86,,ô!5 4"TFZJG P]425@4T1k[,*?LZ [8`{Ei̪&UHZL-d>"[j[t`YهF,Z6Tʖ# 'rvob+} n Ed9Fd`D­l&:uMo?*: Y蝁',0%:v9kM<' %%4M䐑pݎU2Y?h© w]YAWn.Z8}{]6S VR3aC`aZtd5 ! ,FaL|~!&I  K,ʤaAHXɊqhճ@Ɏ,ը#8"j̬d$b8@'踤^bmRk5\;+.ܓށi"> XrOK`QDkV`保@cnko­j}-tZI? | g+8^ ʈW,-jufE iQ1%悈Ih9  XVlT!&6_zs)wuJcgnNz&JӎH@Ql6 TR?RK{?;6D 2"h>?@+@o|BSΑΔ/ E+z4." X~/  .(F\U02? p06˳'m&q֯[?!qr0W$΀TqP$BrSTRG< ul;tHsof6sO4^4 k%>֕ܦqAH׎15폱Auf.t҄m"|mHT y3(Ql:_&?wv6v̪TfoZöˠk6Op\5jpZ_s=sBpiABB0@DP0R<4@@D ƯpFlk+#;LGN+(`L ,*Ih5sd6N 7s̓44%B9NH Ϡ]Csu!?R/4TBHUIՇWՅ=O5/IV n5mY^%TUUH]!iӔ@ZV+eQ,) ]]7i ^ Ԣ Cݠ|x )ǃG,_&$%,XdLL/ 7.\+2h6EM]SU*2pȓz#pGGTjI-NNlF޴OLܮrtq}Vg!\$’{!r:@IᨫLI ?^K~D8xrMhm&(R d4 (2[ܿ5[9i1-7a+X4 ͹pLK{80ռa\ >hF:Kv N#rH"]NpCqdg4NtsA-M6gsB"|xxݻ5#(C8蘖n)I c\bRC|E8tRHs@7Q@Z]Kizu=<ߴPLߚjtFf> '< |OeLeNUڞ BtT\OU7Po rNJL=9'Рh$Mr(s>Nib!Ni)?ݻCșbPz] GRiy0#\u GPR'Ie(ǘn2y~bl n 8;]$Zp$'XPT| L9BfEFM TrLJInA2 ̹SZTUZuJdUIj§SقFuӫQuF1AKnaLZ%pIћ4^k?yoQ.6C!Ѳ7 ?jZ\9vl&8iC5nU SnlX S9g ~n-&iXb&j58[j'~4l6}I̺317ijk"䰙gW<|>TBBM7n*rbF1z xA@a4 eA, ܠ A) е+W 48 D@, ,`7@TI@A eESA'q'|h/b)ckH 'ҿf%&C0gʽC9(G 箢#N?)|p頚KGNt$Pg+9Nnt 4?RtC?:?ΒB4@M C B0EgnRsxt f{"S:&QS"- J&2F|T.\D9 yvTs Ftv,x g3+#t֜v?IÌ>:XuC"dVt=4CGOp=*s0N>4 q$}8Ȏ92 ppFQ||igu%cF&.q};w5Wb]sSayHQNPNg%YDgz^Y]:ѓ9ײX=9eZ gb  DH+f|>੝(`'< PeIxҏa`3@͡ ౢCZB4{;ӽ{B8 ؐ2*i"i!&C-ԇ&plmv_GFicT$CW2nvJNn 4K#KiœrF82]ҍk5Ao# `)9Q {q|υTghT{ZW"WWt*@*ck qi6E֒8R蠉eeN 66$]c5uyW[ a b$=F!bbfS֑`%%EyR.Ģm)]2lmI[ߒ56NlE5"J#VAR응YCWkPrAĵGrN^8fDrZ@$+>Gnt::OCI8pp D>r$I5 4!7WCV#c<5U"|JN)\eKۮz6Px]TOכq7{j"ՌUJ8b 8^J[=RӪN`WWJRHv#ycK egHhRCƻ*5k.EjVz ,zR_{_€̕mD?yhOYit}Vl~d- h ]7qPFF^n a>:Eay^]b";+ix(RRO LAKTg 20CIJAEqTX!F1DH|{G\r@%(ҡ -I"Rl'3$# Sd6s8sp@T%34<x#>AQgG"t t$` SPƀ;CL4,q$LUVejNQgQ_V!PX eMϐ6I>v[gyou=w^w+%HAT̶1`i oB({\a DWT Bl8 %d p8c"?` /<*L0L OGc0BvfO]vVBrE43faR,Ŝ \KluG+!@f?TK'Cq*qB5 bv%DȈ !W! #P1A Vafݧ~S4LߊviSʘiB~!'ǼK" H?6{;?d|h|!AjW eEHtn0b?n zݏ(]WlV>?–֠(jxW Q@K#Lk ;bMZ\Zp9FhjuƢl,! cpLCx+QJ,vAl!\ni BH܈&r$B% "G}Nt6J)GN_(KkҚ,'[À0O޶Ι5y]hM%7w= ѵf~_UjYQ'3fG9.R*H>>΀bR'Q@;JG&%Ul->d+`.׭Gtz =eє{V˨=Pf^O%\ߚ_wI2pGoH'Bt6zϒ'%E6(I( vk~`vL4z94FalRFBC_\BD> WF$DyKH;43i#"3NQ-3kƑ1U3+5)@,/$^,@b& (cT4!!l[H4{ժG%GPǛH,)G,2eD".AAs-rDIsC Ź./\Vq@AƯxZ :_:X@#0SpݛÈNˠ'L 1B1h1M R,788!I.: A?ȼ-Q!5T RYUi26f,-Y;t0 =) Ҳydܩe8 Y3I@ OE` ,z<+ C! 6 ǻP>,凡B-Ŵh#,lYT,_PkAխ= X5x(,E7٫’X3V!C zƭ4S󖍘ٝߎW`vPϲ=0ÊP%$U ѯT%SF;9! 5M9(]6$ 117%A :pdZdM (dT/tbq O #t˨5Qٕ  0Q] 2iL)9@4yDbz^,\fܨޱYa/ yTϴ?@\gI=P5_+Kk3&MKF4q '_Nu2wh5qXhiWV6TxOyYX|*\[5X)6;d3iNN/ _6@(9hꃎW,샮B֥l(ZxTj5ӷU7GTQ]4ñҝEɘX8mA0Rӏݤ"O/.SÛ;d(SDY Ċqñ` J d\/+dԳz ~p&UF]yWZI d;a]mܘC VTĥ]͙L ;nY(*qAf;L߼ex$_8^lE3x&X% ! |qnX3d^xiH3ieo3OZp|[? nFbΈwOtP7$ਵTg{Y>=֊w.o% P@hٝ_yHזqDDZOZʖBTlm^mXʃun#!8EoRXɵ!n.Ч O$9I7?99$Zw:0ʋs SI[/= G3idCUEK/ÀEKIPun\uuX\&U&\ݨdrcς~lpCaWgGjFlq91.nOq4;pޙ\Y7H٫mvw+IcFc$FfA-*_D P$E_acD_C+t?3w>tCO_+CM%r?EU_z[kms?ƶwjN[m?{M⛷/;.J C=Qg%ZWZxo=CJҚ|nIN KdFm_$#oHqxj?|;F__R?{?wz~o<_幯a A.y$:`°,Pʊ䧉1;h&.vHp \յq-yDZ'H1,Ȓ4u#Y&3S$H # { œNL°:T5:N,A@ElFRPODETyZP$RML8tT@TT5 V0QU[}OXW `5łU`}]GfZifveT`=c'ip]w<27]Gv7*|HA~_4LxY$*0bG70V8"(0QEѩpy!fWf(r!NW`9%GD"sᶩ C61@k5W#H-rdr\@L0o,303S3kԟ'5\[&)cd^19m,gnKa<@J=P D<#0!@ TCdBd@aCϡۇQ!t_3ζm\SQMD(=#W\.PɷKqK1ޚSqMm?2}OTHQ )AV*Qw ÕHڝ[CD"  ZW͝Yթ\U`JbbZ0Ő}K*caW+,1clA֚@:? :fq$` >9VJZD;62Gip5IF,%"lM!TH)`ydګQ#˙i %f-T0h2̑fcB=90&&]4]:`p2(@0oI>–̜ 1nəKÕ(ыt'hEdP^ >w֐Q?6H|wԙS}yO2[1}9n*mo?[(5Ҽ/z359rP@ASӱ&;^|pkʅEP?Rƃ a d@ҐEDY>[њ2sf\YZ .ذOYaa,"U-Kz]+ "~PBu+Ep"\OHI#)/?`R~LMËx'bDSٽq5ݮ~匳ks bL0?x>#F 4%x?I/E ?¶wSzw%tq` ؽ͚]l*B6tnyԟN)t'Y1c a\y$\}?#r\e&D+ء:[@wB˰pk| d3H6M .O*-ƭB3IĞo(/ 2g$Mf2,ICPuª*:ÌxxEǔkh1;.fxl@f?Ѭ@-yIPэ@{"=D>m*{G:Nh}}F16fG44HBC/ r2m|2ܭ侂iM"2:O$D,!Za%Nj!@(ΈjE2rXHlㆄ`>["pDg|*-&k@O$h&e0SN4_%,." 1 C GtrDsK}Ğ\XX/rzNF py+01fX ny+ 0e3ܲk$,ۨ0eͤP䟢/Rp#4c=C+BsM:E̾GptCxmindxCͤ8v0"cv>0>0>~AdS>1Є'CK?D&=,:< 0D0'j>v/FsH*(V(t#P' # H`H2# o#5Ljq"*h;..$2=L+:/N|s*l<,x$ C DU?dǡ_'{#=3?шC;J|i@mBdubwAqrBCK T5$|3{!N"E"TTMZM2+#unO4`P2>͞pg'ht0uxyGVӨ'ohpBGc6 }!R<LYh~g)E;RI,; nxn@SPC]PJJ~pa\eqB M Lql'>"S{S /vCT+ɼ{muDmw@^vA7j{wQWv"r-WyW.57gwvJYdGc4GQ5u5Lx.Fl>@&U{jv6C]jM:PCD>j9Q@?t9_7y? {OCb|9tn:q8"J1.Cc8̮H/KDL^LtPo(1p$#7vo$rP7gpPP-t օhN#/7utsl 5nnAsZY)Ɗζ'}Ii n`Ԟ{M+(s5Cbo)aqWy}Wv "(TGW6ᑓYC-qc5G1m]n7axW:MpPs%3MM+Q!1W-ͭEYYW^-gyv8kv$1]DgaB']b>mdz3Bb<43QD1W!eSmSMKZ1M#DfWu.lƺl15݆woOۘ3Ic mWrNN4sbŀۋpp&hߒT=dHՒJےN-N"@ J f؃mH;ᇰ,0&t-#| v>B:RJI=U}s(_Qm$W7xzsEaMxDqH-u99Ԣ,H4g&|>@^n}qwCƤ8b'ǃ~ǞyJb9_8|y? ?3BQz |&8 5z9z:GZ,G;`47VJ׮XM4QEdv\,-Ѩf4kb놩#sh-^ƚ[Z@6B30% JHl[c&kkYSRq0i'rHM2xgڃD#V8{f: r\rms1⋜TUȸc4xZW=G'zxqd% W7 N7dN;h1$hBoE 6/Y5zzF8C|mw*b1;#Q:ծ/[K='1?љ@98$^y#;}zw=Ýtwv(&J8|7 |JKL0d]U734Mc"R.1ap=E:eĽPpT7g ҨUwN)娢X&x-uroIх]P2m1Q$E1Nvߐ+ʥ]WȸW*κbz_u~MB˼V"3K3>nS){0yFzrc yrzQ}sEW/Lq.J7#hMoʳ{(I.sW:}n;/7PG>3Yvw.g}ΛB8yG}}gm-3?G$+8yGo8&]74}y9D6M/݅^\~h)=Yfthp0h1R?ӰWzSBxs9DxqFciG!ddy1#e4[,m8%SAy I>MڵV?5 ?WF sqMh?`3A @BzVyzt. jc7־[[1(5mN7m:'~mx° -lp몈wj}1 S8!mPg7s=TVv]W)]8gfu|g~~ᨅW[喭Asw>ŵBWo1yh1LV=XT[&sW_,_s?Yԕ1m-"wsV >2|!`XBSD7p}O>T! A`rM0aJ)$~3Xϊ!,~\kE=eQߊH a'AJ],.ƀ]ad& ~Y%!vVY=tu dhYy/%:"[nᕶ`da,m6VP BQI֎9d,jU9`?̯Y -G< y6 T?T~a/1G2ʹFC*wE S 5m.3n6JN;9(KO6< y5`;a`x /{4W\`.V; \(LǸFzI0WZ]19n"7|>e~AGҙ-ExCXjӥfM?Ը OM:'u T:z U RQjR"E+8Ypa AP;vCYTaaILQ=oQu#qXGb1d2KuIrw]^Q+(m fC,%[8[J[ Drio}x6:k2 +sĒ2-QeGW^|WeQV"лy t d-Ob T"Hq# ^MlF,gQj|'%OOBEˇ%@OSjU 4,V*(T4!J¥ 4JАEY鳽UU&cEb1t32s? Gy 0ٗdKi;Y b8?s67@YאjE , H^Hj$.خrZ3A_1A%MI4ɝq ԗBtIt9z냸 xJp *R蒘t7Ü0P[K<971|ÙCJcH1GL? *їat\FQ x镗<9u/X,Do JNDEy#< _  ߽ϒ<+@3eJJ40TG!T c R)@s?j!R YQF撼K 5Ryp(#GseO,Dz8jϸ?;p-jFȸ9HpY :ȡYd +K(Z`|$77ɊQhIQ<]IbёS BC|A͌ē0RSjhÝ,K$?˰KZK}+Û:Ȝ-;pI[܄GQ Zxb@9S>V!3WN4O#6T?E* an5e,dVO3?ωO] W-qnc3\qh[*Cױ̊m~. 4!@Uz (BEѨIX.ɝ} ed'AMԘŗ /26UъUD$kNA[h\0 4[ELB F-̔1 X=4Fx!8 4#ҽU]5Ye>e^ES\L4rVrfR-?;Pj4 ?Uv%wMyJq-6׭QV1YXjfX`Xp4Xؒ@̦IQ@uߥ]%xÞ$@(8a^K1x6Kty c}9IK6b 5\L<ݖNj)hՊ)lQLF\I"0qctfMy;f;3}M ەR RFTXbc\fi d)=ۖ9ilՠ>%eܶ1kUmBUD AQT$u٧ciXt?] Di ?M#6f'y+ Fl#6NeBniF^qAE<a_BB&Jk^#1VK9+ 2(們p48#IqN)ʹY0t.*[9:{nTMQ mv Iҩ̙{la<vHVxe}&Th-8z!n3TZЋCrYGeţQ {(Ȃ?IzbІ1T3d)bU\4EHK{ V[ Х\TL9Ihu =Z0vԊ D+ ӘFN`((j_) "b05FCغzNvƉPc[CfGB{G~>6-dI=(Z$1e2K,"vSvhcV1LKjݴ%]):vӌpq4M.ÓN3ufr` ?:GQѺ0]yaι@;`T/MAѸki ~o,OtʊU:/r-=g}E%Z#; %-nTG&l<2J@1(cuIe/b*a!8O5APn!TEaZ=j`U"BF/ 0+hl̯%H3'.)NW#`Ph~E QE&Ʃ;Z!|dd1?I /(_cE)ܭ3,6%ΦJz;rmQJ*rlyqQ`_nxUf vb=?Fsus=S)kw Jnnrov?8CoQ70ԖTʑz梩>ZK 4=S=E ph\leD ,qYK(N>hND8Y&deS@PR/}@89eג JSgJجHYIE֪^gYR/aU˪c.MR&L͋uH(+2<[z}`/=I9C%=FgbA_i4O(Rg ;A--73p_U,%D߄0cٖR:/"XV._3ʱot=WD}ٜdйq7;Wn7uv/%<{_V5fAC.B͐C.2yADT/n&FL-*+pI:}I Kg/mN&mJB&j>(.E#Wh_ꢁ^ v h$ER`VVn@QξQp`%R(Ln҆8SU, _j`> nb,"Hc,b&%+ fm&˜f-:*K*PJ=":R\bOIH"j'B!Pty"jP6OD7Nd7l'J!ьI!>q:'8 )zqK rpoTu:g,&:S9Sn R $)Ơr(dTvzKCq2nDKyN,qADNCzT^$w-h,pf{"i|CNwŽK*}▣b<&gcⰱ18>#"!$`P|bbrq EȈ,O興JV , Vԇ)||2X SpE\_R`OGf aF-ԮO&H±'".`0ok00&LLY0ap~cNcpE2,&.(3ƨ!3H1O 1BASBCj(yn%DB_H41~OH:`Va lW3p:GqSnImY! UPǤgvFQFTD!8=>5\?ZkpN/p<‚2:-(vBh'D6y`'NLB&oYDT.\P.`KR5*abjf]b FGRGE[(JHWeeeeU_]h)fڧ4)wL.!*^bRabYfc,%0I`l3 lr5fpM^Nfp.)2dg9\n b3@ b /&aD%+A#KIv `GhFba(F!)HEO$T5jDQCĿvD?w24cp]#%4fF-AB-;BHvq52(6}R:&`hSela1aFOJ_dWhF&&(^/FLO(xVvI Q̫e4XTb[H:%SgL2zTJ,E) h(7LoTLȫ+&f:&EmnhD+kl|>;|^g=%YkDm.-)Ʈg+H}T8,/jg:2QfPR>AFD*P)w;qIƾ5P0L.1r4)RǤl#u8n'"|7^GjAGE=+wGkxM"GRB"FBAd!V߫b.87*&ax/xӇVa-$OXFMΘ c0L򻅘d> WEEԏHɂJ)F9(4b4R9@ ,FmtVbLpoU9o%jPrkuN^fo1 (b)mO2OmqFyF!="+Rp9Rp5SNyNo{K{#C*wwS!䤥" IS"GznA d7!$p7jև#%\|.yy;yD\ڿ`N8-pCUh|{d'XAql&N/c􊙌g. sz6!舊!NPUvNUWd),e*#Hg*}g%`b`R|TȐ8% -Po&0ي# i/VKQg%O.uˉLWE %"fqbf{oO-ۙ2ХoƦ/U#nAMx0B3BDyx2Ώ:|4y.vz4(éƠm"TCd6GzY>2YE|FD@3' -|ZDGAuA}Z/_ g}ɘ2Z9T&NJj3RWQS1[,hg^a!~PYH; Q } WHtEX]YY:_E"^GbewEjտ"'. ]# q۸3k"?}K6-10[m*x䋾Z#.*;POoF{z-PB`p41՜yCMiC5zL*D6gY">K7CHDz4KIʜ[$k=4'Ǜ}c8-خ,)R-لwAyv~_("&.{"O~΋~;oВVͨ;eZl`^%p_#)HjUəځΆx:_R{7ӲɄm.&pO/:]JD#_kgXr[(1R?C;^Nf/m:|UhHg^AFq]Z`)!B换_'Gs>w'?#Hv:*J\8G][>wߤ4FD]g}lw-"=D'ߞ3K"~y3lBqɴ5G-V+ڦ}_K& xMa$-?Q(MZ0?jI#O̮U,JK915M:y;e ?G&1̒o=NQ5JX A?9?6B]der oFE"q#)K-̂7YD?5*h!\{aJ>j[+)wUL96)E+RZ+'bn|PKҞ{b鿼 ;:(>hq<|@p0,!I"h8PApR8$DHCEp[D1GFRCt *$eA[%()MDhO"rRU/gUdaWMtWsDX\4g?@PS[P 3MTRte\,ET]@^gF^39}UO%mE*TԵ%&T]Ot)(t!.\ \PeŜ?2-XZW%t>A2QYW% WZB$HEE OjV^{KJ &>K]< ޲̃(׼8  6 KNkE-d<8. <ݷxs\f*fRM5-'-ƅQ9B񂹱4M/ LjLjӾ.l=%Xu^:Ku_$*2:$TUpqec?j s1ojb6.ږMsmgUmqvsMoqBsUaZ'Z忛Wvt]q6o5ve%_U>'XE{UC^zzVT)K4 hXq;42FO BJK$j?7Rۛ16Glσh(,du+՚,!:,i1F`Ɍ4Pܞraٿ3𘣰dK32h<)j<1hm0Qt>-92#'GӬyk(X;-6Y ,_7Rë#!(:{pGY DW&q.bE2{)W 2KU#wA, *P%rDK)e ]vQ(UjQin̴[)Cg&syE0}&L_ UqN钣LvnuA1S ewT"2Y\ P lU]$}uHa"|0H' :'%N|a6bZ+QӰSDdiM;+(y=[1fyv[S,Ń*Y.$T(iuc5RtsJV5҃O`Why$qm@jA+n6DgXH@m0EK*b'L k&m`I43*#h7EtR[S+RZtYv؏=f2Z&+&BK*4O)C(?zW 3_j{w;p vwNW7WAE" C4D4FK(0Gԑ>}$'i~ҺK*(ƃ K=Dpp[s(3ՂT2E]7Գ+T T2 iZeM\hM ^aGE޲r#Ij jVepH !^+,rAFLH :[2rʈ u1dj* 뼈y%@I ̝#L%3a\_ŗTK(YIɒ<2.9qD>&څJNgh>{Ǽkb   *j;z<%SUӜH6}aVF*Fy x] ;U ,q ~ռ@B`%% A XAٜ̾Ŷs5cļ#Wi91ٵj5e%쯓Sbص/VXPX^Sjj.+-"۾s4  #UFGU  =S ]OEkD5jRmr/ tOY.PaL*rs]^ap/Eq:&igw̾ko:,HMrM8Th !I"Oٍ8E ?FU֎%G|s(a%?MaL &עǦ팮hxTjBڜuÎʛ)cEn OV3EB$$A <  ph1wnC^A8S֫ϠP)yj-T<_jQd2&ܵka.E11+kJk[p=TE!JوI_YPp[(]lSltW_GmfhK OSk ` YS@T 9}!я  ,q1%ηX{Va QOV4 j[PEUNZ!P-7]vgQ}TådigJ <#,@n . w2WՑp" ,ЬTs&[<5 >+Rٕd0= +6PjD!sm_g'Nq))ajw؄dÑGs4m6MA_8CE aH2z$KE_6LZ>d'+GYL]$G_;Y:*@J4z5!K?j*$IV뵗 ^A6wBaQkBlANts;Fї?pl)KD?HuCIDX$Gܐ/4;?Кeg6.{?.yV* ZNҜMԐ$zه)(a1#Q*jgx^e{/9|c)N=nL[,=APBPC, 00HYDDNiI)H:9KiKтZc?2h[S-4|]RGwJJRԩw$ȴ^TT5N3PREԩQ\=F֓e#IO1̥e"p|Tt$PRTA]C/4o3mƙ;+o[\lP*p;dBMy Cĺ૦ .mD ,ݷLN*?cG4?@ȵ,}d!xYw`++'~6&N0:.湷^2%Oq/܌3=H[ȓ$T@|+[Rf<'ZXK=ȤF+6vT֒Б]/Jt̿QW:![GVM3]y=Ymgr [ԞMI/-W˱Y)Q,ϫ,aqEѴmis߉'ciaĕ}yL>I@@4Liad堓yrE/Y6m36 -VhZBee/0ckq a2p/&!Rf<ٰxl̜"5&M5MBau!`-g1 ]s&G@\|l?ڏ.6ts-劃hBfJei&Rj!"dnB1l:To(J>Jq19"jbN[YHRsv\.]~6&鄚|N<Ǚ/>l) rUzZ^@ +^{QYLz7~RcrfM ܼY$+{h$p"^E4]BӲI^HQ`8M0UQU*뭃ha61taيd8=U,كªT^Ux2NLb\ Kieq,w\gS֫YǴ@*c{$<6^|j"sBG$$\j Z-nloԴ9!_S1񭞩Xh3J `o@eJsQg[c.fbsdW@f[OA>.fyrtNo]Z;;ϚICtJϙ.tHelT4[,XD~!릾"Khg;'>$@bp-6ohp%hF.!+E,Fr;'=hKJ (BiQO !$ns|HzGsr++ +Q%@%&UE&MdF:UdpVqQPS'NwkMN`Yľmf>[#pd &n"j\jD";ÚfƠLJ-n<3a>m0iDŦ*bl^ fcȬ,fqo.]SPE6`c T`lb_/b7j+rjKB: %$b $$F%# p([%H2\t=Xo"AJX%:%PANB[-qfF JE"dFO8JpZMn['PE'(BMq&ه/'xy.Q*RY/bRrۥ'eXs//rLDhMT3h})BC1rn'I A6?if$ A!"\jn/&7N6ÚNB3`,c%` c6)<S :\`fʇ:&o;lzd(T|`&  2rCu"6N7Ⱦ- ]f##q]q,OҢO 2dA&h m 5\sHp,%%Qr >cj ՄBJ['FLtL61.ָ~GzL.gqW/ONwS0LT0#J:y S)JDͅDŽwi$ZJVv:F D,![ߨsU%q,Ƅ\jt'h%8:7j0-83.?AeC2"~&B"f\fӨLr\6p>cӜS<"!N\vc`*b<<Ҍ,$AzNd [K!z);x|<;c,Q G>KaRO!'Ebtb)wRN)Q,dĝ^DTK6bV P$Nxh܄[6 9F:xFAD%h>]Q~ rgwqE{hZ>0YJOJ#`cЅFc>86F0!P!Xdq備Dg]W0' 0)!c+!C`J~)6=hJ8X:Z:u24*fS(X5^\ x":vhB p#H\u:NF\o E0F$0#$&)(bFCRx*zO 52Ni"F(48|,T2u6`Q|'u+h"?"CUIy*I:DȥAВ"SDXr$aKjF:J6HX&M 䲗9xOWTiG̈́E2UqMGzS/vNF;iD3 * I"F;$:%<"wOE%,)[LWi'DM|Ws~]Mbh Bk2IĠ1abԎY۬)5JOa!Qu[w153|q9XDSutӧS,gh-)7A?I(3J=W#C.S|Q~yt|*s$l1>A.ӸEAE'B\7 B>qCD$L _taGv0D ±4 d\o,<1SG 0sopt-2.0.0/images/cameraIP_SARA.tiff000066400000000000000000002451341277570055300171300ustar00rootroot00000000000000II*IO4q?аID_舣cOv 3cԕ{?\97KS&}O%}H5?Е7ެ*_Zc_lO5%?Ė _K#w^.G^ `_%k?X%d_ܤjaM埓`FMpOV?7Ol_}_8\i>cet97o$k4[8Hx]dq$G @ /#̗ G+ℌKX',.p0- /űx1"2t LFQ#;OMXFC-,g!G,F1 J.<\C!*U00W<bđ%2"Rp*J=;Қ?1E ]giլUC"$as*;"Kdz$GDTɍkxWb*X-yYtDZ88<)Us2+c8+WwN25oRaDTGO7Z:TʀDF/eU8ME>fh(̆@)3=aX࢑&l}幡n{kP @[d溮;mhF,^|nC3͕;aͯ t+'S0>=! x q͞*_:ei.:`oɧ' p|)w;xX*Vme_}q޷&{bqr̽I/.Ι-e?Œz)[h}*ReN8^L+`_KӣYlN&gYdiN@EDC~苽YzyՂ|pY.cPfxBKu8Ж?M} f!(KB,/uK0RV\]/bBJ HrQ<_c,)A:2{: 2̦ԳYRKCK6S ڏ91~f83MΏ5yŹ`&[EPLba=QI5re6unـ_ ZNC.YC+SQEٽ9QdouN:,8\!Djl?E9㾞OO\$E%BNh"laeU^ldyjueHzROKxRD]iFeq;B /tPfuWP(M +I&j}Z5WZJdy}=?L6& *%EUɫRQ/z:(R[t+m(ai(X8B;W}fnJV6J95̾X4ҚhtDt٪_$\dBb\7W9gV}3+-|{GL˥鏐15nfj?JY:γR/yis;zl .2^g_ccڛ|ŷ:\lƳ!{5?MyίN vB32x ͗r4=`^ T5R*h~Lbkv. 04l|:6p1̤\̱ CƬ"D~p @ 'nƬɮLG0ÐN@bޕQ$ "h\PZo<@hG\b(0ȉ" f]^#b Ne ȢVhH+34pae~ߥVޖ:ykʅ'V`?E.\oG$L#ц$ǚ:NV$FXF^/r<%V^Ō@A$!H'~D.ETk&jein_Nr3%" CHf+ "i%TN4VD^(8 2VMhYk %bDNR3fgMVH<̮^oL0K.ye\yF) ;/'Dt-7N,yiZE+w`>t.館wp83TT,rɰs[5r2_EE,+䔃,R ʖQ/TF DEdCDT̤RGRM1xҗ_Ko$%E6J)nDf 0fd`3*[&ZSƖM3;G*k%p@+!bdM|U)ǚפGز%zL7$FuA%Z :̓$%2CD߳TƳ}=7VO&W+GY#2E׀DɁk.H(N9Cv4,j`ȧq;R&8yeVzd$c̩Cܱ^px[L:Sa᝜l\]>&\tCk]⮹ϞvP&T0&hS_8P_´~{j-LDnT^En߭UZYf;YFYhR2%&艚kXV%e'pMVV鞙)$'9S? ;?e.D>LV$ѽu_J$Vk4 o:HTHN$W W5S ) hA82C;%yL(_ɔJ35Ʀ=(qވ=1S.--?5_y>(T.֎/P?Ƿb_<xLKoNI&PV5Qm&]= YJ^c l^ M?%zkz}M,ne[3u))4e`p]^5NWɯ#3잹;cX9^Í>0ä2 ;.JDIqa+jGgK)#༓ H@2OB2 ܬje sE3I`gU742 N1q`&4gCEф^XGE"-0HM>>ϴ9K RdiU#g[r}W_a3-,'Yv; *# Mʚթ@kph1j*zK*8Aph}, l;*ջ0bC-^Jz؄&)M膳/{-9 C׍/.*%LfgB"Z;cY9(>5"'g&6-3+KWscV;cPeمK&^*;us>~Hs={jOov5U^7m BϢqS [$t,OQ,XT-a7}sR O`;SA&7wmk~ZWDZ{~Ox4"eBPwcTg~ /uei;+˙r"P43Ű;}#rYElAD#Dg\S6e2b92WaȀr_eHXա'6H'hY76vMOA&t_b P 3ؓ'ȱ TW^ ˭jK[\Ǚs xjϲkoFq$Y 2T0?48mJɆeH,z;\:EL%Kq)YS3gÈft¤8$BO1]P" W")tŶTfANxbkn i wX$&dy?#脟޺`cl ''$gFBJu'WCRID"rR"|&e}Yqy;%z ~UTePuDO T_nGV%U1 GQ؋*5k& kRz?sR9Y@H$˚ɛ 'Ђ?yX>L>=b"F̺DgQ٬>acJBQaH"r@ņjѰ$.!D,Z2TA *\˷"%2 MUu#1̈́6n̒"480 \?˘5p>f1ٯ,,ct{[5kЧgMTr<rj Mh\XJw4K}E:|Y$F泻< W5ʇܬ ]'ƙk>C!$| N}o6fۚvsgu3'h$GJGJz6ܱ2֎ehM`EGҊ` 0!nR|LO+B5"z/DF!+@vq&M;H5cOlbHX+.0żمlJMm/)'UZaY96ރJz}!\̱47+A=x¾M2&ZY3$I8aUO ZZGBLG&!L3b 1lLs|7aAԄB*Opd!g^'$[xj@%xk6PE?Z|hR nc+a"E/{k'|=XT)@+HÞ5tngUeKĝ" m-=dvd9^P?Ǐom}.! a*A".Wn G-zz:Kv)<&,FSL%'gyohKj202*$!Jaf Ic9Ut @H$UM{,c}px1p%w8ZT I "s%xQX'1˹hRZ!0z`[3K!1S Jĭ0zr8, 1S0!-R,1'1q>XR2R;3޳S05d?{(hȧˈTX= "i10-u'#9/hu+s7(yGV!˪C @Z4% Ԥ$#݋= 1u(ՙRG8|{Iu@ )[(-Fb5QI-0 5܌t_ A|J h윸ʑ[7QC?3; s"댹(Ohh c/)G ,xY܉:G}j?(3(l?%*92S:mR]RMj) U YH^ms{'{z#22RV)AE4?rW"H$ *,')O B u m76M@tG`dy8=;ԄSn7 ! -˙S,\)S\! k2ic3T5઱芿>`XAydz8y 2"ØvKz.8sRHR =kb-0Z0Q׻}Y8"0Y\ (B8Ti]UJ<IASxSu ۚ8!! u@ԏ~AcHH y 1s<-}5uYli C'Ҿ.rCLЂ%i Lf`Nhh2v7|4`5cWŏ"ĞG ʬ 3 N8^ Xu \p:! l.PC( L;is4Q::#X1c Y[ۈ"ʠBH[ZeɍXfDc/xZ .J H _I RsZ@eP\,68Y`k2*V`;ýEP3Se;59d}8f(< "g-R3&vn I. rդy,Ny*-I%R'Zmi^p8{pn! L؂3}Ю!wZy-o)L) On WM*T Z_@V U Is=qho&N8k6 @B}SmfD]|;kE,eЙ,/4U  IY|s8gqܰiRNp$L Α RػBcԿ%Haq!c.E4}tP<ʪ|:ޡ(: \fg<<)fZS;TƑk6*R Ts:)'#Fif7㘊y 1=[d!Ӏ$lp8OTxj6(g "zGȝ ^2-&Н̬٘Xی"W4Y d,Tq5 {IذSut<Ĕ!)Q"A7AG q.` wdaydXd8RH؁C`0 ( QT,JIX!=U&6 ɶH8,ZZ 7WAc! A@_3 mB]Tbmk^&˰ F*#) Ⱦٶ|8P#/ 0Q\- k07 k < RGVMrXQI d9P6.%#k8T„[#cOH=B\{Ssb\K L[wp͍HҠ u Ĝ|Î4JDK ISpΕ:W T#_':W c"xD86 - ҼJYg@*Z? V."+{- ;F;Ipұ4Fh 'ѓAFzϑ㐝lnUce6#mIҽgjQJGך{JDu1N݉BuG̚;W[ʎƈX#tn^νCH`xYK1h4=` [HkV^ŢP\P6~( e0Ojy3l)i2 - μ<$%`]ўSq (N$Rw%HWRoX(ˊ%8K`dU`Hj~CWs.C-%5="s bqc%C.Epݜl*xo T,zQ"jy:OZGьPVZ4A/F͢&BS3$ȱ_G&\PDr"wyI r޹VQXZqr~oCL0<2ꂗp'JHdF 嫆^bեZف#7O|Ճ{>lzz -Y?[ u#89>rJew4RȈcXW *?7pJX?o|]Z5P+*GL${LN;8 OۙqŢLjIw(t圦PÉ#M8Q.-ͫ6[Y3hɡ@{^p"DL6:}^wP6@(Idsd!=g\#Eϒ i~<4wω=ȍcesAEDhV+3loXSiYVp+\bQ+1p\N CZqhͩDy -"7Bh[Wz+ch6Nɵ $| `[tH.tdVF rOC?&8Ff=P"Pp D)PFyEN星OBLbiR*du n\Pt㈬ 9&4NNܕdn\J6JlkূyPN&NE~'"Hlh8,JliXy9,H,΢ȾG,Mlp~.67$F>% GDhp?"EZ~122gzY L##9LQBbO:+yM&*Msf8lhGŊ+x 8+rtu `MH+ZO؏/+ZFV$*_gZG'yIXpQƌɌEbrhkދK"% .7zDddKP7Py)"XpE~$^dg"*ܦJp!"&Խ~dp%\p .0R )NX-f(XQL$AڴBDRD'\DgB-fiƁ+&A()51m9k®yKEbFEIQJN8%JfN$Q6BP8BNa{ҊPa<b%9|\BOg$PYF{7"N')₌L46M($:N2lD#yU-dF|z=(74Ar*!d!NDtr26DP 7iyU0"r<t\TBMJ\ȵ4;t :IM/+*=L-=35q*h->T|x(GS'""IAHC`T%F3\") ir2d 4F1ayHll(lmDctL+&lYX0WpNMcPNJw!Xm)qepDRQ5;ULap0#k ODs #NK#5u )0IfqX&'A2B$@X6mHFr@;r9 P>$f$d~$fE Fg)o p5οo}Vt.UFJt86U+2o6g xMGJy"C6YbEڵ~U[):f *(M>M?V[hb(ȹ<] \J}ehU{1Hp`f~$FzvMOf{tdr9;^j Po*& ܓP>,T:DlBI/2NLw2s.2Cd%U6(Pe'*uZ$NL%F&hM,b JԖ'-=m2PPxPGJ ZF/'ݯF#?G5)P @$=$#{c­q&rEp @2iYfOq666q:+qc!r$(WB|(X4tÕI2MՄp'Jdg7[x_u'N0oB<桕z' ]\FȏלOzMVȄו1JSU|[]wǛ^ Q}(ZMY}H\(hy ~)$ P[_ JȪhoMcNl:Ǟ=8P dJ:$2FDddv{ DDd2j9gI炘i"c俉ntZv')c-*e:li(^[7MMGgJo.~."]G%Ryghr2nlfmum,2~cNpK&YSVbbWuLΠodpfYNYm.+B< t'&C=fA0Ѣ4292*"U(Y<#BmĦH'hm:mctH ¿ɾ-f|Z'4.)ul4ԯS$Xv8&e)j$k/Rpbex+̦&&Hblg#bdroH+B~Sd+8DArpܶZܾtNiÚJԗNxbJf)(P&֝6jitȥ3ŁxԴ{3` +x{;_vUٿۡ[{}ם~[lj#8hE;.%y##? 3 ##/וȺJ ) ⁄PBF{BzF=f>:6ʐ]NLFjvcmLңK4ԑxZX³\^C; L(֐\vdl߆*Ƿt1p(S ՓgHD*sx8Gt=)` b L/k^d&ۧ㦼?l:^]i'vw\P_ [+`M7WmWt#U1|F]ۡ=O׽]]ܙً+ hfR-%>vsHDokȿ-x7gH7K6A8- *Ն"g5@"jЊ*y4)ܫ"s9W8B8st]h?ͱ؄J"|dĝtDis1&,?3GA葘ܐ;R*sQTblL0xMta [?6eq_ycF.<31[ 0dؽC&~~zKzqSi^]oɍi?,j6.r%vg_Z7]0\r})?ʾW[yJG2G#ڣPwBX5P)[;D#H$ip C'>C@i E'?<^Qcѱ'7~R=4IQɰ:)}(T,C,ò/L2.h&I<q29:Tϓҷ09-#bж'J5/,tӯ$'_R%NU!I5qV4< \mv1L4-E=Om 3Y4tGhYGZ 5s,) 5- @p4 sB”YXڔ yk鍳kŵq$(DYג?a#-+X. #,[@, M 3GFkf2 =O3dz˞4e P(4b:6NNt2=GD ˹0nv՞晥křki@j"= a<,űкݩo\eo[ל G2GW_GAGgQt`w't! W%L.JTJ^_L6z^K_'zҬ ƙUhطmYĉJrkui>F`Lv ?< *Wf82GF[9spqNEF6&i)_m'`sCТ_DDWPAn}w/U@Na1 }7T;F4r&8"B.1G-Ʀ2G3(fhrk\6_:5R{rƁ3(Fbؽ96ae`ݭG4T .ю8 Y08R1/z r$NDs-vİ_z{ݰ"_)i޳1H^ A?x}"gV;G Gu;=f'QּYšKM7A^}{/b=JC(\MI:~O?ł mG3c W@bUS5X~| zmJ) a!+mWN ^6Jr.4iLdS]\H<6Vk kˆYϺAqEf") Oj&i&Q2TK| SFmRս#~&3WC=mME" 4:-{Z|2+q?r kM thdxSRa-(98v¥VS+e"t)딕g:jⓨ>V=Zފ1EϭȗZ2US@Nq(QِY0^ `[?|z J A= Kq4b)È12ĔM%G'='ռפyf RYA3L@^?j\cV.[ 8IHp#-I%BQnDjBq*wɶ+M;k2J8ӭx+0]gsU!;/dGLFikK8SI52'_2D̙+ݛ.:YZ'3VF,Q):RYe`(S jJ'9H

`z /˼|ɚ-KN C` $a7ә`C$s$$Z &Q'n5)I+o6{GRэfC A FML3yCLI Mh"H2BCqLNMȢ<iZ(*%ʑ%x  +[; B&Q+ ֱk#b~0ě4I ԟ(41QMddd9"<ވS)H`O@iz^HLaxSxYzZ^@[ H!ӡG4Mcm1 S'.).%Ըזt45ڠۖ&йfVFƼmd P FGBV&Hx̟xcXFu(]]U [A]jx(^$@iuxWZe,F\[b/ q*H%eM_l0= QLf!`%A5l  rrRP^_5s*Wf{;RÇ~PbGlL Yfaʍ!"ZlS:^ vv@JXB'Y5؇FB7a`ҳ"[bvc6 " ÐZ ZM>,NC) q.(V$D9C }aFk} !*A rUq +Wt&č:L(ls^$ i<!0C;_)__jqgqrf f&է$) (t [..е4axv. Y*rn㙐Wp̑zw F(" lVi^̈R)Ru%pFJuW`s֋ َa-@>r<1_6HQqŌm~ ٌ^!.VxޡqSGONIe><]P g뀻u,|p(Z)0 %4`=deƉFY>9SW ^VخD`ݕl+)o <2mI\-FѮtmkm`Fl~m$fjn)q&p%v $PsyG߁L'#'h]Zu²:In" Zq&x,*ŠaW%lp6}vh5 ,?UH^# r*Ey`١7ڹm|aA灣:4[ W"6LxvhS1YrUu>DЌ \U>_@u +FJ #[i^FAK: ɞ3 U exu~˶')}ة5zlmY֩$mMqt}oMg{OYzl] M_˺R䐄Y^lo6 lOxr(^w}nsQz4 Lak> [? N%1ϖ^x66C$5)LY1`,q+rϪgTP1 )qr/CDLQ1fBX+vnj!d C+\!I%IYP&.h љU3AEc?PTOb;g_W-;gX5br\PElf&3-!g.(ʂg;XuΩ=:'D,?:(TM[6tڲjhH:qN(UZUͪ1(UϪcoRMi*PdT&:t'Y5O6F1 uڝض!4)r B{ ?ŝ~tE*$`_AvQ8K5gR2)井K/ƩTk!lhWao!=Fk^&Y q @)\鏭T럫pl|\lkdi W*yU)ӌ3.WbI^HJqb‘\ (㧻fUae2)b}W jC) ǘKo5b|-{Uz뾴)PD Jb.ٜ[݊ڭZpԍjK? 0r\ m20(>Isxm1|31/M ?UC l9R$ҹOY!$єc2۰qFETN[QD. Y6db{z5sċS ?N%#;CWxU)ԛlqH>%ӅJ\) h0 eƂ5L8$jl|08VU'm|c%s6"G!b>[kb%Wy_ŵ ypY!ꉯ遯ɀoח[~ zBV'51q5tѰ5&R0Lx(9ؿ=a#A$/9:YlX_8k{;;j8hrD{ߝL (Md0 l^inzuA|;­t$ƔIVJ|$| M*|lGiiXDNEl${%$j;E/f)\Q3Yiův]-|ilYё{ѹu/܀O/>%Rɑ對S_}ʸ_YVO|sʛ|(D+ R*00)nlJpyӣۉSۛʔ5~n(, 7.,ZE!h2RGo0)DIEDA8nb\ T00)x@x-&-D+br,(Iqb\\Cdr:!"CidAǭ͜{@UtOÐ _OôhtUq<\B KC/˂bE®[*StLv:-1*ja´t$$nqϽR;V愈l\[/~bIDnq¥N(]TA )I=d'C_!MBb$d&+au}kOeX:[Fla! nRERշQQ.Pl?[ueި?4yR n-AS tMJ?b82Gi%%ܭ?ϳ5K%gs;MO m1>jEJjuM?u&W- Yl`Uj[=d]W^WaAvC%e1z+RT[PvO);=htHdrN7I0u~֛Sn*ЀE?W\{/vl}owu"@g5atAw ?O 28C6TJqDOģQ3A qo<AB䊍8 3Jg+D,KQ{b Ll(+3|4MP|*J 0N1Og1O0 !Xhఆ!µ#/<*R1K9MӨz" u IO1QԧWb$ \ r&W|%$EdYH^׈ȟYֵXVUpVR#%(<γ?Δ% q*x5/^<,ta{X($6'p@9b|ac8&X9FK9 ',s,ڴrg g|̳&3G4;z~4Nhk+{"N "mjڢpoҰHe-n} k!'T56p| X[?J=D(7J)+DQ vG&4r} Aa{\^3O xrG˶5/4vدǒ)~O8˷e#\>&^p#/7[<+UkUi0FZPmZA>[*O$C`| ($!](@*](]Iv'21X(mIn(,@䶦*ج[8˽> .@9ofE񚳶uQshsiը56c{hGH +>f%"?U$tMt9䔦G"TO(G9X e GK _=2P=2M D j>B:ao4^bʇDs.ʰWr3]Ul7|IIf[I]qv J3PF Bњ?GwYV3 ;^ k'4xt'!tPȗK"SqL=ZNŹ8@hP=6r?XeC$O{`㲥 f9o"TSTplqHG4T:M\u>P7+tFG,Al;/pT}; ^@TG4hGd1rHks{ȹ & ή< ;kBC,1/;HIIC9,%""@(E 7+}7(D<9` 5@°⼵ṞJkm&q#3E8㲼mFɼzO͂Mg-T֜4;,t>Ytᤫ%8l@\:T|K 4Hd!1̐'p1Y ձIߧ"":씼IQId̗ |C IC+qI9 C[? X h HHQQŅJ%ΓkP] mR%#PJ8*8i2{P@R!?BQ`  SHЊRa+$SGҢREE?M4qTGEBGdrT70ǔM.JTǝ.H5jܘI׸--v`&̦]Y _ ғyb4?iPQDxH ߁V'Xhe aQbfF* ryJ*>P{M%zox͜JtUr*X#C(+۱e.2!*20b a˥1.hʠhـ*Ay`◈zCh2')O-IvUFFitp2Qw1>*-=H{ؠ̳k\7µ#=c]cƯ=k*3 VyOEeqDOƿil Kxl^Dz,_Oe$D J*ϭ ?f) 9ԭ%ZNoPRé!gOc'DiU5b"B33.vfT!oNq.e^ qTJ9E!']  Z.^ 'ߡ* ! ZZU!Qdma_m=q>xldg]6ObV6l^bc"%R|B"M% cjZ%6# h} 9j?2#i.k5k;SMH!|7=Ws@l>ćBy8EBOH^J^^!K3_;6AHpŸ_ѮЩ$!.qG.0<G`lP0 ."ibr22)pXL6 . f0=do$(`wVs OkXZ=ǀe.66llc==Pc^W .b .*Q>P, Ռr^%\B5B:\ yݘ| {"'*ƌ`9! "O7\ޯso5c4k-j]I q #_#XU{0b{(ktnp/q6sk>_-#u+n/eСv(n\Wx+pG6P?_]{>ubQ?PJYe7yCL5ԥMYxՅ'!L>ء 76f|]7^goq7Wq7d7|wk*A_C !EK?w4!G_YCD⤩CPJe (M_ĈvO_)Ch]% Qh 'SjZ ( W_rV wjiƈ2s?Wku%7?͸!p?ιw5No?ZxJ\Qhd3a?E* ^?A|;ui]n_txS{=ޟ7}~=i8 Ij^QAG PPQ,8UDG]Pq\% yFO ͣl-G_ᴀ2`+ YIc( `*'e.Zn"*j(B#NGE:,BY͸5ͨXB|G9nſp۠ \d |'י;|_ w: s\g`!}0U%$*p&&H9>Gw^aCH0T4&*Q&s­?n#,v7:p7ΣjBa +ò;G,/#8;/ 6қh9n_5 $Ӎ\Wō̟9+*UYtOP/oV^?Wivo}u l >9yHBC S.:l^=;F@#WF1*_GEй|89]kdGƤ,)8\R{o6- TۓtpmjɁ2}2r(8=DH*\K&6Ky@ VV'zf}uX !byrIk^1ؖ2Ȋx|j-0f j[ؚ_=xdak}: P \P1&&+cl> 3V?{3X+ 墏hR)9J%zI4$K`5sG֦w*`MF(q(p/>6)Y#dh}!i? 훪kB\+қ|NDL:IGbatPnhe =n;CwYyDxHAHϭ9t 2^?U5BAtԖ*H5FU2m8b"*[O2z$V= %eAdBe 'kRh|S8K"Xd>=%l`XU14'C[vC*EJt=t+:Qciܟk/U*# DuA޳[Q@pI,[r 0w=E3^"D0ZYAR){kQ)/%sF*,ҹcU+zɣE!jHiø#zbUGp!,b@x끣B`ZZ.XD`_MW5pMLv.b)l4.NylA;B>8PVwUj#4czo&7[һ/fqFX?Gz097zZ @f3IfX|Noe>Q_]qSa&'NJY~ԵoF_UP7g^CZ[X+"?T,[\r>A$?~o'%M=jBǀ.~SZejethLv qd۝gy|5Q^ E߶XiHuSBG(V@gX X .lDL I\@R.V SPNWMRWVS ޵ȐI@rhHpldpflo Gz,^n2( M=.뎼а ,'Ƥ?δ#@)$jnF>ޅJT"‹HKFPt)ai0Q `hg,~Cd:q&LBΠ) -Zepf@tetJ-KvO*O |(iNΡ TbHŨ٭ۂk$tI$ko-h%iGDtH*Ɓʂ!LaUmBDM^k|zLZPnȪR3,4QUE{ \ bHqTO:YoX/X2FP-nR-I n蔍+ZՊ&k*R^b؈* (C (г()0 F* ! P:OiQ\\\1fRHiOK6޿ObM`(yR/B*^w!*0h flLƄ 4K܎뀏\@)HzY$ JFhPf׋P-mRFGtK@mo,-*3!ӦEDXEdDRo;k<9S= mhŖP, J^lM&.QWWn H#hP+H-R$4HfNQU%hOXA|2(K)kII&)$t(t])c)tg)k)N)ý ңG?R};Ȟ ;$t !!-`"^[ɆtIMD0Arֈ-nOX-Κsgl^z,RŮlkk\F3i\4^-)'%-T8,b7,٭ Ipa;ai<W5q;;3:}WS:D]![<ӢUn>Όp,R%OIDS!# ്ٰ\Km$@Q$E-~HS?NQ@4dA|YD4AaF5WXHL)EbEOFoceFAc*wG̻*yHtKB3"bl( 쏦tGFha:r4K Vo-3X֣/\lԅ4nq r.K K)geQn _(Lɽ2_Rbҏqvo9.@*5L@涸f(Ūf!G!HQYYjquVu]uQuevMZ0l >_\BllKn`.`٩\2%/a&.#P5JVGZW!O{ a}&!W|T$ev6ɖ?cE)6I*X GLEüiL"ZZWu/.' ͮ|g?2 a (2-:H$Vas:nf Rl2һ3/As f" ߁wPtX`/ian$ nซJH3*6+XL(ٮP/`_0oPt 9Gt[Y7]')Y3YukMwMZa&oOmz(>?^  R/ dgB2#h&1Q 4YtHnH-APk$BYnWT>hQD_AF`&:Wy3VCw>˪5(4[kn`#ӻ;ES9LX/SdýJɇ`Ln2}Z?*>S-/!tῥCXyDB-P#AP^͖ǯb&Ǔ,jF-^fvrq8+>1(3XpX lLU#jms5-#X! w:Y!aK/Z]y+[ yK2P35Zo42b\M oX`aFJϠMKd@=&2\Q{ фfq:6WPJ 4_8۳dY䣻*cY9vNvPT,&N)D `Ӈ0sNPIԧG.,Մɢc,X^2w4~)l(4vɮh(ɦ,x<}äjm5,_4pl:;쉍-tam9 D z.2Qapg* 5kyˋso{"D|Z|\D{V KV|p3FrK4jƫu ] fsmnpZŬR..K0mtF rZp fhH{ b]rۻkևsG=seo%X\2ldfLxxt@v>|͞3ӒszDަ9{}p,O`Ϡ'2(6Y2E*q=%D6-ug~}0^61G٣ 0va#%tYJH O{Ż]o/0iu{r)I%cz:VAa_[ޛn @( ?CY.cܝͣ}?MXiwa{X=)9GVlimȻa'?0WThs?L]?Q^A$x?2.`NL)9/hi=Z?W4VaZmt?Op#B-Q`ѧHM&+KTfS}"f4vj*}Q F$_ y#.@3rN "'e> &(# sV t k B42v S Q#bñ0= /4@ChĸdD?4W-sT2vcF8׀ >p Q%"#F8#Jv,1eWb]Btg]ŜZCt<>B* E$?^Q+f4ydȚ9a6_`́I0-Gm]=(tv>!^jᕫ5K t{6@(eB:m t/I4."Yl&Iv?gOU( s3o=x0vBJ9[NG)gGh?[8*hMoӹh+L9AFӧ??X'SݚzL֨?=OΒiH 1$nUR{c U |:w%'” $rVwJ}7^qН<¨U @zY9 -p?D%|!#^1 o0E{Gx}A!rPo*q9Oi=wUY!V0qչInipN# -!W7Us(DHb$jugYţ #q0{Tq˵SjsQNݻQ93iuؤ߆< ukMݦT~NsI dhS9/s|oXf9뭏\ EEh-Wm)fW%R@"^"ڦخ1h?貺zyܩl]R "V@6IZpt$}=fikHu={`GPu$Y`lfpQx^qBn`y0!x}KQ*B՚6bNY7pmw r I7g.S (ϊ8b !gssØ<˰7DW&-Vx-:'A=20F#szΖ V`rhRL:],w:H4nſnsw >:B*ut~{c\&pvWOi# ޚ~fRI1'EA 4o"kꅝй[R+0_H #3uގ/}ґܢ'=NՈQ&rYBy }bf㜮5h@,|,:'R 8Џ8C8h/ ƛ҂'ڂ#Dr Dл})@ə;9á :`޴*Gҭ'K :x`Aොٙ {6*[ 9ۧ%⭞}kC?H?C) /3yܴ!11BZ" 1a'-86"DE(hhs>@9Q*1;+ VinZlT!UC o㩚|Z+]A#=;b6p *k֎mԌ)8V!a0]ڧt䎱9Wdjn떺e-UjoXkId&%9Vȱ1sl!e#~6w8zL`,Gm-Y֓78~qDNS>(Y/3 Ltv ނ /&Nӑ4 >_S͟[fZ&mY|SM3*r]b*_]EkipTUcb@ l8 ]pɌ18vT$%IquHJqur%m0VS^]#Ёpf7l1>䆥11d1Tr/ߟ0Y*z {sB|ȔSgss͟9;r%i2{84 To aMTۑE->2f>  61>x֧1)3#jKnPBS 5bO]؄ֿhՔԷ=9MK]#VII㞻mv*raatPwvH}7kwymw~IqׁGeQ^K:YxZt)jry~1 #y(ր%gmymgħs<O~rvv7ť9U#Ȁ'Oe?P*D_X#Ov RH_$f6F?2\rL_)7FB}=ϒuFE_*dJO?7z,V_Z!_,O?v4\_蛣QwoO]~+_,%1XlZ_ꬣ]^ٷIgIG䌒(n#IR)H4*ʨ,-HJLJLS 2̓ 8C,Q aC,e#aXl?49&bC 1 "DJzoL`VWL}?4Y}̨3K+oq\͙QW3 -#2FDZ(-vX71L3bB3Ӻ܉]l ޳K5ƶ *U^" nM?qPӣzo)Ϥ)RZjuP?K׸Ĝ*B 8Bt|˔L{):+5zv(ڻlIHIS}N+xiY${JQUHk|bP:)*.*UIܪ*Oqk%ī f`ҚE8|?uABFa7\ f:_bXbaz%ĒZmDŽ>VUJAib@͒: *U ŝZ-ՇwcC\S,fR75kOLiXV޲gd͞&3`rvO(eGҢRJ(ye)\|sS(Һze~#dHM{3/!h:94E"Q6PveGNYg=_WsΛcƞyNVazrA15*T0ybE(fa=8s њ?)خbnlQffifoM*l )c {@hjeN ,̜Tu{0|?ÎY#\U* le;^ I=43 ,*yO>SB]hS_cp:XhcőbJ(/u"͜ga3XChjy*~ZKɷJ"Dܤ[oݝRb)+%n;=$P?oc^) זh#gOzoZ4*%sh)l3E1JJ?J"l 9KQ$^?w.Nt5w\u|2fwf#ޟiUMh`.!o@R&G.0 0d5 >}W %FEg-.,"(D(N ~K8qJP`l b % nn ª*Ly䤒 eꖭ0NbI,ö1* iz&f*B{K9ZÂJZ:Dkzodh<& /oovvq44O~BgPCJL>d:F@>mL<&GKiƚDDϴ7/CO4KZkm1-ߍNMNLJb㈨ \{ Qpd0p%ڢ .n@Q$4X9Ab 2 fkLT @p*RE䮊@- $U p Na ZĪ( b-( !e-" qGFi֦z)zG{Z7r 2+9D-o,Y%mx:|;ī9.k#Ē bgv,K#8zmGI081i1qtEqz-d DtoՂxZs?C4o0N[,~2P |nTq }7s7s31j4‘"S\s*Jq*`dZǭ*B B l'G=,E>@63.AT A2X*a" Hs9C3j0Ƅ KN RL1p<3:O33Te +m+qdzjnKft|^FrHR.Oq/yIfTѯ4,rmKb#ooLqM 1x`FDk2v*A*O45L5d!NrONg{ }8l?8)8U-71853RS8ӊ}9eX"ES\YsU!iVukVQB7S{N@j<8D **^j֭h.`:'@:u\a]!U&bj^kD8&i玺-4W Vըdn0VDE4RaO}ҿF7rCPL?GHԓ iKIw Y.KZ8ff{kL/ua$zkBCzCM611M\r B8yO'b*zSXaLEJ6YR7R5nvnSQnUVSU`,^;P7;E1^ 7(io"V.VUe(eUQZt_s\U]3`valƬo6t9ǬJDK" fh5\]uuZ0uw@\Բ&gwvP 6$w)Ұ1,gf?$@EDH)9FJ:N^VR e.ԓf#J bzrhmGI<i3!mrdej?NTujkk=k@J.PQ o)+>gnenXgn8mnStUH6,=p%π'Ul)pw YwWUVC 8y$T2#Ct"UbQvzLudRWVB t @ݎebЫdLfWuwVeaߊ{4`'*GY+kDQ|FRhoc}ïeL~]wb4z'FIRUexWE`D `$P`h(wfwdۅGz+…^}X.Ii 3ҫ3zFy?c2Ó{b8?-xhR:H}9~$ke+olK?j86ϱi+%=GC%xF/aO眧yK+vzk'qioOnj.S19,tmVIUe"SywzӣtWtۢz'T{TZ2,si@d; 6*&4Ђs7XJz>E?_TY͉[٪V'i+:|BG$@MQo+{):K$9mfYq-)V` :GMhE9M&rlFX0qZ7I;&99'zײMQʶh4zl %ܫ8sH ZUZ Vwtw{rϲ%:8nq!U"dj!·QwzEr9YsW APd $!%BXK8 CgRX zgNuy ) {O579=k[|J~&أ++BJ;euFM淁$oÁeͰ&rrIONȔ][*ߤ{38Q>uDdsqܩUWn#9 VWI̯CMvN{֔tvmPQ6WAC`v=;{tQ"^SW9>gПJsj#e2$`N>%Ai!#r=y( V_ClFsC$ 1xJrKCMJґN9JE!HtQ*Jla(HMtq: :#UGR)H*BUlMdTY{UcTWMuCge{FRiuK/SX'("r\g0?ȇI6UB.aV*Gyoᠸ?%syuHf Ө]#<){糏T}?$q'0#$4"/A|K\*<2C@q1DOLUőtcFq\k Tr TwG{ Hq!G@\ \%g+R K-13A Mg77M| S`1;-˲!*d&ɔ5(В@ѴFQJɲiqSc'SSR)Ug?Yj]zXq)eu֥eՄ W!L뺽!*AD?Oiz{> z^0R5BH" vo kBqv-5NӜw#H<#Ǵє|KW3 NjՍgٟs35oIX|-IPTE4G-[PaP^=|gU8Nu>ae}]ȸtaoGQҁ^P'GA A4?1x7׼#m}N +(l0X^[ i0?Xeq!B`Y|d^&ؖ_k/ff>+hff\Ѝh4oZai1Ftڱkѭ`alf (m /D"<6o(&`,uqIQ(\;SJG˓NjV^x)Bwm;tH3n- dZtJAKU.&yro=]8\Î{ 죄tKC1%v/5yMB^Y_0T?ᶋ 2D"+)$ DRxG!Ol{pl82 D M8*'cQ D8H`1B&2xR*1e6)XS3l.X6qog0sڣVgZ[کh%"%lHc ]$9+$[" |ҘUeAg`YzHU7})^+|\Q=E=Ѷ$jRK_0.Dar224Sa)1p"S~ƪ d6GKOU"(SY3 ųEUg1:Wi8-"ZԲlGN;W*$S𢼶JN?H^i&Jf8s?߰[plJYO5l҈FV -׹-IZb]LSB_{mn-ռP#iʝz%6ҦPwDVDŀiB{O'nnSgGsڛPխ&vՃe9nt "6ә&9 a7-xr5@DZ#XSWqi^KLjjY8Uq81qՌr=]8&4ۓ&Q9PGl 7i$WϚG/BCy8tr4x 4B9ZKEkt:Id_+3ŷ3%>M;ydm}RV:B>tnm"-{U&qz {o /hö_Hm@|怲Go,:zB{n/.xW">)ҝ8 Ȣ>⤾锾)88*8Կ`*+26c\99 I@sTbx3@H$Cwjh,FQL&cE4p|$;5;1oCBaljY .".;%G,$Gɮ5("j3hԈ;o;*4!!+924H16X<4;ءFP1t0H0[\@F4@3E b;C'V"J,CM>O1PD`#ɿ;K VłDY<[Ų+?¹@ _EFIbK޷bFT?L ɨă=!D FL-<~oGBnA&r:_q޵XIL%}AARQ SC,u(Y*jp N\HrP23NʀRJvhI̜ܞJƙ;Ib!*"!OĥZ#)"Mȗ8lJ?R *#;?E¶]h˵)3KQs:1LI$Lp8̩D UloL$MGMY.'Rm(M 3o;Ko3j9B"M~BM2M̥[í6/޴ZjLzF6`0,z4i;H6T) ѱL  {!TCO IѪO8Ą12 XQU]mPEX>dEK < C%?5?KmbKP˭}e N, IEEi56\g5 H(1W:'TR1$RUyS=zBlsL'ғX׻ .([V5/uMRe{e4L ,R%(:wXH4>:h/%Y8-ߦFRw,;H7٩C@HTCJJhșѤ:[ 01HXOͫ8(U{UP Z\K]2t &K(V-aC>˺ ۛA0֬V@y)vMo#0ܘ-Lۨ R-AyL{~W(BqO'9C?1ӝ! H킦Շ͵4%zbfpm4 &^Ephw'eXd/h M}CF4߭KIKMPTEK KLK""Oø)P\1ԯU8 PVU U Vk*<Ee[\_\.\&VfL(ZАް4#>.GMz5ѵ]-}D<,'‰%.1Gz<= -E@Ev,S$p=μ2RGHPv?3=,,Bj~Eb2~G@ Gq L֥8뷵)@ E\-fZVOkp_U)ћ DD E_ܫYS?3̰ 65a+^N[p=naa]\gMuT C쓃Hb؇+ci5%()*>+>,H5D)%6!GD+ ]F8c]Zs1 d5~>N3`8ӁΜ0 Wc?V^X'c-!TF;KgFbAJ$(̙LTMhfs!FW_XjdQ5Ƀ )*"O JY`fVgVh>i[ۅ]aJVVn[oH|a@>fvC=2mM G#Nh] h-2f8ҕ\לD%A6sQ(1AwW|R}3Bmd*B#&tk"c9P֤*nED Ԅ\)P  o~7`x:j & >5e P u 23[d#vjq\˞HqfȀ=a jl?v6trza%  D\:bmss-0i-x0/3S%ԊnfԃH4w_,<(oRȬ"UH2Hd+X:o\c榇{YFΪj͟jBj9 "i/LH͚袾bJQ[ qveE`Wо 'VF#^_lfluQ}ly(u@Cx&:e/,ឞ*h^Af?~2w \nU׵Իpq޳|<B.Wn1H , n٨7Bƒ˸Ӂ0<؞=lh&iI(Ǜ*wP"Ivsx+GWTpWVT) ; }7 .vݰJ_kffvsE$Z6kjfo YЭr D)%o'Yl|Mۥ!Ѣ_]f;πG3|9w݈hmoz]X+҅:5Xs\=4\+X/*/j6/ Kfz yvTwF6?u_zi tg`12=zgՖ {-fL?[4U߶[^v|@CBO<}?ϑ# DK_ك3Mw9LBH_T%KS)i*mBQTJIk䭅?zAl?6r_oۮU?xw3⁘~;!ayL['csoCiryFWU5ڝf_aoF} qna%?(7uuN糁q/{p 0y2GQ 0$̴Cg)đ2IڐlaJLc( -1uQsR Hr2Ĥ2z%$PQڦ&|'r`F\6sy7sENEOD(%AA=C$5ф1BT&BR,B9MӤ@ 2iZ(H.8>#P%)*O]t/L2 ujҡɶzfYvYM[Q<6h:p..4M5כGzN_Mߗ߯xYag q<@ּ7mp5YYՁa<]b42L%d-ᾐ]mzyNKlj)YڽjڶVѶɱ I^dQlu0deFD)QG?L<:lLG3nsnSu IhL4& A= WK)m4XdFj聭*mb]F-fԘSKrp(N!IiM.><&ܴ}OA@(iK4ftn:gR]cv*;7fbU\.]x}GzSdp.8WJJ{)K,|EIIlA2hϒ@j^Pbd?2 hLY$]^8G)C&N\u N*fM8+]f"C@Ofq Y!\ Б(ea0>f64Ӫ`B (B8D0'Dq'Ź-ZڥZRa#grr0ƱsL;|N=9 $Q2Fȅ'"S5I $Ue!aWI4 ҄+='[Xo8jt[ږK;`i[,HKLI3̙S%? )d畛v Mc h] @Rj̝Nx3C=&:\lB!0(>j?E.djݙ9!S4fHݙGdbDV& J[!ȣ`tT*o| {mu:T{QE9H8i뒏x ]E՜$jڕCXA*][s$JL+@YVkKtL&0>فEd-A4赙YSW,>Cj#+e0 F9> 0 EM6di6L?}o@g`D=^$K=01%lcԊ1ńjafԤf붴W` ~KM9낪saE#/ :ݕczb,C%؞'#t[k[,=Ib%7q.l&fgLxW IX ?<(=h̰{$+FqP_ /\0vm ~cE௤/Qsz`ޥUj-N]jѨl;YzR~Ut۴k qV흾LN5`71 SWelݰjF9!pI;'vXn]klސ {Љ.> Лcnl̨TO ,#J+dF$f^AA*  ]yAJVbuo!Ќ> 1~NXM<0.P5 @{M ZՐGKc rMv\r.ʪCv٩~)-s&ۏ) 0piKQЍpƼ""ء\&tf#i?R@$p$N̬䮛 [&`zf$USxaq(ҎҚE *aA+2+һ+,A rʘ npЀm- q!Q!1//RmKQ0AnLm(*ptّ 2uh*-Ei 1#- 5 J§  (9D) hb~l$84OM9nBf%h 4̣$&SNfí'$L%#4vv +ļJ=>?*L99àJhA~˴̬ʣ>C ?! !6CD4GSb)G3[h12OzU3 S:Ï)-FEmSMeq lr EMY6sj1!dA!茍p2DZ T,5CM8$NT)CBe/Hn&TzcP#0 :rt;@GoAFB2[KU;+RBTNUAZVSUaVoB$uv^gFn T ;S*USmK2KUUY/2E/C*XMt3|Pf #2}RoT4J o'40zVT&4JU[EYђvDDd &bsMc~9dpZ1nAb.3@MfM5vf|2m,[hG R.E(iia֪kkvlU oHb*4 4 VunoYZZ6opGD Ze/ EpKERt`m}112/JGS/]5^P3S^ԉ GwHmI3PVNҨvEp{޶a-.h nXWx&4 2HT~uMkazWMK5dSdt/,fhc}Z.UdÌ΋1c=n2֌/Xp@Wŀ8k@A'^X/hR1:LyC5C5SoxWoYYէ P>EF51w)sGxG=1>tIImIqlU'uE7fՒ + CRx7#-~ x8,m~6?zُW3z{,N Ό;d4+\,|p(Ea+.XDc>jjɀw3d~@d ~U7wa[aDzi u7ExX}FnψuՈ;9sB O"wOIQDqHHeZqIKChX?H~f&dcCEz #*1hvΒsMvnf9 `!0HB2T8" xw f8 & bfcAykVVASazz :j;|tZS&ZfDwXCw5w[٣mGDK׆qիrU#y2 ]3'-Rp37tCHHإثe"cqiU+{-xɱ7xp"&p8ۢ(wúNhC'졤yC7$ +>钪nfeDyْ6è#t [Ϫ V ͯmg|jqX(` ^E{~:u<>_+c0gkpΉz1B/&o^c\T ^8 >?0j I昳}?WJPMJs1NNgeIA(m8C sQ]?n3iK$rkM?ҷW^K^WZp<5.T3@DS/fYܬ&E4:=Q$^YפvGmHnp(;yb5tzhODx4CS=/7B4+ ~A!0TD ! #BCp8?C AD#pmyŭRҳ̻%1#qy G˳0 .$Ė2t'k7*-N-KPL'E24A\3q N3lN<\ΠQ'BPt-POSԍ;4%LRNR4=N5 ?QT5KJѴ5u;Vt)Y] H1V1cEdvP!hN` D[gp71*24]s=^'wz w*ߧŀ_y]b'5x'&ih)aiI8n0?lj0Y1 6Kq6'=2r6±r&s"wF>;.Դ&j-3aFmdbŭ+k,SECF:.);SD+=oS3㻾ϫ@P,40)C\rr0',PEZYpƺVhOJ#2DLL]o+K2;m|L%P1f:%N?gU4)@>%oKTOuG|GJRm\z^յ H@7{(UV:VoTh(ʽ%^#n8H?$'w Z} 8h?Ä7G4c9D8\G0H΃v)EVnZouJ@bфs2F ƲgΑ&Z4wiFi8ڳU%.m51s-3mGlF[t=17}}o Q8D \DAn.U!мC 9e-bs` hE taLlu1wm_wo<4(^lI6pN&8XC 2VU|J('}>y?'US<ŪU"~KRY #VQ2*E[Ih%T*.A($"+`zX?U/k}%xD1%G:T5ĹGoSK)g 5OeZ'_FGG&7K$:w2tŎ`W]In>jᱰAHCy!3_2%#Iݒ2RJIfy$rmI( @ràXZK i--Rs&?3kt$j]ǸkrU r׻ź2ݙ+Rj\X;A*g>?o>B|\~qDi]-{(,ֽPJ{g\2?A(ښɜSND ]o"PSG*c%}|a$dNO,E2Ճ5g]+svF^_*eNp(f-gZWܾ]Mu6XZeڗ:o͏h> lbIcŢ6[rhiOV PE:N45lm*TXI~Ώz7ֳ2糍rwę˰TBC >ǟU̖jN }n=ͅڗgFP^ǁ/9VO?ĥ(q7Wb3/C[1 RApAu(Ì8 SvC3&dzf:#q&24:5S, )> @LL@HP1( 9 wаM*a=/%A d@X| $& #Ӭ,3S" ';H)¤+;t,L1\2ɱC;MPPŜ)]ȱм` ûYJd=C?ʄʒ<\D!,G51="k=Ka46HR{(DZL+ O,K7 KʐyYk$@1Ƽlt +GES .NA0Q~8XFXT.ˆV j2ӏGlsL2 H̔t@,zK u+h:hʉδAN<D 5;: !B4D[?Bk@I (;KB;\BQF.It/ JCLԜ45Yu?C>]EAd LmR@P`{2̕MTsh  M)>bԎqb^In)D~+B ,T"#τ%ϕc($4B5V6ImjIQcl㜛nrc]ݚEP8]%\&dMF^&G^.G-|dmnіLפh ie%kX랻k^Zkif$ S¥XǪ­am'Gz_+Xaba! Yp)Kͽ]A큓cFMh @.yY@-a lvnݾ/`u)kH?$nrb!@}#alĹl>8 /Ca?1N6p&ꫜC`\F3fMA˝M&s94`{7AfǂYA OG*%hot͜(@t؂έpu&n=ht=i i%abܾ1]e3ug67ֽcVt.=ZDޡȳTC :,- |d^Eq }qu~~:oF^ge_>r}wDT߇_A4itTZ/[syAl [(&mԏ}xnjW'6>w=9Zg;N9:>Tj` &f~H`…Kߛ%ל."UןZWdć7V./Ho%fOԔuia]P6EmepfPgGhi3~5TJ_nnd_ Ω7r}&JU.w/?e6UF QZ޶_?kσ{_9Y$qf9=1r_I?O%V?Ը}9OUI6L_n\MW6 bYLU/oZ%{}pOUa8'd#*nS&HsB)G_{j47]ף6O1m(xoQ<7  HQ?7Ct_3 v:WO y>|=l?;.~Ե6H.ǒl*1Ll0°8/ .H lS,Jв"*NrGI9:%)"<$IRI?'y?(+2.'E1S!G3,l7sYNs;!χ%?})ETeQM'JҔ5D=NuEHS55QS5%VYlu]WDb\2؇cHe}AӠ6>!qWI9]wo!]w(_fPl[XP<8iR`.&V y)`\ٍdb yŧa*>i*ϳУhُˁwGQb+|_E&̺K/9Ci̾쏳0o%|ҵpc`F|+kqp_83Ny:nϼ#tKt<Z$AtBlnLnx6ٵ%L)JK2ܵ0KLeM1SQ8)D ;)ZB)u:Ԣb A*SiV]C+& Ւ P\?1cܤa 씒H9C `%ln"@puHC*EQb:C6> wCQA !F#٘d.&8?D<, ?LqD`#N ʰq\E1>tQE"4CתJ]KE/)׏3K0;*̳x3M ߜ 5qcfS8'ǜ$䜫9^y۞sy=ODy tԟ* }Sun; 5t; PiSRiK=4p)̉.{ a=KLOYlW}/%?8M)*jBo~ T֪OM4F2J"(E NVU }cPZA3[oRTE]ՌoB5F_9נma,ǐ?,rYCФ?gk7oilt1]=B[Xd('D m9\UZYҟGbOxtbV1?nNߝw~5fLMYI|ť4|PIM oMY MӺzj 21T*c ?qRAY IxY"BVZ %I`[[EweM2?֡͹٬^?*ek8'NU"Hm(zHD8kPdt"A80qL|@!>h GN9Ra ?~a,/>i KWvKKɍ"iH ϊY/Ffp[074Xce(?o ZLɣ0OG~ S-US xzZS-"<R@෿#ͭW:xXBA?F`NN8I|ʾ5G6kC^ bՔ?ezXY5>_pqU@%ۻ{mwD'ޔ O*E`H؅~E+Nɬb)f⮬2w$",JXl"bv\bãh F;J<.x A `ΌN6q**Ɩ'j8̆.#DR*%ʎ lKpL~+ڽMdX/ RlF11MJ, 1+hJH,T_@Yaj/@E:`1낰sp.E},ig>,[!pKҦBOF#B8dj m,Zq 1Ȯ'+/K*Pr* S U"jI"0np8<2@3Do iFPXq^f0jnk&: }.(.?dt2Q E  Qs-KQ}9CtWuUNq<p uXU[a\!u n+R?4?uئRk 20t62:irAB 4 L pNKCTRU%r^rbseDPoDw'${Ej!'@>dg_(#_)GR_*# mNHp"R 4֥,2Jp,KVN(UYcjLlKj.g.* UNџLӶ`V& 6KgQ45궫Q:3jӘ\mqPFcPiEDf[ms@M uXv!7hvN2ND ȼ2[LG>T?UG"F^@Af5n=$+Gv a)GC0VqnWaab0drhB t8crycЁEde ҟme4o)4s`Tw tGł? 5y{G@+Rz~ԥ V~-iKvsUU[UMۆ4j*yiVNQjP}`Yo(S;e=EULQg9ﳤ5VtFiod9hUfs=YؐE\SE +0Ҵ vO 69l^5osA֪I+z̦zA^t /||t_}$'}.l·%ٔ EbùcR={CEFj;W4BB?G+80^C8KgNIЧ8W6 KXkmlˠ8pt}ߡ!j݇gXة$*_qBV%TVsG2ZW~!1ϗ1" L,p$0Dt'$KS0XqըZ> x/9RoO`ms>V 5yIX ѭgYg^+{-fcGG}U9G'}t+FSCt;~ٗbyDpqM'Ytxp3F;@@v{IfǮ𯯇.,Df]gEgGYUIh hVӅgL˹[סz ס[ݢʓjW6½KUKg:?RhCٔh}Ӆ*kƎ {;o\s^%]|<˰Tt%$t(Y~4=AV-D-c:\pșAW*J=  el[I:Rfj䩰(@Qb8a5ḧO4'K)ꊈ AgͷIRMq[x&WuuE[|eֳi=[\qJX M7RlJIRpȗ;μu&Zzt)O7|oԕGϹ\WhUC%To쿷Gep¶6KH!lN&ulRK-593yM=\YNj҆ԦQ7^`r1VrsMy4KK2VNcZ|"4geR3vGZ&E:U٘u@_G\΃0gy-&F{?=^&1_8xeh:6 =jz?-Ә7\нPZ&yu vi#ėvJ-}mMS7^)oΟq?OmIQJK:E-i+ O;\fFڦY{b}n:뷇u˼{ l[ѱޮ{+fl=ϛړAOٶ [wM`E;?ߧjݟZ=F AM]_GRM :7|t' oڢ0q4XqNx>9Wgy%S,βg\+raߞ 3H*RQz!*:>S!+ >:U7> |7(7r^=\b0QW9=kqRfV;W&;Y<9('^_a)/:c1辚!w;>!H>lK4NC뙹$)|S?EDSUElVEy?P9,ŪА8z,ںHyQ?tLb;v-F_rb.R+ծL0 X=3Z:2B*B9 sBZtBkB{dB*hBBk5"(16 r\Ckz_%7{ Sc=0 ~@R>\D>kDd)ꡪxF!vH P3DR9LXE\J{9Œ#E3#dİVjIȄlAɓ %#IDI:YKjCkØ;j5o|p\A tv< wB !ĮzG}a<<\B$+M2HCQ&0HD40$;|4xCް̽h7L N|A8D\BɄ麳cNP웡"$?΁ \\JL,WJ{̩JB)#J]2)P#,INܵ@|| Є身KT=|iN8I C =nLLAշgAt&uM̔B\Lx̼z4͞R|G(GH H4)>QMr=,H{oHOͤKrLKtLËKH=5FPP||D ˋν=PF\c+$P\HD W[zN# #B5@;TTJlPOȗŴT21,!OP%UxmYTb*T`8|1I}P_FKP>+z}N -2%}0MNGf5lǦ"ʦyŶ {M!8'kG$<{R]|Y IdʥK5E)bJJ Y# MOŝϥOs*Oĩ|3jԱ `39mAP]cUܶV mS=Pj2]Q}ho;dVӼLuQWlqW3^\EuGbW|~W~3M{­%W{/ ҍHm*M4qەV77]5͊ZX8> X?Ϋ_, ߝbbh]K]4VmKFQNKQ\qR幝VR[*nrDQ t$`y׭eXvCac;պf&=(ƮSmc}_ӮBN#&D5⅔U(Xգ7I#9cxc/uV" @Â~~$Mx%:1!,bS46@Im_ߌd-:_D@EPdm5]F˵`(}2`KPѶ]~RBFT`RMyG#Xe1'9e|im+͝a(7ؾ X΋Ӟikhlb] fP^pZ~!Z#Z09U`cyg^0&?0:Y/Mn⑄_fD%4VC}bMVM Vv=jL5dͅVNQOjf̈́vqQ B$B5tiTl'LBiM.\\aN]\p5O3]&jf;=j]tj>Hfo#k=r%6_$Qi(iUBu"yvv+)6rs+EneHa]'7=1v$fSMÿ;Su]4\qjs>l1Cbq hZg2to+t٨ ZB# Jt\JЗ Hp,@ zqE]lY>З[x&Fv!u۰qqԍwbqj>m۶,hApoju ֞\oornם"rQsjU53ab.]E?:-}~<71E_o煥 OY^}j03Ěk 6+y@|'O8*p\kW x0:@PlFz]Iqa=iMcL=kGeVvє`e]e=vv@H!!l>D!p4 D?Rw.U)%la2GM_Ts;O Hhj*ERē'SUw])Y%kUX{CЗ-zf&_?s'Oc_??W.Pgs?UPZva(q[Q_UrT=It^_?nwS|o*T{_ꟃ[?XN@wyBG 0P5 GC|PQY%EXp@xZrUH{\/(R*I;+.Kr 0γ2s;c6kJҳs*2Lē\0<KCQ ы 'I-KJK!,S1H*N**)5j(IZVn&$jg^Wg\FX }v2L$RFMh$$B@#::d1mۨ1p"/r#7Z1oZg6bUc޶_pַbu_eXUSST 3LԵGQTUAO>N:33NeM&W~]75e7ټ՜MlNr,;t$2,!oXjYu4\z9lG;ﴟ[y?nW_G ŁßwkR1TtG1*ZW7/zß6rLN+Ћ6>3FK.ح0k-AXrSafr_q}&V/ȗ:Wevim#r__5/'|J^(]X=UVS^Vz0\=AlxMg~wf쌛d𹘧] ل2ÓjkӳӈϦL=Z%dPU}7-"6ngOGBupNŇ`1V)93 K1H"ҴI12D6~Sd:u2V t)1N@;w ]㾔$^4RpuMA`+oH=BD)P5[@rN`J'нJ% y>餵[]p?&an@E4 ,%y:`˸&T`ʄAg,Xn @Ȥ{lP+ 4agXΡ3 "<)DzrKiJ*+3ƸKikYV(9#b6R#әI$T~F9ڍRircF(611Aݢ{vН?Jġe:QRUA)?JyZ*"= *IXA 0|$uL2r-"D؜ }n?I,>q/9ID˰sbehU˘--XVU@%adPhXdhUZ36*I[m-4J?SjM<6z}L\U1jRUMqƕSr):$zdwZ_~ܭK;RHz]œ0®IsmPևZTS3)\lUX~=I0I}|Ω:ųþɣbرCYwdq9ǸNG Zf,x ` (b92z5,=m… II@dC Vm.Cmrp8KszMiZs,i "E^etOi)iι;ҚNjkz?~'$QSoht%.8NV)][ظg JV6VUͣ16ޘyw 3vnԶlv?ۗtx|q2xdY1ot[݀N<-?n{Z-60{k@޿Zc3O͆cƳlWKZhnpyj|a~yN] 'w "0!.Faph?O7][\!*{sM-ʭ>حËX+nڞl@ ޮ.|o&,}k  O݇EKALHlB)M@pFPReX\pP nOr4OvfZo~InnoO O zҊ} \|0] /nLjCLj,ʬQ"p,0, y;un†Ej̜ML^:mcge֜n+=m/01>/6ʯ;kRCFQ,S M~mp0odPOi p LPȇ 'I n q Ϥp H ϵpj~ΖI"qZАQ-}̿Gy#̹MN%o02suw'pN1/-lKJ6eI@;#IWUN1+Њu Qp9NJO 11jr0O0 r Ҳ?2 ,3./O),0$%%g%lM) `P.e1W'[}'w71ms&̎1xpY)W1)ߑa[*sE<Rװ3;; 62Ԣ[-Po /2/P>/>>0 6pJ Zg1"dr';jJ3SA*Dik$M:QaR[)6 h3lZ;7S{FRyFr6&rF 4Dd;4q#22c̎J<3 m\7srS 30>N4NT@0i@o!2%#3q*C4$-4Pٴ9K5O(sdqTgEqF/TV}y'3~S&Rb_1|79UwHhU.IRU3R)J#YT<,f L KL/@H@\0\]TM4.hPfcAʻx7u^!3A/~Vη_o+nmXRvn+oxxOo>skM{6MWs@5Kc_,JgNQn.́`Շt5.Ne2\6+pS~G~Tm2Tu((o)TQңiXpwXncQT#BJvKa9iJ.vg'xUk[`7m1 ^ol_Uz)zγgvو3xWRG|aT*3SSXSҌek&ˋT7_x8R~x_us}X9yi*GI!+WԮ Ӄ íi5wPYy8_t0x:GP29O2jS,dVBux 'QC?fJ|QeاUup7K=7wuR;}w)%/8}X sAyeXst}Zr۞Y2KW1z iϠ JOھ;59Um-"x6 7TQ9Ye8g8[;rYczpȚiqyd Zq0ks̵IX{ڕf#Y8)y,`=yrCy:Ѯٮ;[˷3W6ʱgX18=];Aqus׻}q\iҜeN=31vO[yM!kwm9\aq{<}y+|̺g A@/=I/KS/[N:Ϋ.[!U2U(]WSN5^⸮߷y[)Cfٶ)~X |5sX*YZ2& m2Lzp/=\%s6j,w.Ѵ׵|ZJT)]c6xX2Q\)%jb9#P5=O<6c4R>y34Ef4MB氵C?ıT!.Կ_CR[F-k% .}m]}˹ѢR[S^ޚ}wu.F>m {-7cw?I_c5S^֤H?U/RZÂdUjArƯ8Pa\!һ,Jv5l9R4SԹbfgemֻFڍ~S[UFיּ+pru`s{}fk 6k+89>tꔬM.xuxi5xL%cCqOv| sH³βFHɑ\WHpKDTSh=8?V=ZυqQs?'‚np3mh!`?lXfױ[nc'9[!k+o2kKwP}\jj*\1W|s&a͜8n$TT+G +7k䞧Ǻs}w\vAq[t~kKp,*S8|<*3'Ŧ7;a2v߃v3|=\wmw1>1$ 9RVG㴬8+?RC$[o;^+˺1(ý3tM:);K[<-ɷʋ183ߤ<Pܗ$A@#u)HS q=jA4SE=2=o9ޯL=ߊ*)칃Q0CR9.+;@8!ﲓ[:[:dө?C{i{?ECDdG:H@LK"|6oD,CZK;*X@֏T9kTC@+2~/B`A7ؾ¼,Y齰,%AA<ˋiLn`bBl 3 l==p=e+F-\a t0 ~;S(:ClH)"+{x(q+*">( B04Tmӯ" PVVƼ!q}ʤHxL:K{<Ҩ8N ~AB+SE뙄J*+ \Q;Z;@D yͿ[`ije)рQ|_><1P43MlP$\ʀ):!>)<=21\ O AJ v6$B6;aD%FATP@ AUR @ TJIsopt-2.0.0/images/cameraIP_TV.tiff000066400000000000000000002461141277570055300167320ustar00rootroot00000000000000II*K Ov?0IDaABOyA )cXb&O= ?_?(O5}@dS??57V_;_D67_{c!o\7* ^mv0#?<YO7,dqy 7su g:cj- K6[lnw3?=hw _czOU2M̽ᇽeR3Ry>O/?_o"dP, *cI/\ rZ pd0= CLEB0HIȋ ͍ƨl ,ȒtqiET.- 1U,E"9L1+.#D &DpH]%;Q+4MJ3Љm(MCAD6Rh ')(ΨLCBԴ S(S/N!WeXd=l](^{a IQdHN.@TB JrG gq5r0ړ3,0G{in4՝MvδFJ̷Q>d .hٍDZ(R: u~#\YyS´:h Nඤ/NH6&„O8Yq\k)C2/_MaM.~9Mv7?VՕ^iPDu{,DqLv}If݂ u?Al-[;D^(_|'˴ 12啒SN/HI<9hz;5\G7mfBu!FM,h KJ("Ù*>AvY*uRL"lhU/.xQN0`b?\)V\vm9DDGBJuĐ_9Q2"[4nQ-)vJâ\i@~)&!u͈*m@QJ10A|M-uRm BȌL#KLS|hFHV:RM8d]/ `9<\M`CQAԀjm!B`L]w~VR[)A7CU ]M`L7g5\ 8 ػ72O$ Avܠ#D>i N;A(1=ǟNo?KV8R%O%KXtdbq &@"v@(qe6kc[NYJd"lu~8A$[32[O&m4 6r&O8˥Cy1--<B G8UWAFNB*YLIٳo=Yͮ,T 3ꉪHU>T*v|]~)vmRrKuВB5;(̮{Jq yv|ޖِ)b>-[j+QJ9nǒ`JÐr(CU*d~RIG*CׂQ+n[0kyk[/dtk#LfmXXNN.*lM?(CH3YIBw U4;PDQ0q@8L\?1xF8>GHɉ2CZ)b<5mѡsH]T0!D_șKȨcn !5Q2ۯ .e˸mbGQgC{tQ1DLޑZ#&oM,tuS!?xIZ_- g!1gg[fcLV)TF19s9Xl8uZJv}p#V<\cw۶z _JOC\zٿ{/&SH%_ˣKC&lт@V>o& e,*BRX?o!ψ|kX5F;tmkd7=&adKj- .+i\"m nȱP*Fq#H*+++꾮H,JkV\i RXRϹ* lPJX ][a !ȇEnaB Mt *Ǻ nν'⬁l EE}LLrHI.Gg© :ΎF2\q$ %YG&f2CC>ġNNLI*lFQ.'m3N>d.fO y'pDFDO@|2O;ё*]p_0Лj O.M@3LYGCc- i iA )修v YjF,Q_m")+@VpD6F6AR@钙p:Lh% /.ϰw&hG T[E'(a )0F}OQ) ƣ4D 4Px Gt-FY,-R/BD;;f2Fr.Ҧ)LAO ~*nؤbP^&}Fm\m}dmnG€ 'I*`X>j@[%G_jG(E]z1e.I7tވLdh8cc1";>$-QMJD0NV]GCx3S| ܻi+FS?#ަp 6G O!օ!R'aA@1" m#(O' A,0 2L/KtDM%iJE %>%')qpGat|H)H)z_ nE/<@tm^s|Rii,b C AHS eάG9R}I 50<Ҟk}1#̷"G6г.ͥ1DR1K"g+4+CNЦ^_M)RαEG[-jtF^#MK3W#}Q#3F;4| ;"C-R@,E"SRަFàm%#/A1#k7V ukq9PZ޴gE2^Rf"Z%m!%ʹLiŎTue6`ofal}na"266p<1- tSD FNB0j2\x8@m)P)Ȥȍ A}S9Ȭ#F݉ m* J3R(8 ͢B0XmS8("!$5qbH$а$\+q MC5HyZRnN Dx{&؏JuDȔVBhdFFͤM-;mzV׈u;l_,&m^E@ozױ]iG]S%R޷l2(v|Fo@l#B46da2xCC '\ifoodOz%ڦA= Hn&oaZi8AA]у+ηǒ8UmaSѶq8qLˇQ&oUd=5V)WGOLOK|k";ь2o*2Wa[EmÎ82б$~mc)ȱ@q&cEL=vlBK}Fy&2HREY&[F_ &s&gndsWdmP}bTddxe0XO:ɀaI..꿰@;C h+'Pj4@~% vq+qU6OA~I7qla&B4B3Y84B*ਖ GWxFG2A`$jGK+*ΕKDQ 3V|і-*OsrMXe!0!6@ NrЦxmmK:Zz[xKL=C42dTzeFSaܦ}l94复Py2YSy>K.x5#$[9>L<{(iD}qse% D:eUkpM>RU+ i ]ʹm1'ՑDx2'A/l!w.O$V$+baKdGDZI~O q%"z?aᅾr2_0:;їĐŗK9hx&K @>hj2QTP6 j0KGd>vz6},qSR̟T7-N/a\ x$qѮ3L*_Fнxn.vg շv7i`dnFCj~= KEL@hNY5y=;ĩ95EBDՎG;y%zѤJs3w*~;@Mz: 0S_fKii!600[]M' qJ.Dx3"A l 䦐&[֢۫Ẃ{ybXhfJ[#:_Nj8\ݤڶ_f,7#%̤*QxRe+;[NQ@.ÿVpe.wT4νQ'rZZ~*Coɥh݉oI%DӅa!z|Mu4b[bF| mzv8&;xEYD v$ &x>x`%'c+4ܳ]--9EPd\#dv|`Y~2N)2GC=Z,]P[RDi@KJCdԢ^+•SC^;}h.l5$Zr6>.݂ۘnrɑǕ&\:(=$x>NA}tR/y *A>s[ce*}Ӳ#kǢ|νĈc<$__rL5 /6CQJAJMI8kL xxL "(6dP?ɒY+3_w ,ġb(R.E$+S4MZUjbb60[b4 v\B0S}W;)  x#+dc옼lJ|.;VE 8Ee؜F>l_Y'h mv?|gqnSOp?}s}o*ySGR'_?0@P$%P%ApiBg# B&BP4Dga"MϴQG͓esD2iG5Aq\7Est oW[. z! 6[)崴 n"Jѫ,\>cC|%"d -- 8c8-*X8-׆[|_lvMTϭRgG&9aCc3 G0-& Z{cw [# p5lǺ <{\W}^زj-#់;E/a}]wVS}y|4>j}:N<>]VYi13c'3;3bו[qC0UflKgO\TL'EU1mZ/rvjU4\Q.@Z;W}w`ȒZdS"QT(.e`dS1ƭFV+A--A1Bivx$ͲcS-e\Йm"0[Pp^ \|iYL4tPM$VLͲbVAu9ttۻwˁ%*Olw-*;ZJ5j$DH9g, &T8gA4Juhe :GPI )>y~1/#eUew6PSd#f*YV}jL~j5 iڂ/r-}QwWOM`W{5g(wn{d;QS}ٵCMDbAZ[o.BUxx#PU,EbTY+%D0M(KI01`s#E[d6$݋uW(P,n'P͘p&+@TOuj!8~J,#JY٭$d(>9ONΤ"[]@"V`S4Zb\J٬psk^(#k%|'I z/N&1G TXu>T#syIŢAMH1HY'f" A26f}yM ZrGkeZƆ@T(D.H~YWɰi=G9C'B,U@x2EG kPQA#]Yh\q3̲@!$CcÿMۨnזZ_*,>%Gސ\Jk@2ݻ4&7^p|4nM!ŔӱlF٫8da>asXp JːyP\`?G3㏛Q]뼏K%lEXŲ8lֵ /U.&z(T4lI8_Ӛ7_CP*%E@1@ǯh+fi#@J fBZA17ybY wږqQF1\?2T x"/`됊 pxHU̿܃+Y|&cuT%B ۄ8Ȼnj .ᜰH+Oc 6>d;i "2ոhIھJofJ;C$yV  9wP13;!1ܰ,CʚDj QQB|Cc K>CO+ [zC 3@ +6Cn̸dIC蝨Z(+8#Mkء4,U9,R!Kؖ4+LNQ#Z- TEpіXГ9>¤Fpad Q "KLI[1 w  }zVGٻϸP?6}̮ց &dȋ:g$ ,}-I vb+Z S3C<1L-Pp9h]"A=$DJ&K"C4ƪ%8I>l(:7Ka,Ҍ+'b-dGY[ӼDDD 7{K;KkETL 0 @D$𗈄,H@NLUb-+H 67q1ʘ< #՘vUhȈ ɖ!UdԢ2 #(s5Dts0|KDSw|DZ\*sWrB@|fABh[g R%5D КǗz=:YA19љ/9=0S)s9xZ@s| \$? >hzT{L 8ɻ!Q6int3K#Ҡ䵌Xө,@Muٚ# ;fъ(:**Ӡh@1c BИzJb ѣ#Ч -p<@%m I3P2V ٨U:_ $R]HEj b+CBl9 -PVX]+ KHʷsU LN՘dbK0OI|(K̈5V] g}زkۀWP@h@zYQՖ" _@ߞI`})Φ}|H 4I3 q :ы!2biCHsYݞraJ) 񝑰mvͷ+[hQQ-4l&*mqYV21[ѠQJ3f1*:@D#сA[U|\mP mx{xɨ 1Y]EwNdN]- T^(t*AIE_ip6U\ ъ,JA;F"0b^gE3mZ (|`8_P ZgWCtXA{w.kvxy|Aߌ}ߘXl ,/Q9Y9BHơˆΎmYHRؚsƒ[`H͵}QӰSZd0 p lM[ ӟ2Ed rM(> BB = ٖ 9b>ΗqbiЊ  فrI9iC K,+WT⻊(Pơ ٨3lΊw?Iaw"ʉ Nj-娭בMd qXD_d刎๋ް',O#ZD݊_gyع2oX"_ʎBa$fYgҦ| `8tmYAu9WyMn@3,-bpo Z0j0NsNpQ'.=-ibpq)B)q<]pD`+U lO *-CޞkD8*bvfQ , -pWMsh_8GsȈ"ھ7q6r0( aSxQ0ce.R% 9TYneqNk)TҙUlS ^VO2nV`>1T)QY8 hbQZ!5)J8fW{hJTi;:d^Wl髒=D(ʈtAj72 O.NEk\LEMqѨsNH(Z aQ22`۶+f*Agg?nG[83*cG&xGvO7 gѱCtwwyHgZ:_8C y$!PÄei?̱E!4+?Ųd2M_m;ge3?4y!7Sbe8SD5w?W_c[=K3mUq5TMxL xڟ?ưxhvT͵XWM2i: \4hu(&N4ꪚRsn o5,y[V_>a7QXjwѤ\\0}hԃah>ϒh#*<@Lյ,@\1+5,$)OKp oGE0\2KN2ЀȾ㈺<<㼘=Q#2MJ:Irl;Lȧ/MdпI'6S!<}:$t9 QGAF RRQ"8gENKPih_RMP6X(@m`m\Vb]xU}`WUqZVsBख़FQԨQhQiVV̻/;Nոr! JqD! yGUzۇ|Ӕy~(GohƪLQv-Ѓ,cѵ2,a +0!;f>"* C2S.[-0s^1I3L4{5\ ӹ,d1 9,$x'^;qluV6M+~J{ѧp 0?G0@tBwB' E -D|¼tWD,$] ܐ:1&,uF*` Nw%IJ\+Üwp ]*{S>T8'DtEIT6+P~Wz^%uxպV 5 D)^+u`|DR9~5&.sДU#ȟ31-)Bۙg{9(ĖI0)F1JAiӽ2 K9f 8Ga"q3bxD2d$9MqhC,ZIf ծVcڊ.QI4$>Dɑ5d2|D0M g6yGh"CYq"I410"j.FY)E'\& T95Ara?[\ GN0;sRjQAiLECHˠHFg5 SB| @ܢI`0S}ml- _8RwJ[ ǡ,xi&Sʱ0 7R% E`Һ_U%S!a1bhX N CWOSwOrYW[P*N, C*2X"#3yl3_O%$@\/4?ߝ~"0|"aE)c̔-]̖xC$ۈR%)T'%%=.lYHɄVОi{K iȥxJc`ǗHdq4QY >Wa O V?"ī $nE>oN(k?4)fUlql8k^4@Jb܈e&t.$H\Ad0$GmX.Nx'ÒAbdl{nQM^άb[ |^~Jҹ. "Em  $鰙 *rk,^IGjBB[@ /. Zj-8li~k+P9$Ah=.rir5hb)pXv .r݉fw,KMD.d*R#h"FbΔ:؂z {5QvwZ, gxiBs2ёK4F`^h DlvLjeb4R!@B9 #=ģ"0?)NF3D\#%)@,$BJs"PޯD)dDr12\o$2/$8mQ#:4&,bg' 5+ POFHPBZN'H2b{j̀/r w.܀X &J$(2@9cSֆ!沿M`L#GاL A:@"NIK8 g^ kzMeH \/{CsQRC;5'y6|H\b,\$}TCL!B+g5&P Y@PJ2ra( sUR XfL+~eoH-$q)@N@_#4B?"Jhh@$FB)d9/7)\k&n-GË^W30"X44jK~wjB.{M&F/ jDXZ pco *e0 $I HzV 4TtTAhhihRĄ(G03Kk֌",aIkTM3)\k MãrN8J#WR S@Vk&\3zaEC pD6i5u<+gySLSR#;Xg5Nt U q(d`(RgG6dUb h`-sB$r5$<)L7wB5wb\)FL1&$4*JNbzD/{^Lb"T8z"VyqgU4wv07"Mv\'~\'y/kP b$`r0%H6[eV N+PW6WGHRL)kf1H􍄖YgG(v"w)Æ2 kKԡ;j T~HL ࡉAXF`oK]h@F\9#jQ3U2$o4u p qt&r`!$/wHV=ÑSFa)lcd+Rk3k7V}3id-w]lY1wgb@O{$a&3]Du5+tI#L.,`ܺw9$G;S_~)QM"crwG,:g5v6Mg6=1{iWM&%d! H:}3EVJ*gU RXMrHR턥I: (ɴ/[QAuGFE8CVKeW9H݊oӊ*ZKF@tXy nkshLHˍVF70/dyjz4rL1/w+z"c $;\Vҵc:REg/z7ACLE09$XAB$;)dGVD7:R)D\mEh-I=.X?5)t/?=Mr0Ӥ!0dp):-sГ&ed'RTZ7L[iyf۳:X S,)o[^ !e#R`*YL_;`Su jAl:d vJ.# S'NowNy,s$Fi]8m1L GtnOkZr$]T0Y-v.1ҁ +RV;}K܇/%ӈzWvrV֪Z ۹f{ۯiЈXtXN Z֯XԽ+2]L/7%h\%iK;v+ $Qc0r7v&"ٯ5;~gHICͲ*Ed)Ib w6ψ,.ꥄS,675{Xc=w׫d.GMȇT$n-1:3zGk>8$tiS2L @{Mϯ$t=ҏ*̯@Z)MBCg^Ţ McN],P( +K% %LtXOLxAς=g rV%\/53>D|%_hҍh鼄EROEg??} O T 産1 @)pw0v43yL#%Y#4=|l4y NY.Y2ɉli:qؓ@0xHd?PWaD=rA CF%z;HL2WvQ'%P?SWNq.LTH?ȴZ%II 4uXt@YNo~` 4F&v?Gjjnlv%־qڥZk0x?!eEG0Yv:пšW{PjmsOM6|n[^z | O\=/t-x3 y=/ǻA|O32+J.; :PS 4o0p D'&~%3dL23Bz'q|n#,Vq%8dd#)+?  T#!!3qa%s\Tm1v3V=>Zp@\xC+1`p$%hA]-Btº$ / _a8hy(|r|@?O`A?@}=GNyF3nA/)l"cp?r4\CeP* s7SZcz.H3/@Bӵ*-!*w1>”nѩLD4w 9Rbp}pK'IԴ* YK+6p:!3<Ͱ`e Z qZE[8!|XQz $+ܖh!.iqeȱ43k$,3)h(*Tp%!2{6+LF_Y2eLa?͇ydN ?GV(e3jIgJ#p I7&4;'N i'}mrU#k[MK$8Oy>=* uVA?Uߙ7L7 !r fTc_:X#2,w|'f]MςXeeA>Ǟ1fUPX .Mԏ..v%V\h9sty[hFJ_9'上yP4zOVS8mjC)!r+d[ ,⼃>VˢЬpFDyALtEC!Zu ]Vd́^eZ{Kj-P!j߶k|p>`I{mݸK*tFifhѭ5.q D(ȸ`^Ϙe_ ]G:*ZI]c:NKs*b)> 0AM;# r*j=$;! r<'!˓~!1X v9KZ(_%nTA~4׍nt">,7!^k0wOpjA8}~E"ÎK dˉ)Xc ꄜyѝ)PSS8ѥ+ ;j] 33ss)!#Ֆi9gA`) /.AAБ9s1@)B31⣕9H;C<R23> * s?3˲@?.<2P$69CT5 еʍD-A<ѵ|<%Qk]F ēA5>> \+,:Qx @-JՋ[E`WREb;6P C@@A;B3=B,2c&ZS  ;(-+F4?G7D?(GP`w2`6GCݬ1;Yah + Y%ZC919h 'Ai$ *`̐󥌴 3-H9$"Z: (AFQD<;[R9Fح3.J1+(ᛌ;CUE<=D:K%t@##WD,%M(5#C\hύIWL4\QcVh] =SCJx =#6ͺ534q@O<ߖoDXܐN&iab4qD=.^YOU~P͗ԱА[4ɟt/9 ?QD V t:n{|'cVc>@ꮢ!a3, ,Ϻ̗0A v ,.VsFfl[RBl4[>Sm]Ik־fc~`6bIAfJ= auDcta–LPyg"qo%Y&9!VaR?ر3~,[HKԪIgx$!#OoN.l6-ըZE<.(? wNhU<_6̻v 'A{$-c5DŌ5_iŬ([93om\QCQ"KCh^ e⺮kC^ߌ ͺ,{iMu~4--N9.!5Q-Ŧ+EK vTf] 9pqLtY1բZַcV!qרjܬ>>_&Z.; 0 @ӶnBm G(Qo"o0pG ?q0Iɟ,*ͣ:ւ̠lC1nFA`\=&OS^J/u2VwO72MlvN(iQz埬UajZƓ"?tǧdIn"J%%$ןK? 0.Ү 8̱#m6dʹiL 2ЩmA0+ ɻ{/ds?"D(8I4.;P?QeFdLIȼ?”ahQ*FWa1ր4<' |2'Jf@ ]crDR&DITpa%䴙r2m$dP$2VxR+M*9*լ7 g$p #tO;'17NYk|ӻ BCM<rN9 x:e˜1qC%&ؐ?/@,ęI12I[ QVHT#|흰{b!2UѫzhJWK-9бw"\)F L9#0S\_Q&/ }1l+Wx L~vPj(j59ZɶA8lkdfʦJn@7w]ʕmSeĝlV1A:`ZYnsuD[#y=xA'4˹ &s#:g0m:gro,;ZiWqcVMiDCj[tVO[YY_r@:-|?ž}I'ttQK0g=l+Xq:'D[n5D^ 7Pf*}^|#Wף 2E{)Q̽лdQ3&6}Pv8Os 9[LbJm:oņiHd[Z6\'4%0. ̑y6J%zFvHkJ;qD$;!\FR^&7YJu5aT Q)kK@x fOKGwCsB4wҠI S]HeBi 1,?khn()g+ޛ@E*M+!Ҹ}+ljra1Pƒ vcpɆ XhxrEa30澩1cfƣs8Qf1K ꬽF QZ4Ld`gusJd4sdZ6O6uc3eW7s E4H, 7S. t̄D@Lk0@`2\}s5%7C?3rgo5dQO6td5lOj6sc7U4Sg313Tf*--7TO?9TP2=.sg6R6US)V A_Bdn6nhM}ptkvdo]p\>#Mpj&&p qDKE+xsJD?=r>8:(wMYSqphF[ ?/>d[L[psXZ@ J !'~IoxxyEszCH㒗]w- ەI pῗa (V%n܀Y(pT7-؍6V{/a[L`+(-F-kI 2S3oSkRiXVXxdf6ZT_pOprGvon 7Qx{mgbh8f/ e8h84cS>.#ًxۘ*My@=W]SK׍RVaaY#Εp ڃR=Zw\_8N@a"Xk/$7@n:r %d'x /ET 㼖C-kUe2a0vjB(,ԝ7"qih,y'3&8 b9KJ8Oeɜ9f@G2&8ެ6C$ 91lSI؛S(Q"7h;dv\.9Aig(Zn{i ׃;Ϊ:[؉4MQ{'7 Y\RQB fL+Bh1r=ڇ"U(i>+ 7k?څ5E<5eQx/xa7Z΢ %5^S0gIp*(-gfteɶac(_H"W%ͺ;16]0|&30A@S "D@Y.{_#P,"5ȭ$5Dzcv%Aƾq~cцqvOQvdxwD.?*jX0 (;u92Q&>$ץuf Trk{'Ν" cY\ڀ<#w,>=|#ݟYõU!ޡ!~s: ^ =*uyc>Q}LUXJezfY2XWJ>L%Y={);|!T_K~i(]~p<>p&j{?6gG4FRhvra([bV\?}K ] vyכ>`g}~oh;o@C ;p(d :Ь:@p+JҵqTT?E8׶.Qf>GY<g#Ra-I)LB@IGKga/LG# 3A g79 n)XA@ZKS8I*ºhM7,J7O*#d3ap U-YjU+g^?Pt,̓섫▮ص?EST AbسUD[pZ5ErAp](eر2PELM{1e|1wŕ`TxK"39T9ޮ" 3L;6b-~J`,6=Nycϗ=p,eP9 /4Bl2}gD1y֚õ/#&催ё:j- b;a'm@tuj(,Wt2migK7"\Pr0ŧv?tAV-KH/ZMq]CsTqM"G@^FI׶xzvZ_|mC^kO7AC}T'BU@EKx=svwzO#XQReWNt B RUX0[&SdP(V]>T`kR`?\.;l·ΫCQP s4ǢA=׾f{o8\cFOAE"[\/w-ްcn\U*rldf &EPAP>c +&FJ! tvIQ i4\,Q< tz9G[l qPE # Cu &V"KIŚ}"_pPRHU G,r?Mˑ մjyd?={{i L3t5bdqN1 { ?ƵMb˒ŭpfж J6WEV[VUFx@jKp?]DW@^V@:A|qGTd.~SD?V_v\/'5O@j?eIR Ń"i- nA˄3PA[[ XA(Qۀ)Nffj##gEJbq'bmSqEU!"_%#Oq#D IU+Ćų#T?f[7/GʘDLPZ@SRlڋdΕfG](%@Ŭɠa:J_t27eڭ" tGy52JI*ŰPJ,40f6M5ٲ^I:5 u4n; l{so1B X4)jC~v}{gm K ]rE!s E M^8c,out@I_Nd̺ \'UV*\m58c>9V7@M3V;f9..QZ}C0¸q 6MYs-UrMG0-؋WOS*ܱ5BBfpbQ?ſcU+fdv(TyÉE4J?{I *S tF%gwWHM񯝤%X,񴾜_5GRsx (_i;> si=dB& ~2%ޭkW ,'Ԛ I 0DACAE$@;K{5$T+tS:sz%+Ż5?,IE-zgKF(# "!{ƚ)z0,RH.:K2zĒE ^E4Uo+zŤoGr$+rG|w|T^2pͧAC@:z?ω-z=#>j:YIA-)` 2!08 8@ѢÐA1Ì ! I DܠoJJ,onJhhʘX|JiJuS 9<BHK(B̂<)SE4;l>łCҝ<ɼJLL |XDlS("K9dKNLMGoRI-z"CLO9|DSMES|CqTz= HtEX`ȶ_=+٬[ G|zNi%FpѭDĚ8[[3 I8یc-,v3[f8ջ`X@&KGBQUZ6HUnKLdY%R֣ N푁{BMײBWV] .;k W0h^a\X~奌jNw %~S?KŒfIMt. _t$$"BPtLT-Bw)[ŭP}̅g}greZJFgph}Q%tK>^%W2 f\i5ji)BL9i]=+i6ab%f4ȿl+bПqJlX h⸨>?+ͭ,RU*5S41v[D҅*>ɞfWƂ`d'PÄ;Cɵ!;sSژ[n NA]h.OB ;Zmfe맩LÔ>]ug,Rkf9[La^J\}Pp6q%NjNEdTߍT.ii6h^,gvn+&^F,Z܂*dXq gal3r=ڼLY{ bnL2eYxaݚƞ; b258 h+05i [&9jް~;j&Im&:Ig qҾkn%r3H8Hk/5^A魚 [#eq7DDU$OVt,(h<Rخ>4SOѲ|lemCUHDUl)  Zf,(,drԦ}i fy}B;BLtulh_W2e81b$;E)>YE`.$L,9EDҼP|x`4osnQagVlI?+ǧ{4NI;4AA)4ZOLq%+МJ)z9Qx!ۖ6q7n;9N[wy$F>kw"Duc򄗗K`@LDЮ(x&fuf^_oEX_md?LEl$MIm VShB|(_˞Ϧ\2mPϲd;ZMᥗL\VХX}2qQ´WTgZaYuZJueM]]HJ>O-'H7dS;OH`Fw^֧k4uD^L^E&|+Gԥ]_7;AGIEJoXZ)ŧ;(mggCwa#s;{zY[|Io!ډМ G'S Кȳ.'@ԶCg1Iī(7 XŀQgt[QEC> CQGM&,*2UG[.D?LҸ8N U6sMa)NʺƊ@< !'TBG]DhUEhRxN'WL8sf J5 [{՜ >*V(1u^0V/Xdբ[vu)ʂ2ݯ`pʊ\"z t x(ި]uH7|#&}$v_={aH]݂I$8 b]X7X<\9!0@YY1P(flg{GQ঑eri6QdYY6 9BG0:Y@mBY>O8oG-z7Ջc‘% "xvֆv [קoG`MMڟp]әɈ |`o@TYn_EG3>+]oG_ƑmRXbF~GTW,r[.K?Y ?< ;n})rz=+VP* B*hPLp-RJPc SG ;wݻn`9CwvbsYӸV_qV*Ex]H.?e(?'{ z@<4ZޓYHoH̘pރS<i?tv=͖cn$/-3J}q , Y1ߧ+xqogⱛϽ-d,}25Gk6I 'oP pQH)ze=]-u~"ri-Xji#K+%CWeR,/ ?uUZPDu}Zt|YfQUrOO n RCXkX|ye%dʒK bQ1W_,,7T\*E;HaTJģa]aMxH[O!4]G)mەmaKFCpĝbZ읓-ou) 0̈\e,nԮ^?Ezs$g0Z& |bN5^8UV|kq3W2Y!m5ڶtk7!,lһ4Y(8x#CyО xGJc x׎9uԼyXK^i;#2fVB B',5;iJQMHU2UEtњb8U|ۚZc}AiD 0[S֊[qy=H^#TH.jJՀ3ik#dzEȋalCԶt&Ns~{[ٝugͥ8 =+l-aq"&Jlkd{kRgqnE{~C,ɫt0+Jʍ^\٤vR a;#3 5iKp@?o :g+#h[ۥf~`qpyr~S6C`5b(eø@ݻNGiA^00.f^`p\*XNƬnO# I T*,PIꞮa JNݭhNTPl˰ I/  11 KKo10JOl2[($ԆVʯX ,'"qpyǜϊ1o|MK7jTPNjC*1 `]͞ioo -Qd 2%K~ʐ"I\Ȅpb1zlg" CT5>j 2z0$q$Aqe!Rc `!n'Plt/l43(/($Lg' Q )%)p=JXC~JdԠ PT|p|nVH~(Ih<*QMLD2s*J3'=3/ `J4G4hs>e13>>+F2I/b@dlCd, [:lT,p:;o.l#f#9cpoPa !E; FRnm'pG)pl_)n**]2!F.tfJ48m+eɁ h)\}2120k _#u *]Фo)iq+24((9Hc2E.50uQ!(ty)2u)6L/ SNS34Tn355s'AOuc E /*+gI 27N*nGB2 T3-PP %[[J{$EoZбZ wmTlݳ=]SS?3@^f%];1AQ^͖]Zdp4)ҙbH.M%~v1\qwDHj'b$.F00DffVsPX2 ~l㉛#K'"lN`4JV)е\vG LTtmbS%k.>)ⴁlpa)p31u_QIV-U1ž[~ N?hV!&ˑIR(ILK7T5uN~DL/r1s'T'T5uW2OLV5ʀVjo4Yv*5Xbst c?K̢F7[/.[peF5n0LT\PRJ -l`-i r?i |33<7ؒB aku@bvmfhxx ዂ35g!~mW9 Pr2h/3'uVEZPaArtM/5,2%!"n(r*powc'K5iISuʻqQ+z7plM?QΊX.lr2F4cnxiGIqR!1$J3U1AsB.IwQ7R9Uu6v=5tO<֠/1czt!B/D+3 Sw%nqRk/6lrU$ 856 F>K]| W_9ភb c bW^3djXZX#az"ᓢᙣP >0,Svw"DrqAwG$ZH3j{o$ʧ?/3aiXaAiڇGjlpaj|Zi,% _يV묹uꅎ88 c-F+zb1ՐljO);Ѝcx;O[{ (q(w10m98m5,J5)9c#hT2#-Rk v)RF0nvO*ס11.ҝXCIS>)*^2%7J+9*jj'"طϱ_KY5OΒ;ռ zZˡrH6qgZx)Zut $suU<#%.pEzØ8|37!:Qwjj16'"'ɮz ̹uC Cˬcim8 g/9ZE.j-N Cjx[u5!u|(mVucjM6)Xv0M gMhVV13r:yP>On*03Nt[li\nWgvpxCءpkZ 46Ǐ(=9ӻ?}~὏ƸW~wO}9#a3zk!]!Z3o 1sEH,%홼v "~ؐRi s%WvGTsǘphVj悕BBWi_(ru,iii7F0?nw4ЍIZ5CCу3lvz7͑,Kacrn{Irw7~?}Wװ+]·}+wJϟ.zsze&_L- RVgYrdk$ϑ@jj:0l?[Ӝ@sg#4-Ѹ[s\m/.i p|,3p۶F+.ǽ//r>r&/e\20 =w= JiWӴ@)p393e&Ɠ-O|"Or/,MJr߿"O2ώ4GT(}sOzי_N\m](Y]U@+rS r.XF )XC A GK_ V?D/5Y`?7GĈ 8!"29p @QԆUCdW-ECk( F>) LyBIXb䐍H/3[K`*L3–ƉZhᳶ w ЮH ~Gboyص# +N;Z*W3HqE؍CqRU7m&"8-` 6xKT/9G,s'9W,u;Gh׷wblA 7tBS3~@$_#z4E񥷰u{nR4i13 Hsz҉K-P*y쀓TC(,$qHO!D1UX%",GaZCH{( zZD_.5tZV9 #48+%-?<A=d;8u|4F%5 Av[/ˁ*Sv0G$0Jy+.bܘ ԷY *^5wn̸qFu0[¼wcnf57sLŶ]4 Eqn)9f۝`)0o`y?3xtwAh-ܩp ]eȐC)zQE)fQZmV6O>S2kƹ':%M,#uxUyGaH6D^_9C(UV  Hʴ:7sP`$Z". $8&|uvSvt|!"T%(MT}=qcdΠBQ Q3\4LRY1%yL+G~g~Xr[|XØdI2ǯK') d~wEԫSnqΒ.@ (Y#x'B\](i3 =0ϯ޻z7d _2t@C}O@@ :T֩)Vb^9_%?~8~/ѴqW|vÿWn{xor߄`x3Cr8*ȸ$0 * T d󞱃s2 "A4A92D:!1|zI6p3J%2B2An38& #ABr);04'.Ra7:!C¼b"=)ʀTXD$0 \-1(ѐZũY|^>͌_E ؿ?IFH⥈pƴlFm7i?4jN m >ĨF0ĥZ1G)zxr$ɯ8.TG~6<~OzBD܄9LB2I@cA3tЅ4\:91K έ { DX4 O,QH@ <'bbcRD Jʦ9O #,+ I2UѴɢ-!Q8IPT갽GdPLyL*:B*߾VhљD*Թk\EQYpE>lͅJMη|kF\忡Ő2N< D7Q UXN aK"T%Ō LKame$D둪 Q+ *%-lPM Hk %A A=nd ASϊIL#94bVQKt'RR-"R>t\zɻ$.Y,@X`م,1ĠC*!R$Ey|dIөCz]L* ;<ȫʡ͝I YTEDEFZHԽJ[D[M[%jFo%&=&86 U'I IV(8VEefOl'H-}-Qъ득/9vW=sе :u]V]meoȭu}׌ҢIWЫ]H]O)CM<-[i,akʻ sXܭV(HY1t4}>"* \ ZcZ uÍfJO d ,4"u= !_!K /PRh7UN$kl7°7 bAA؝''UcdOܥ˜\ԁ/C ؤ1"yU%pWP[&uI5uW[(Az|!E1, A':dEMdj14뛽$0oYf}8X /^XxTd[i[ qmg-]N..ob_`[.UsU$-Y%~XV)'b ܚDbE$EcB 3ju +kf1i1騤/k4L!21γOyM$3#Maż^ibK<0[eYr4dKB=8ĦflRӛףK! lhџ@Uk0 q>% ~ۉxn{gmnU 5Pz[[hKy%Ƭnm.".hbo&0=NiTdYiF3ꁊ)ķJnݍݛG):Ωcw]fxBA5oƮc5~^0v*3*ͼ@e0G~&JrG#HR)^]^XrW|Z6̔05Z\NE$Z]> ɘIVG: n&k g I-HŀnڶߦN#M@6.an}S=Nu Zb#q/"5ku$ZoUeLv9έio"*ȵEa^;p*vǑ|ɒv9j]u2Ȼq` a8b&$lS|t_V7ψ[Oy+g,GYl޷pH9 in2;N5;O03$?@jzƵjL^i21HnDInlU t@pK4{L}ʵŇ\5в! hKEjB7`Aü'&orP'˲ ZI,$7 IVD8Elábሱ"1?5wKcD׈f!S&;`)ƋG3cΑCZ8(By# >uP3[9Hނmg$BoRE$U!G 7,ݤ&lM$G܆OP$})BE+Tz/MʁfMI1dMpl\hEMlW\-Meӌ)c:P**c}SK- 32; KW&1_ !)㮵XKH@U$x'A^Q @'涏JE98p5&C3LaP¡6_XQEC؄db%P("(V쎬jjO/ ߤf.w[6[n]yAgݴh_~Njc[r cp X'dz@FCȗ$䋁hINd"DH)?-@VlᎤGӥ[}8$Cǀa.CtN +s d` Nl $)@l#;%+,ZdY *ˡ&@뒾I'EQ>f(@EaҜ2:2Ea Ғ2ag|A,! Rw| H%1RA/2/@/cr$:#w  s$L&!Es93ePA4Q$qXL*R\3f17"*p.*p6.bӘER Rޒ  .7!ck(.tP0~V8Ĵn %HRG $$Q V&=jlflkRDLm)'T'+2.Jo5(NѤ m+XF>lI ҍ,d:uK{`s7')L$Xx)0nے :1g: 2q|!hLb,j'3G"U4t415T42.4lP',lȓx`(L 8"q/D.2qmJ Mwsb*#m!2fv:Cz4JNȬ- \U1.8c< n.$lG:G ;aJsR3Xtƒ[NE0tgq$TĦ634nBZK2T6V$]O6]tȈMf)˜-lɂ_0:a "PE9VQhRaT:#ih"dm"r5@{ a29?@rO@3K Cgqn0p- E2q&mop fVYi qA`r3@r]%siCF@cs WDtItG.TtHK BD@7pwg\v [I"u4eJ#;6R OM5x.#3$7{4\G5w|qJT]Y}6T,+}6a7bfp`6u8PLQh&4r yUu'SSojIq"Tcsd9UUUdܛV&=zm'WovodFpvGBVՕBN)_M%I$Zji!wR%tŋaV-xu!( oUokp_H)j귏1Phqn~ѥJ|,N([cBUct4%)5K|Wʡ+NI H۔~gNwha9c32v Ϲ6Rم1 Q-!TCxp}ks(N֯\'#r_l*0ؖ'XMME[5 Ü(U8՞0U yT/t܇cF QMr r2nRruvR򠣎k9jS7 ic+J[|„aF)zё7467{lfEY0S$dge=}AYJ쇪-l*"Vug0{9e+PF+89_sr  PS7Vl4yHx#MEo|n\ݸ}ϢqEGHa: `dTRCd;zMzqЧ3}{O}"bӕ%1#q={ֻ/639SF?gm\tC?UݥPlٺ9o.C=/7[}ͤXwR$Ui}Uy={gDө*b +)q{&Dwrv٥5K=c0Ll#6ZaQ$R4B{Lyc9ڥh[ejB.D*w՜e|+6 1Zn k!. `h{'xa$Jh'dIT= e RQ3s}=u ?4E(Mh*NjzZYRA5^ch[mh`@6BQel_BXsaVqx`y`1/׻UzڛvYQ6GeR]r_~w-iDu<>Gm7^|wn?w["WFHtA&# 2 tCDQ FEg$cFDj1oQtTT$??LY2).A*E/ET[̇5M3\D͓|8Nd4Τ1CsB{Aq >/4eFф H+J*?g6?CNӔAQEL?!Ud%Vְ_u]^#N% %b$p:nIrA'ilγ5ʍ%[5n,brJLڣ˥wwu"<̰:;(2A }g+4n5K!(^bF.̰p/ A+g:n:Jޙgggl=OHCzd+:YY]%pM~C&!f?DT=Cl9- q AgAHo<zh:'q$EQTY(41r 4N\5=/QНw]D4WgҝLwKQ-CUUWxXkuYmm6&óly޽b{趲%%o1h7?~cm-_JnWX)ع/%ױwg 6@ffY0`0LK hѧa幉BxM M,w `g4k(p?ü;%Cċ3`@2:h`'NQ 1TȰ?[jG5X}ګ[Z/=gHk aWhC{qq-T:rީ? R[GC#RJpGG7ܓ n=(d&NLK MΧ>]t.S:iP(|RnLWf^ x>ixUVor4+yQcIV"XQeL,YhbKt.cE߼/V1:{,0! G3h̔6 c@̡D+< EDa;бGJ ~@H#t&?+a,,)4lJ4P[{r.Z.i&#b c1* C4E'H>Z9AȊkZI'"SMY4IS=LQyK*]MurU]nZxr^6GiՋ׵56E{Ua[ K ۛ$ޥ .)F(Ӯ?qWNpD/y }؂@/xGpPV)U,ڈIrWx܋Gd%_dR"DQN x(L ? CwJ> v }!?O[kTqRUn;7$ܶ;rIMJ(Xȕ#߫h'&d{ERGW*V 9>Cr'?i>YlelS.ZhM ϚĖc;rM΋U o#|De t%x.uՐ`:j\_iA?(&0%9vbe?< -ٔ_ .:I:Btv8cG@܃n}yJa){zݠm|u(\MY#5^638׃cx}L0RD%4"xnŒAUwʤ=弽%ebr&d˚sO4'gWjvABJ볶u;"%ګϡ3PUq4nhQ eұvvy{V\㝺\}htWݒɀ&eCA6ި<&W@w[6״1fbaG7;p=> p?3kbWr^QGTWV=^}t3-V-":$W*ˇ' M7Sq+D|o&qDFVH#*2?0I0p{39 93q9%%N3Q+:s:@ۧ#<; FI)b& [{ L& 4B r6t#˺ø<3W 5(̋[!q27#WJ$sʰ4d Be>yM9/| 933D   %l@X%̞,ϥRѭ\AdY'{-T4|~;~gؐ06d&BC6O<xkdâ'63BЊRx(BK]CڨxĖxü6s6C7?/J M{٪4"#*Y# k1sc,P2d>P7@d!B +L s @t H;2. 9FF4L`qG Lܤ,9FR& 9Ts=Lx[Ź$D~d}MA: 3L<*>$Ԋ;9BW'8}(6LRv6rӁLJ,1GF. /dɣRoꀁ\Jx'3"",P)iJX0XX0NK #PSi44:a$$*њ1&8!JAl">F|{.ƫk1,L 3LmF겲3| r/9JGK<,ĜKĴxnj1Q;͙鴌EM:ޓKB\/uBBSɌ)H<ɅFN]BjC'HO9΃P2U$Ѩ WQO!;;U\0{8qJ!1NӋ,'0%V{glJ9 &E1QLepl]`"G4(,.YoM-\{ %cVW*Ѓ0s>C]ȴ(nqX[|jn.4zAQEWuD^li}]dɬV(t{tCp uM7Q#uF1c4LŇlyY6sko% װdUqsZ/hw?iȮqdQ-䝷'ibׯjZ5zˆ J}wo)R ˚"?l! 9s[׈~V]jDbñ&xfcx1KGCs~tUQ}%+/ƙ5!y.݉R>,Lݙye۬S./ǛpxLe=ø|fʴ23 z^!+~dv'Ow_t`@.0C1#w׍\D ($  xt8QXF?qD_Cs+a2M_;g5z?Ĕwn Sa6QÀwVK_3c,[=u.K[_[)s[iGNr]M^ox6 q=$2AfĎ{Cit|5jrAjLo6(."r-?]w#/7~o/?О A~o 0Y>l?B CACđ4Bw8<\޷cHpвqȰL~.+2 '*j,ʂ4r K2K0J3K28:hl9O3;OZ;?#?T4S;FutRXPM`ACT$seF5YXL+ p50WձE`%9qGfU[!,R@ [7GQб,Tzw$ȋz޿_lE0Frҷ2Ɇ`x_뀰W~&+ G7NuDSTps̚5a0M(#!/AZ k譒K㔌M.Cz4v5C xhM" :Tѩ[EhM2&+ejZTkt\vlc=r9vTs:rIȷI$i9Ҝ+[2BI5[<֭I[u>`+pR5< =bjҴP^c²+K4?xe3m$řfjѵƈ[C[˅/4踳uYA2m$ԔMO"똈( -یqٯv-E52X(tZPӟEϣlAGm._E-(%DP}3CQE"Zrkޫ( Fa7z30 ]Ի/K1MQ'ad?>5/D9T=*i~c䱐D*b+#R ̛ej^ץ;"}VQ63W䁾m=NO=q:KQ_g]i##rh܀a*4L?Ym~MJe -ŵA|K_DsOALeP/uȴ㈋%H_ݓ}0=7_ODtbU0j&+"XFjmAt1Ww|߈HŻH:M#RJ8 WSȜ?qx[KC!\%+Mi99CfxZ_#:k^ndI 5U)o <~dwwAP?GMX tGNCRX.U`Sie&cq;P^[g{^<ow^OBuc7wBsDNVϲoᷥqH|&>l!44pFi4S `԰bk(ul$QXǙݿ˹_̌? .>w¼&kwS #*X2K5,qۑx?ߋz_$}h ɬVr/v* `T,&j[* u0> la<Ψ62YA뮫av-jPvz/  OK "n'%ުԏ0ꘟo jIޏ"̃ ֌ ޅP"aFR0;;B<SQ>ͮ1@*`DۤV*i(L2֊ ?#f+/ Zb̜XI ʵP5U+ қ̈,Ft4Dt N 첓Ӈʷ(xd-(b[:[$\qqcHEq.! o0p2["r'|Μ8o:((I#DJfзX- ( jߐ e% $3u-b,P$V\*0e&Yþ-*D1*oMT t3䬧Nbw5%)1qP['DQ#fD+Sx">!>TA uJU (MU#QVuf o=s=S=~!XKFjj /?5;?u$h@r_ %h%b4ABnE$( ԓC,ACl0|ҝD򢿱ECԆEZͯ+k,RD,"A!,Hlo.l:lI6t^&Z,WJj-԰d0l4A͠nvgZOM3 Ǐ51x)I2 pN*nSľvR2 AjPP~?d CJR%R pXk`)eگn vnV >SlțjklVjYp r!u}WHAorA*oPS+mV?u`y/u P@O[ϳ& &©u!v\b x2-) ؋etG^e-^f]E^c qFcGt~{afTtյvcIcF,*~GKħk0zK=F$hM N?53V|X 8#>L`jӸ7WVrSb%sL.~ -,&'dM-nnWEy,/N`ӇWpxᧈ aWŞZ!]K2u@+()wY3m8o +cIu1UJ;ZJX] JuB5\b.L461l 0(ddDmkycĿz _Oi{-_i`&z`'v#w}mrsv[[Q}kddzjKl f` uPMiѤYhP7P9h'1hP'!ir Y^t!j֪N~ Nj@A 7WBe?UTRar]. `VSbୡ@O@hS>t*@ldAcץi}@YuOuūv٧wnBϘW(^EcIx)D\ y#yƃh9@izì{)`a`yw+[dv0_:n ZR]7O9y=N]P[Mq9gqN4,w8Mn4e ;@;Sѵf& msR vh9JXK1QI,'%b +wypWT@4]"P? 1ջqRqL6@ncbӍU:ax@ǖX&d.5m{ :o+7{]*y :YyFf|yc(++r?Zz9{D DVw4wŚ]R+Ż,HyҪbxg \sٶxMt49pO(v`NXDƌmɏߵY֏shv LXAXA|dCXpXkTסkֆtO`uz=V[,ӌ׽XՖ=MZgZźɿ .uByMHbðA^M*"gu]gh9$?UOjGz񽤕>P3 f]AIӥM[7]zbsAmb6)ۍ{H):(=D݉< =] >97ڹC{9>wf۹] 7pa;/Ěn7d?:,#Ѯ8ӑ"{͑~6~ %N't4GJRiNOo]Q)u:VUV+-i$k5[q.;!m\Q]8DVEbqsd(1̡=B4+ j(G aؠv@P7=?syVG~u=P%މt??_N~T(?9@OA'OP§? B0E$>qCQ1'<^qƧdwG"Hr4}rQ%rd&Ȓ#xK2|)rJR.L.̲t̀L"2X:OO@1Q'QhlpͲ4Ise/-M@ tHQA8Q-V.Cm^cYW'Q^Wurፇ\WUQ_YMq6@[6ۨPB73dA?iBV? E?|#/:r/e(B+n+za  : ú/8Gd,.FlTPNQ2,+Hϴ-Lյ[m;nAat3|9ZSj.s;cbJb. /_rz#|2r3Gy;!9p|$PB5EPMU 7[*2=5+NSWGv4+LݟmKS=JMӄ(h: yxMV WXR^{4uJxx1<D3:l?u⪅>MC~"$*GPaBW~EIaB ' iTR17@rCIA)@)] j40D!JHg(Jo-NED& s$RaIEI [{ct1?lgі2Zj*eF=W)_L.gf<4HaYŃ6f4 d"H{)"cNY8X%M" rQ{YϣxBS $)Ee k.~2Oqks"7$[Q"c͚I?w)FM>K`^Ol?j}G;r +G@KSnm݇_v [`*u϶')zʝ¸tܻu,|٬ wS@-mۗ@UBUSPПZ(W%mb^VbDن#ؙŲZ_kc"75#khf kp̲j3;l]&A#d[S:vD䰢;%4,nqQk96T7X%S ,o5~z**?Fa.Zñ3!J^9w&ֺ[GgL unfS[m`+˷_"QPp=?۠*7p _٧[f}U ] ㄰rrHI;cLg=/o"sΐ= ?Q%0yg..JڠZ)mlNԝQZ+AW&.thb{2E[sNk͹gcaey8o: 'oh6CrѶWIH;l8<{W~&^jԦ' -#|ҵ )^䥢#j\kI_v`?VgxSz̍/HsoQ *&1Կu]ۻ3L8}1܁>7G>풊,~/C(pk%Z3ʎ\KI)38 | 3I悠c  x['bh= 7H>A@=T=LcH ` *SS XAv5S' D$"02:b)L0(*EKB9;C3::;?P4*¬`ػ9;=;Gx @ChP(*ؗA *ƹDxsDkVĩ¢ %[0G{Ѩs(2;郀ĆaY$нeZbFo6Ҁ*͂Fȴ%ȡ@>F7AiG!H*b/nNdsʄ\w 1|@ۋHꞺ 4+FCG@)%OL 0HXp L\8 3"KO,,"I%K鋺@D¬Bԥ:ԦJ{ʃ;ʐ̙>S>;RC4LK+C;HԷ,!ɣ5dIlDUrUYL!S<<Y )S SD;x9S 4_dp,=C5EA M*Ԓ!M*8W0SM8]Q巴(J,:5X. 0s=#5bCqt",:R=;DrHRzH< Yᇤ%, C51<0 3-RS8KPDw.4rTlqy]D EC<^Ųiyja$UQXć%e?0e[9[oNTYՕ ΃\Zә OUa]qVC򑸅OSe[ V, h%YlހW%sW}!X,Ĉ:$BXmyJ10J5+i:ɒ\/ʻ=>C0Ι;cu M8aKFh$m e+.+1RPRZSM<+%|ÐYZƪ1]0\ib l]BM[F%Uە%JdHRYQcmbXϼ@"C D}ReSU5oes4QP=+]d)8@$HĀǨ-䄕(X(-ᜐ_NObX5l܁5i<݀P_"<,"RŃ4D}۪ۨJ<+3eu2=BY CD`.n`>K#C$Y$}%;଺2@2` 3YZva^n^%~9Ҹ)(PUXűE$P5\V⍺i6(iF)i=fVN0iX&u1L4VrwƝEc096lH'4jޙ=gHBV>F!FE]BN︃Gt'Q=M:cpAk^::,)Lj)~V|evgS(E_$#Җw,bBصBf#HBջԫ?rY]QEYBEn亖n@Y.gPl6a4yg~_zn{)DRX!rSNa{ڑD cy uDmy86#^$havЄ~'E? n#p6|4šH޴ewfq3r OTH y\r]ww;mceB@?}?D7(P ;G`;VK0]ă\Wpqr&PƑnl}z彄_.\-x_nvs2X#`O6 FB`dT5?ᨨ:&D_n;D?9F -!fS zl t=AOEѐ4YLӏ}JSUպ%_lV#^YzI[7t/Wk+ү K_f/c,A2?Yq7ΦޏAiS9[mO?A7 ?ӼQtyEDR_NcRo&,9z_c Oo } ?/XtBP'Ы ?, Dć;,TQiF}TlQǏ[7!D%'tr;-/,. 539M=SO?@a% !ч!G5$4VQM< ԕKR55R.U1V`1Mx[thdܵSXKYb[XZ ʹV`̱K wp܌S 3]6uk(-jz^UG`/F`DrV.s!H$(N6W _ vd "*f\dϙf*jfz?+}{g*Ƽi w~w7Mn\6 {#kZ֋K5s_e5Y:m7{F۶ۋ:NC:GG'ø %ǟW$<sCNE͂Tu!0/P>u_s8GYߟᧅ~h?Lt z!r,{^+J<|EjW3 t8q20hA00(@l;Qj4*`Ljx0aTA: 08L (`hUe{6ȱ;fl-C| u}??YUX g6n<{lYJQ]@G! ;n""m% zRmީ-fh-0k&F/.%N/fH%N21m|XIuk|mv8CC\:r;NnznN"V)n0l Ь骚2* s?0vd:'`Ala`~a`!d1 Ā|$HH^(1Bljwa+"R@F'oFaa Χ кʢ*V bfQ2ZbpCP H|ibŬ&C&IFV0o]F%^F^_p ܦl0n4SXn,ؒr.9 9uic.TcC *:TpjeI,4 eW,4IJgD:{t@?hVc=@HѠ Bjk% (oif6^E6 .F 3؁܃GjU5R OSLSE9T*$ TTq1)lSMI)cicR8p75,qkbC'CG dƎִyЇQ_j 8T)Q(JHp QhV91kW!ޛ|[ҡ ~WV>:V7bsy:z9W#wגא%6 y$B#BKz4-WX.JX,@X]NatP։ut2qĆޗs(Fmocmgz+4,Y6m-tPVtyЇВLGfi,rsz^F'p{h'V Pd*jUR< l8y(gQX[UAqpނ}2*, Edy`97Fcs:k:ϧ2pudխ=.aF[pwUŪ{wy\C"b^c]5"kA߬IyM%^A5_?{"1Y6KSxt\/`θCPe%vY׼6CNr eQ;I[' !~'ɻ;mr@[[D={-^s>Rs1f@ݴp(?AU#. r_fie|=i;(7>~G)!NepyӚI>?eofi1>/4M j;WF{c=Ugl{XcNn]2o+vS?[㟱x~0 @x2r'鸔F&?ɨ]3S1^H%TK'J|W1K?q2gS?GNKoNTHU:?Ž-mim.s*yD%F-?йn?岹w9oEѠ;kzg?{t7wZHRT='Jd>KYRbidRn5Me#V\Eps^װ3 `ױ,1p Aofٖk[(8#/rf-Ė)r(訪=wnM+*~_B傮+8c 0 3D1Lc"B ,3831<-^J5PYc]-vݷd+jy W#BVZ.\&hkZ瑩ٺkC;$–M C$?̕o!Q"\kAO]H|qˇTrW)ց+BRTNOs9Rܼ>PUW/[C}7?OQr}T,bouF̃W\Wc$! X;L%iMA0 >_C騽(oDmg^Ut(#JW6eGUcySGZ+G1HD!RrPrA-99M{NK_\t ڧA%3Wʹ[+, aM96 ,(g ƫdVQWDSJ!T[p,❺\tD;I <'ĵ=nU:HzhTNd+shKJ,G Ш'B˽ /AQK|i#!0R[Gͥ6PHYTaA^6NN2% O!j Sj}NkkUgk=\xފ}VFMYn(%\k85zP6$S5e+~[XeS@3gn,oٲ^70CaZYKz 9lתuFM Bqo;qmĢajy:]9ɀͪE`Ŧ z_/9b&2 ?e2Zѣ5}!9cRHUZWޣO??s 9~_ i#Q2, OƆkV1Z\*֮,*n#~gj3 g s8ȹ.T#_'Gi82={,s"|aך7FK'VtuPת8tE团J!ITp҄M.c0a99{L,zvo`i`^ᅃ4@k}Es!`l#Cϋڲw`yl77h3sv wE-<&wHnIV=ֵAlXw4.kެZ&o?6ؠLbG%dW!^$PWyGmMq_l/i~c%3N~? ymև#3ⳡ:2=i/4+-Dܽb+p: 4 );"0Z|RK f;V[W+Z;뽨(̼C`acke/ƻl'AyR;a< T;.[ 4'*0é=R[7CK*3A8;?8q-髹03D&2q܀??C,;*MSsS IEi$4[*: 3|9*;:c*at6:d=XS4#.<1)З"*$ +NS0kA\o A 5aAAH5y(_(]# |(жD)Jd'.rbB*.Bؙyxșr`dr-@ٴ$:7EEhq]>?=;-DWLD%-$3|F/| J9,+LNDDӎ$%HʸLʁYD9Ś9ŢŬC}IDEvHFq2Կ@C!4H{|-LC. 'q̚ʻG[ " ÌLyl{/!6B<" ?@K*ɜ#7Oɱ8þ+ɑ)Ox,>N8ǥLPJOJ+80 8mPMT$8a&K$ЬR"=ykۣC*mFee_|le۫[iCeD6l-p4xƌ;.,mHM׍#XD/{f&(}& pR ¨n&6.% @SyGݨ}4S]f~/pƃoM )cD NT^mLMe^_O5`唲1!Le^ V3sɬ=hZcc,k]4ŏmB~F;R ݆gxlG>mE׾p 3_b (b.sR vbf$T~)%zf 5롻õgts ~oke^pc-8@a1ui]n.nΘ` H59.]o\J4e*\~IJeNB}`cEEI^nIKNE"Q`4vm8016b}®ivVk~dϵ5(Zlmzb ]8|L̆)p]mMBkwXpY^Lj0tKn7uKg7@ [V$V<;`?nv'@;)2=YGn;'E8?O3 xt[/>Atedp'W[aIO8svF9_[' 0ݎ:9\.T/:~,Ho%M^\vqAtg%?R" ьdl"׾ tR#!w]v,&]F9a{5ew cl`x[Ƭ^9cEnVVO=MM^Q ?6yǞO:[%Į".Qe'P:o\zx([ozgIFmHW[N7]e8孺m?#`X)a. ƌ.^}܂|+^b%5'LlW|5!6b5˘]0 m^zLGj6ap+p ǹm'{} vsxfWAоYDSWPXZn+G>uUgzf;R`e4%?tB!*hf/T`WE!o4I* j)`LT3wC9NOA'2}R:?ꉷrY֓jzXɫC3k[- jfL]ndyKIlp\:O$񘴦Gƿ)GG5ͤ3ċi4h;TFu:R;KFmuj7oڣ/Eqx<4G%qo?Gn_Cvx i0 ĬDME7w7rtܪoGV+\)I=!ߺ{#˒4Sc3<2SeZٚX4vY:?6zp 6@DQq !$՗Q05Cb!v}#E{FRjSoD*Dےcw/d}zё0 $Ð4 qā;~FӚP;'? 3R.к"P @xC]j;unB I2CSrwcpz2RO )>&IJYV{Ϛ&Ąf{"'X!> !xcYa,%h?:̈S+Ǧzs>ϩ< zsBc N}aL%`h<ϡ:DHáR0FlZWaX{6ttbK| lTi|[n2=y`%ӊ8'!'pҬJuJۗw/J6~zHEV\tH*ġP'-% խYIV#v?J:C]J*XZ*3[iKM}KKL˜OR]"e$>-֚j N3\-&n>tNíd3S?Y1? j{Yz] h:])iP 5 G=Ltk,LA%Z]MaOn VSoz.\Oq?a+iJ :T,&x5X#NLEqcOV|C}\~F_'":Է c"zaJ(˗.É6W, 1r1ȩz/=FJM5D߶-d-8N@~`nc7<sWhfko͔Q5;Uԗv^RzU~,kʍkHcR#ؑ,65GHCʯF!*؛ø1F-nm'mjjʻ "t׽$ũ9N.*0E*>~%>YiY52z)/QS^FKMCYNvP]ΜgN{3+hϴ'Ep 7xPUO;x:3fZ6a /ZKQ]EW+#uBw[۶ m*gPȕ# jvbϽO>Sj͎V="|tsx>-ҫhLbrF ɑOvuۊܽ*5\ .˯ÎNǵVc3@f\f9/'Zn0YU6\'tƜtNk'AAk4ۜqҺfr.X.B p-J0,@$O/,dj 蘥 b(xGFRĎ%' l&' zxm*ȑ0zT$LWIv= ʺ @mߍVEPl*yʑphɮOumlό'nCgCihڡ#t@Njlc6O o+/O\ϊ nhV.Wm<Ɩ'0r̺P kB+0.my-r [hp{ Mi $$ʥ4PJo3ޱ0Ѝo7 ljPyp"Fj/nxp>",~p0"pp"PHv)2P aPӑaWQJ#uv/.q8,gA}RҮ$f I#Q"L.2դdEڤQ!BqN M} jbOi p0OMpOЦ0 T00i 1m/Q/S Я0nj"@34ze.+)qv+5Y6Vfc+" iNB~57ӂ+NLvH<&i6s/'; Κ6a2Hm< 3nPj) 6\.l.sM1PA?-m o Q3k 0wR! //1t3GcBC/1/>PPNRaGD0rB3,W\!K H(Fױ{/R_*I/=)Ir2pr?uQ,PZT6~̮\0r@Әn]`y7__8-9Y criL3X?<(8CP Qa 3At/55+*Md5A dpD0KYpU |Yd wE/És1Yy7hq1?xy2$tkЧU GkrHt4\YnMsknT4]㍓ Mn>=9IUc1w28YAmbwDaQgXk?t 9uorAU>6.-YS8%wukgU\ڧś8eW]0oi?{PnpeV[59*p'q$'l-.PUt[#mh\˥YKJry%q dã#8>dc ?vҌ3b4^i~u i!3M@osGjoj_ OZwxأ/BPe:zx8hIEրQ!vn)e+ׯ.(l%"u~>r:Ϣ_iPCA!rI$ ϤZC C='&w[5<^cx 9(Ӕ'PD2YV™1 }!(~/y?WG{+[mιF_O7tܻ31$$2p#)1pRұj.zγBpj*J0+' ðQ2qQq,Oő\cQDn2qzO) C$HLPRl'%)ZTQJR+K)B:R伏#s 1s,.rTM:"TN'S7NstTT- CQ4E<TIRCѳ/M=JS,T%5J2U28TӒ%3֨2Q\$i -҂ZPHaHzHp(% tCŮBpbb[vʤ˵δRs0:v sA0K|2̋E~3TcX=3Ʉ6O#998z幮,.<+́m3Y; {E|L ^Ts\.[>xg)Q|m:tgE~:G1qcǩ(l2L%uN,Ws \ 6K=5VTM%D|:5MS4/\m?I#q\)Q !RT;YuW;!=:%mW7_^m$؝]evn!z{PD I c—EޅֺKz{~1Y}3k5K+< ɉN z넮KeᔰK;Â9VWOKaFof+5sn?i6:FmO%=PiM5>6B`IoL4XBzřOǚ*M)S*6;(g DGi%Kn*%ZMF\Lq6 t"1*vixV6TzzI:E!QJQ1oinnX߂1K$tI+щoWK4w<2:\˕r++zzeq܇?'% \e%?wK+U6LmYf ՞:50inlߜ̙i:s?L f.1Hw.rr,- Zkˆ%'ЋC^% Eօ4ӤDG##Բ #J^nmB@-?!܆ #_kuiYц/Z!iB%WH]e&KܻYMH; *Po 10 29\'&ظ7ffr[r6Ye63NkCCB 8_y9d`_k?O.d8B ]B ?Z/v<(i9:b#8QUfI8+18 pƧd O@ ~;jD^d/ۓO{UYOAAz޵!΁m̯p"HJ]l7F ;`xɓ^:Sr>1iNsCsy'|K73,1[=<Ϡo?zBS+nn;?G*ob _ S "Sر3S12.6< ;Q : bl#$#`z0 c@:6t<x<:S:)iѷ7=%= 7ѣj'3@넌ܭu3 [;->Ԭ$6>#95C[=9\;?@yBx9Dj DIBV,$=Kϑ͊å(Id*Sl{?-Ci|7[ziH7 *Ϭ޸dCԐCܑ-k<3D; DADz\%ѝ?YsB4D{B4y!KK \WJl,V +\FlT]iƬ`^F::FlA+Fԯ;4m5ˤŲG|pE׺a"5 #u?GJ4DG˟1=l%w.!񽜖IYCI ?YhpMlM-@HM߽>?(N*0NE1ɴ͡DLδ{̤JQ.J{TOD*E)®F;)0BJ)K-JOf^OKtT=R˜UApI|bOLl{SD#8kы 4Ѣ] I{Ɍ-R)RE%֛RSֳ0Ü9R{5Ҝ? lM+>r,JS)WcN?ebB{S|#U#41tî(\YJ>C5sY*X aTl_JԥJFte e<;P[h˕<E<+XKmв<}Xq 7Uӝ;\MS]`U.QWQ=EIi9-r?n+Ӓ-VjpôӕW<%/[W| t?MzyH7BmQeNӵ:Cs5U/MTTUTDODûT95E ]4 K}Q@ˬ0X}BK?cYPqY CLda<+ $0@OhV/ R+ 6n#  N9 5zM 1t{Tc 0y|FK& %D3-x3  >~k  `9 D a 5g 1}~? B~> h~; $ /c`^bj~;    ?mY  Q_73^Y +C0 Qrz3#+'7)+@PWm}( /83( Vq!>/ ! !$$*=v~~4 ?h *r^H)1bh:;=?CHJHHLNGP} =ACmi! V}T7%4J5gTPvbVWWUTVU[iovwy~~}L 1v&UK ba@ ~i ,dtcqm2(hwıP#[uk\\Yc|z{jYV0@xwbU|}~~}~]  DUik@Fw͟:8DD?@Nn̩=9HYcØע~}||~~~uq>   x\b`fito !G.`̹v3h{ŝ}~}}{}{deWEA>>AFMQH@?=?<4$ &mpUWf|Ȁ!7L{;0JPM9n{uW]~|~;  !17,3LYjwmllj";2|}IS}] 7wg32rY`~ !-5BEbS57AW#7=(:75^(2TBOZ@{~}~   A@+09NN+(?Tdpy{wH"-'"6 )>N\gmr{qCFgpgAc,JN<)\a 7weB]cMS~~~~}~}~~(     0`L[fe[D3 %9HTbjvqS<'*,TC!F[ -F;!5y\C_n&~}~~|~}~S   )ͣV]\VL<- #9FQWTIXyuGF"C" "!RfBtRoviE24*[}{l    Б\\Q@3) '#!#0%"1B#3Ma3aTJUtp`: E~|~m        "io\D 8Whg-@#!5+ %689D/ =oMD>_%>" 6}~|}~|j       6FSxnW/   (7z.A% '$!6<3 7V9J%!'.%?~~}~|~}~}}b      2xRHknkc= BJq(:'" (>W^VH' G]a~{{uvtr~~}}}~V     1ceVGHEB'  o./ (.:?\AE:! =o&K}~}}?     SbU@#*;   X)D!A12F`AG8 2A9~f'   _|eE.+QA ?LC &H1+7?7-2F6}~~E   LvO'B2 .y3W;8931C@03457258699'+}~}}6  Hw4#! `7 3-+((03)(+*-(#%)('!;~|}}|}|{|- < < !) 2C' P~~~}~~|||o  % Of   R; &:H%kR 4~~|z]   &, 9Z  [|iÕprwvstq 0~Q      Rr   =RRnUFR|=SSMJT]SOC3&"t~F     7 QSJ7rnbUNSVVEUKRT+!!%F~~|}@  X  2v^B9;=> DĔ![^YP̋X}~~~{}~:    8N 6}>Gh]/@Ɏ U~~~{}~~}A     ! -w&Qjy{#$+e—))+&%~~~}|~~@      ,v "9oqXo#{Ԯ,.;7K~~~~~}|}~E    '{  &̉('T~@      $yP~}}C   # XD`6 L~|}}{}~J   0 5z m~}}~~||{{zz{V   {9 rkuy9 J~~~z}{z~{{zm   nA  Kגp` 8~~~|{~||{   dC 5НnuͱU+}~}}}{|{z}}B QC k~|R@E9ު9 l~}|}|{{||}s  N}D  (;%,61-B55v|%L~~{}~{||{y|0  ME '2$ !  ?~~}~~}|z{xzy{{    QQ BM    U}t~}}}|zyzzxa   K_   &   3|~~}}|z|J  Bi 7Z _~~}|~}zyQ  1u    6~|~}{xz|ywl  -z Iz   b~§~{z||{z{     !  f8   :xϷ~}|}{z{{]     Pt%! rkĭ~|}||}-   z/ 5Aex?Fvhc< Kkgz{_\w}|}~v   5.BB  )eI3XDc BvQIXdNEKf}}{{|}k    #[T $. .ie$ GxSJbrXHPt}}{wzf    'HE#   /n:Ud# #~~|z}{y~d     !$  2EB2oiN>c3 n}}}~}{y_       1J u~}}~|{|Z  &     B'  s}~}||z~W   $"   C] @i=5 l~~{}~}\   "!  mw  9&!,3~~~~}}|}h     ! $'&   0R   k~}~t  %! #(02+  J,   !.%<~}~~}~~}|}@   '!#(.0//# ;q$Hq$  %#x}~~~|}N  #"$()-*   -]3 /бV W{~^  "!   0J" L٬c  D}}8 " 9*&SZ% !9 #~|}   -R*YN*{'P{~|~}  #   Am 3cA(vd 0}~~| "   :] 3c=$- -^z~d    0@1b<:R #7{}~A       1) 2d &@{~~   ,o Dr 6lCVq y}~|     Hx0 @i 9tVX-&Jz}}u     $ qM 5G ;vgai +y~~~~W   "  # 3g <' 9shd ,Wvx~0    Nr;h  -9reb_ "7x~}      %I{p:of` -q|~~U    udar "½y~}~O  ).H0Qv@tf`e&&My{}{}~}  F3_ks@sf^mV]L 'w~|~}G   g|Ds+t@re^W@A[W +Rv}~     0jIt8qCuk_yB7D\qP  4}vsuusqropyvA   IGB\AqEzj`zKARhp $kw||z{|     u H=LpEyhajTBBMYfg: 6w~nouurliiku}xvE    65ekrFvjc~F04=?@+  ?ՆF{$ˡMku~tt}y_4  0}jNDTjsuz}xvvpddsootzylcgaSKYuz~mkjzxlshJ9246:5  BZU4Lko\ !lw[LUj{t`TPOTTEFsX:FovQnO.2NS>7EDADC=CKQXOIB>@@DCADIa`F@7475"  &micbb```bfxd Nb6||p Kulw_MBGY]Y|fNP{ka{8{^ DuA VC 3jZhu{{zulaS7.DhqQFEEA5685233102001111022/0011-///0024381   jɐ W>aƸKux}u_[lNR N+ 0nAGMD@KZZLRTNE9952/00//0..//0110110111/021121336+     %a:o P~oiiiQJx[ok|~}~zx<  9z:/|9>#3OwpZUONSPMQN='$#$+5ALNB859=;:21/00/00//001101202331./022124;2    Y#ǴS947&P_N@Ka\\aml_\X{bR (E -'%AgT$Q09q|< 'AhZKNNRTTSROQQ=***((*7JOE64ABKR7   Tw%XA0T~ӸMhm^U:OU>3E^RIKRXMDDpzbj,)20FcR+#Pz7?R<8^c=*5NVSSSQQNOP=)+,++(/@IF92:=97TZcagZTT][cY`\bff^]bbj^gce_e[me*   #"&734H8$&+% WV}rt@εuTPP9*B^O<9;GA79ixXzO (50E^S1)Ni:>:" 8hiB'(.9RWSRRSPPRP>**+..)*7CD8.2657[dtnqd`]fgq_f`hniX[aen]iekjm\kU  1zsqt~sRTaYX`^56u3 Tv1*(2Vihdj96>:/%6J?10593,/dxOt#)0-ATJ7/Jr]::+ !H|~O- #&&3PSTYRPPQRG1'))-0+(3;40%)552EQc_`VTOWWaMST`faNKRZfU]\jpuinG  M{ols$W,yt<12&Sn3-=^SA~Ѹ8-./4>H=/-142/2[jCw%" )|~+);LD8/@cWF@$(3#.^i@)./+"0STYd\OMQM4!!)3*'/)"'1.$Xhzu~}ulwxpqq{spwztyy. f|zxgix b:}zU@=tA!+07357U_@azI  1||,$6G?3-9SUVG#/2  *8$CzW5-0::0%-QWUTTPMQH$ )!"( '!Vduszgsw~plhq~}prvtrahclmpub 5kkswusqwx[Zj[6|mmT@04$4'/RW\ñXiwf\\WI>?;HH4VuX  )~,/MB-'1X[E:%21! "+\xW:249B>0*!+JSNHMQQR>!ESffr{k[eitgf\ftqcfljjUVNU]ibB  Rm ]b9\NH4. bQC^PeSN?IB8Q?Fb`HDEC@@EPUPaeTOM?" Tk~xz{ult}ttjtvzmow{a    F*Z?>+(C)MmI!"-iŭkM9++9MenhZ[Xig`j= #PJLX_lhaa]_ZJ@?>@DNO:?UnviP@AHJ@0.;?=FJIUaZMZiLGkoWQFM\LT\XM[eVLE3 S\b\hcW\SX\_V[~O  [gJ<3)|G -T|I4O6jΰ^`H7ALRTZUWLLJKl] Qe[\WQHC;>JE?FMF@ESXDEM_heRFGLSOBBNONSSRUWZZ\`TO[_XUFEMGMPPKLSRG;.""$##)-120/,(+*)+]e]QsZTUPMMQLNte!  =vrmfbjwuj`lqsL cBk:6/#znTsyIA|~TIOQTX]kc-s̟[_a^`tylighmnmwV _wqnmnmifgjlkinlknomoolmnquqoqtutquuuusuuvwxvtsuustutrqnmmmkmnopopsrrpqrqqnorppqppquILfrmek{vk{{|jVSawrr{uo> !gxv{|w~}*6v6NI'qaAz}[oqrqqqqr],ṣcmmlwzppporuwp! Fzzwuvtsvxwtwuuuuwwvxyy|{zzyzzyyzyvxzywwz{yyzyyyzyywywwuuuuvwvuvvtvwtspqpnpqsrrrttV^mchlhdhmptupkb\`iqotuzj+   1v P ang}eA|́[yxxxwustvg/wѣhprvvqw|txxyy~S )rzxxttvvtrstwwvuyy{~|~~}|~{}~zz}~~||{}}{x{{zxzyx|~}}}{{wx|vu{|{yzzxstutvkqzvlkmkijkljjgedc`dfhorrk  8yuvtu{xwywug]$izuEey^ BzXussuwutvvzh.Ԡoy{yux}{{zyyp O|z{|zxxxz|u}~y||zxxzzz{zvvvpoqqruytruvwyyvytqz|ywxxwtuvsuyxvtuvsstrtuuusrssuyww{}Q 8smnmjmqnsxyzU \1~mRq~j,#DǕP]|{{~~{|g1ўq{|w}~zxwz~M 6~wvxvvyvuz{|~zv{{zzz}|zy{||zyzvvvwuttttxy|ywzvuwvsruxusvtrzutwvuwwyzx{{yuwywxzvwyxn   G}vwxyz}y{5 Yg;SvFF۠_h~{{}~}}|}{b,Ӗlyzzwuzp \yxx}upu}yyvnrutuy{{|{y{||w|~y|y{}z{~y{{zyzzy{vwyxsvxvvvtwyxwyywvvuqtupprqorqrngjvwtnenormnliolhpsovR    b 'iEG} b2R\monnkAVn\xxvklhglnjhknlf`G.vT[\aaabddfD $^gcb`^`cgec_X\c`\X[ZWX[[XX`g[^a^YXWSXZZTQRQNLMPOIIJPPQSS[`\Zba`^Z^]XVV[\[`^YW\_]|}~|{{~|w{|z}}||yz|L    'tvsnpuuqyzvzs c~At"qqpntoATn\uwshieefgddhhgc`fF1nZ]``\]`bkX  Ewoihgmmfchgafhb\[][WZ[VVY_eYUVUTYUNQRQMPMIJIEHKHKMNNONKS[X[b_cfffcfc\[`fhfgecb_|ywy}uw{wwuuy{{xyyzvr}q%   -z}sqotwxtz|x{n 'wVAUIlpqqwwGXr`zuqmmikomlolefgcdd@;sblmgeegji?  /jhgcaee_Z^_Y][UXZRMPURMNMPUMIHIMSOKOPMJKJHONLMPNPUSUVSSXYW[caa`de]ceZVWZWRSSONRyvsv{wtwupturvvuuuqqppb  V~vstvvwuy|z}` S%F'~{sonoruJ^s]qnlklnrtsoqpjkjhfefAApfgbdca`jP C``[XSRQSVTPOOJLOKIQSMHIHKLJFHPQQNMPSTPQVUVWXUWWSORUSUZ[WVY___[Z[W[\TSVYTHJMOPOvtrvtqpusorporoonmigmooF   *qvtsomimsmlxstuC h)C;frprrusE\pZooljnnqmmnlkmljkfdkk?=b\]^b_Ze]-  .hb\_[[]ZWY`ea\_aZX^ZXWUZYRROV^VSWVTWXY\\[Z[YUSTTQTXXXXSUXZ_`^aWWZXXUTUYVQTY`_]spqusnltutsliikmkjijmmlC   .idegjjgjkbdmind) h$riqrtuupBYoWtuledcigdfdcfijdabgkl>O`\ai`[`jM Zg]dd`bc^`gjb`cf[W[WUYYb^TVVY^WSX[YVUQTVVUSUYVSUSRXWUVY[XX]]Y_UWWSTXXUQOOMPWXVtorqrmmrrnpmihoolmkkkfo]    ;kgegmpmnljmnksc h *fjjoplnqBVnSqqlgdfkf`acehljjmgcdlg8Xgkmdbdob  :okfa^afhfbb]\[^ZYTPTXT]`^]][]^ZTW[XUOQUQSUUV\^`^X[WRR[[STY`cbYY\ZX_]\WZVTZ\[YsrokmmlomgkqojniijeeeahoP  Ywrqrvurrsx}y{e ({ZUinknspqwFTnUpuuootwqjijkkpnovpffage5\ïikgeipqD $bi_`gigdgcejjhjigijfgffknjb^fc^Y^ggfghlffhifgijkjhhd]]cgdfiihaafd\bdc_^_]_`]_sxplqqmnkhkonklebfkplgklnO    &munrvzqopmnyuvY N(njqllolouIRkTmlkkmkfiicekljecda\XU]_R!^ţLTUZaiU Bkebhkjknljpuonljqqkimmhgcbcic_^^flmmprnpopnifeagggjh`ftrmkimljegjfjohdfeeegomrlklkmkkpoklqwtposurmokox\   +ppfjqolmkosvt|{= bDV^hffgagf@RlRihefhcbeddacgcce___\\b\XR$j×OVWXZ[3 /pjchkgbjmknlggkgha^ahje\W]cjhea_be`bmnkeekmkccdgb^_c^Z_dc`hjhkgeecklff`^choumpnmmjnqrwuqsv|y}~zyronkpt{Y     9usmqxssqnv|}|x jvjpomqrktpDQmTnpokmqqnhlmorsrsqnimrvoila.qˠemmjuS Vtpnosfbbgnmimwvonlejookghhpuunlmnjmoqtjikdedgje_b\]_WZ[Z^eb_bbY[`a^YVPFR[YUfnortmqqkiostttpx}|}tsxuuv`6  ^|wry}rqnntustp n 2ix||y}}v~O DnYxy|wrrrruvvzusqttmot{{vvzn/uϠkvv~n/ 9zwxxsqimvurqywsvpkfglnlqnnqqpomngf`^efffabejh`adf`]^fb\ZXUWUOFMRRWUPPMRPPInosutorsjilsuvutou{{}|wwxypotlC   ,~}z~z}z||i%sUap{|}{}xO =h_}z|ytrpmv~ynqrxyqwytv}}|~yg/wțs{v[ guuuvpqynmpkmjgmmmieegfghifbemlihih\`dlsrgdklgfiqf_flg_]QPPOHINNRWYZXXaii`usqq{{uuputuw|}}zzvv{{utvrpsfV6     6~{M H)sy{zzz}{I=a`zxtqpwuqrruulgp~|ttxpnwxzzu}f(|Ȗmt~l! ?tlnrlxzgahqnklomiophmnhh_eijpqqpntkdgmspjkorqopvolnsmnqfjkhc`_a]bahmbltqlppio}usrwvsqx|zrxz{ywwwY0    Ky# aJh{yurpvussv^~zqlptsjlmnwsnndaX`offX\vn~~oxxqrxymdeozoyx|utnvud_gafp[]W% 5mimnhpqnjnnsvleieflkmj[RV_knc\WQKMPKPPZ`TTPPU\X``RMQN=@HGNUaaK?@C>@Qqohejhpqpsuoqu|npvrpvvworfjz{vxomm  .+(&  "hqhsqmpilnqlnv|g S&Pu}}qjiqb_fnxlebVXgX_i^TLG]nipmt~ssp\^chg`l~ysdnbdhfeega^mqrsgaiQ Vbgn`emkxkcdieZe]dfcjd__Wcoljg^UMZaWPM`gda]Z[eTWRHM]\\ZFGIKE@/04$&2cileepvwisyvsspY[_eifspllkpp||vx~z] ).*+"  >PS\[WU`gVS^ZMUaK iWhL[d\cdW`QVF=DQ[VRCEPYQ]h^`^[gehvypqmc`kfhwks}uheug_`gY]hiekjd^`no! 9cam^fgwu[bfdcliW^hc`^jlgmmmnpjkhdmuqkrmgkrnmp[Z]Z]ebigX]RIMYISW:?BA\crjgke^RTVJPWWQQMV]bldd`mtopnqpslL #,)((   >j`[\Q^TU_POXWKN]J v ME15;ADBCJKPKLOT`XJO^hcce_grsv{y}uorvrni}{xyjmn{refWS_kn{icf^qZ -nhbdmbhb[gpgahdSUfYO]hfc`guhra_hdtr]x}lclqxzmdZQTXVd^QZlgPPce`ZQ][RaegcbLNLVPQOTYggiv}ppminjrx}~swxt{P),(,$ Lqchjivbaj^dlmikd9 w&VM81=NMOQW`TW[\^gkdo~zqoeyzimp~|rtrwymy|yxpzt}}mopgplsorux~ytwu NsaiqinthgglqiXQY`VSY`c^fkm^bTW`c^MJccdjkccsrdbb__Xb[V\Zf_U[`[[`e_Mc\_hlegjqhejqxzxwt}vuu{zsx|U#/+(* Yyjcl{zsofkhcis` .V.[SG6H^WZiniV\|nklkpih{lws|~tqqu{rtsywsq{xzxjlkgxsnl~{mfqt~tC 0zutqkbdl{j]eZXXUT`pyk`_PLfie^\`WIN^jbYnysurqua`jj^_idc`TUX[[bcVaqvfo{qmwtofqxxyinq}y|st}ys|X!+/'&( !Tnvncnrls]BAIRWpe N/6UBPE@J^vo`eqzpbknmx|~ze}sp~|loz|zwr|vntwk|: 3s~xwu}zjjnszumlovvti\hobkkinnxtfssuus`RYsyuenvylgdlgl_[djqeX\rhglfffkjpsvk`iwcmokknvtwuvnkvxL &*/,%,,$ $K[\RXPA=HcssbTgjE lZrvmhqobboZT[SOOHMGMYUDJWaa|}b\OUfuvl~~|lt~vry}{~~z{stzulsp{yrm` ^zc[ktpqvtotuXZ[goih^\he^l`dg\bginl[^lj\_Ygo][U`iemvcnfmo^swok_c]fkkgdmhbafmk`coj\\ouqg`ktc[gdcisgB '),/,((,+&! ,`pua\\c]bpw|uflh3 q,qqj_`mnO^{aXl`Z_ZY`ZW_caeliq|um_dkqf}ddgmuw|r~zy|pl{q~zdW[uq.  ;jZXc_\WZorei]ROSYTZR[Z]qrusvm_eieidUV^[QXaldbX\dlcXggf\cb]eaW\_\jfovkcg^aedtlXchWNTjvjlpmg[_hdms~q< *+*,/0&$-.+)''  /]kp]SZis__^[reYR ,j.jgf`hlfVlvqtycrzvst^\uoedcalne`fjtueoljs||sqytqsub_p~xi~togp~o^pok\ $fonpa_YZ[Q`ibb`ZXaY]|cN`eivj^`bU_gTVei`WS]`TW[SRVXOSfn]\[URPSKSZaTZjjS]hort|tmsysgfmr_qylhzlim||5(*,++.-%%*-00,,  !'!>gglld[eh`dj\]RWV OA +fZ\bZ>Whopch`W^[FAMPLOLCNdaS]cWV_[]NMa^QP[Y\]KZ`RSewtnsMlydvnnilrdvugkilzkpouy}{t}mgxzbcS"(( $-+ ?fmt8!$%#&=dbuagghlRYb\mn]]S#@|?{ultjsj[jg`hI`ck|}hfji\u{wt~i[nphmdhq`\yfjmUdilfgpihd`g`Y`deXRY]PjbP\aLUQVR)#VڃUKXZM^_\[ck`RhdTL]X\dRilj``mZc}g]poh|pJHXgUojeWmomcdef[Vr{dj^bx`nywrpj|yri\Xvxag^toJktzqntvtwtw]KLKFBFT\bPQ^]aZQ^h`mgSK6"0dlo{VHXglb]m_ZqWUfprYPQ^fhch[\J@HXTWOM^SDXP?SWMl|l`Zrhn_dlyvuvq\jpidmgionbcfwl`thesk'*' .,._YsqK%&'F~vo_`e\dtqeprbxzY@M`fhymh_gls_fkuofn`mM[ojr}zmlXaaYfuiWptlplwqcpx}mmjlhdphXcl]^_dfc]]U[efcMWfohWVF#$g~qqzVS[bxeWbS?UVWgufR]}kebgqhcVJIKQQRVV]UQOTYXUgidYbakX]KLl}~{bkkgqjcizps{aSesm`T^xx{Y$++$ )*4kib`^@%&' Dw\^zm`beuj^nsutf0'WvwszgaijkshjztdputsmWYgpjbd_hgO^_\Zbegmkc_wub[]nuchSckg\isthohju}d\ehimfFY]kreia6";TNiiYbbdYOUagWT]{|ehYkceuxff[ZVaa^\BHVvi_R]ga_g}^c\cZW^OlslnwrU^f}sm`V`_SLWlaQcl`a]Oii}j +0' ")C|umqtS %!A|bhejonfnsoy~f%3fbtve]dm_zvmfmuxtvkxdyo]kkeZ^fc`vldiqe`tledlujbYehtsp~vytbg{q[v}rtnmd\\^p|mjmyT $kk\lp[m^`ljaemNKSj{q`ZV`jciU_hXIh{jYMH^qgXMNgnhjrfTWZValm]abXf`UksagZhm^U]jf[RalrdcpcgbTq~i)0,  &!Wtswwb!  4rkxxhadYd{hlsyO>z\pahYK\gr~w^`ful{~ydUuyjihiilgb{mdYuxw}uhwtihmqfb|}t{nvsSV\djuXWh`hbbwub]eyt'*+'#$ Lrw|yq373.011/.,)&  ;gg_XovY_TUCLQQI.*YyOcXSO]RQrd=Hh_RM\`Qg{tpyu[Soh`rYhV^xdftulxoipov{OPpqdm]hzkhgbvitf[lnnXgpnvorw[RW[eSI=$/WSSXfbdjgR[}g^|iPUjzePVYBFXRQ[]`TMNEQfFHNA]]SHR^g^SV_[Xx^N\TU]mwsxknfe`j`\ZRbdisq`^g\\?$++&()2ll^huo|f,642367423562/#Do[k^\b`lqb_efG"3hfZ[_wka_Rk|gisOLbfgf^^pqu{mqreadZc`f~yyoxveozko{}~_vsgrwhY_bTXd~lvk]ld\R[dWtdZSZkr\Q&%dz`kflcaowwvfllZFGhmVl`URLZcLO\^U^WZhlLJRF\]Y\WQIZWUnmZS_VHNUlmjohgpzj`Xhy_M[^]ecV\aa]: +,'"'(:wnhowjva !56552/,+-.26:8*?~UbXWadny^\hjB={SS\_|yYflu|]jrVkjack{}xvrk\Uce\]PjngkX_|yaxhs~riu~kQ^o\ja\qk}~}{|wyo[]XSSimi_ntdE$:fxvwmajquzpuebewtl]ld`MQ[_``u[MbocdSV`hX^ZbnmUROampkQSvs[_Zhof_XTbkf`begpxstYqvWWOIOem, '-+#'!!W}fyjxm&0873/*+14676:>:! 6c^^k`dlsytddSR;FFS__q}fqovigozqsqa\lxqivbl\\^n^XUYec\X^jeagctzehchaRMrnovlvo^cfs|}cO\amydJ^}o\_X%%jxkUd}kbcYmucupkqqRVdqjYJQlzzyj[bgl[__obVrbbaqd`u|gblpk_`_\Zbueil[\XU]Y]u~ppnq}^moY^wh $-/(+-mwcvzn^f2"66012650,$"!AZ`vp\_kndez_]1KRhp|ytqmSxtQafpwzhdkuW^\g}pf^`WTWRXOR[d^\\]Wnl\\QQ]^Ux~zdnmVhtp~tlkrtie[lkQanpPQSU;&@S]_Y\fxiumdivrs{vz}ldkbgra]LK]lqb\pnOSF\J]^p|ookZx]Ys|\dVgegk]hwx]VkwyrX`[^qowe *.+&,VXgxnqYa5 ,3/12*  Wg_fd[jnZWf}s^'(Vk}khlvfff^Ualhmtedjj\_^bjgewuif}fSYUHTccXRPWsigMLVkbgsjtmceputfupvuojwrbaxXQ\cY\o|kgloV%*s^Wh_posgni_Ytuezkjnd{p^fhXU[e[iYI[ep[Pp{xpck{pSWS`]tsfYtxppbV[nqYfhfopnuXESe_QhrS&/ab_ELgrTlmi~kZ[tppWhk]cZae=JbhuRShehg`[8NfSRPFIDR]Ub`eTTrdkk_`>`tjc_VhWQ[lh_UhwtyN%#$($"#CjWOBON^ql5 %36456579- [m\TV{lR>[muk4HO\jthnsdgski|tq|}y]Tintwcbecjp|`BZ_SUc^Tgnbl|e^zlvyrjNP^TVm^PupS_vvbkiSciXpfvv_nu`eebXY_vr,&UށVgHC '5:401250 OXF_^bnXen\poQ!.\~PdodYiW``QWHSyjH][aZVQ^j[h{vSvkVdQOmvblcWZo_bkivx_Zpofkupt\Kwqjm][_mogic~novVVjbadZF`fQLnrOqy^(%\~zmr_AD09; GrayProfil gnrique grisu(ppr_icϏProfilo grigio genericoGenerisk grtoneprofil| Gray \ |Obecn aed profil Gray Allgemeines Graustufen-Profilltalnos szrke profilGenerisk grskaleprofilfnpp^cϏeNN,000000000Profil gri generi  Perfil genrico de cinzentosAlgemeen grijsprofielPerfil gris genricoB#D%L*5@21H'DGenel Gri ProfiliYleinen harmaaprofiiliUniwersalny profil szaro[ci1I89 A5@K9 ?@>D8;LEDA *91JA Gray 'D9'EGeneric Gray ProfileGenerel grtonebeskrivelsetextCopyright 2007 Apple Inc., all rights reserved.XYZ Qcurvsopt-2.0.0/matlab/000077500000000000000000000000001277570055300137515ustar00rootroot00000000000000sopt-2.0.0/matlab/Example_BPDN.m000066400000000000000000000064471277570055300163400ustar00rootroot00000000000000%% Example_BPDN % Example to demonstrate use of BPDN solver. A random Fourier sampling % measurement operator is considered. Daubechies 8 wavelets are used for % the sparsifying operator. %% Clear workspace clc clear; %% Define paths addpath misc/ addpath prox_operators/ %% Define parameters % Coverages (half the plane for Fourier sampling) p = [0.50]; % Noise level (on the measurements) input_snr = 30; %% Read image % Load image im = im2double(imread('cameraman.tif')); % Normalise im = im/max(max(im)); % Enforce positivity im(im<0) = 0; %% Define sparsity operator dwtmode('per'); % Decomposition level of the wavelet transform. nlevel = 4; % Daubechies 8 wavelet operator [C,S] = wavedec2(im,nlevel,'db8'); Psit = @(x) wavedec2(x, nlevel, 'db8'); Psi = @(x) waverec2(x, S, 'db8'); %% Run simulations % Random Fourier sampling example % Define mask % Uniform sampling of the half Fourier plane mask = rand(size(im)) < p; mask(:,1:floor(size(im,2)/2))=0; mask = ifftshift(mask); mask(1,1)=0; mask(floor(size(im,1)/2):end,1)=0; ind = find(mask==1); Ma = sparse(1:numel(ind), ind, ... ones(numel(ind), 1), numel(ind), numel(im)); % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1); At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind)))); % Apply measurement operator y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); y = y + noise; % Tolerance on noise epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise; epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise; tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball % Solve optimisation problem % Parameters for BPDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Convergence parameter param.rel_obj = 5e-4; % Stopping criterion for the L1 problem param.max_iter = 200; % Max. number of iterations for the L1 problem param.nu_B2 = 1; % Bound on the norm of the operator A param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection param.pos_B2 = 1; %Positivity flag param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) %Optional parameters when Psit is not a tight frame: %param.nu_L1 = 1; % Bound on the norm of the operator Psit %param.max_iter_L1 = 200; %Max. number of iterations of the L1 prox %param.rel_obj_L1 = 1e-3; % Tolerance for the prox L1 % Solve BPDN problem with positivity constraint sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); % Compute SNR RSNR1 = 20*log10(norm(im,'fro') ... / norm(im-sol1,'fro')); % Example with only reality constraint param.pos_B2 = 0; %Positivity flag param.real_B2 = 1; %Reality flag % Solve BPDN problem sol2 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); % Compute SNR RSNR2 = 20*log10(norm(im,'fro') ... / norm(im-sol2,'fro')); %% Show results figure imagesc(sol1), axis off, axis image, colorbar title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB']) colormap gray figure imagesc(sol2), axis off, axis image, colorbar title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB']) colormap gray sopt-2.0.0/matlab/Example_TVDN.m000066400000000000000000000054001277570055300163540ustar00rootroot00000000000000%% Example_TVDN % Example to demonstrate use of TVDN solver. A random Fourier sampling % measurement operator is considered. %% Clear workspace clc clear; %% Define paths addpath misc/ addpath prox_operators/ %% Define parameters % Coverages (half the plane for Fourier sampling) p = [0.50]; % Noise level (on the measurements) input_snr = 30; %% Read image % Load image im = im2double(imread('cameraman.tif')); % Normalise im = im/max(max(im)); % Enforce positivity im(im<0) = 0; %% Run simulations %Random Fourier sampling example % Define mask % Uniform sampling of the half Fourier plane mask = rand(size(im)) < p; mask(:,1:floor(size(im,2)/2))=0; mask = ifftshift(mask); mask(1,1)=0; mask(floor(size(im,1)/2):end,1)=0; ind = find(mask==1); Ma = sparse(1:numel(ind), ind, ... ones(numel(ind), 1), numel(ind), numel(im)); % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1); At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind)))); % Apply measurement operator y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); y = y + noise; % Tolerance on noise epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise; epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise; tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball % Solve optimisation problem % Parameters for TVDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 5e-4; % Stopping criterion for the TVDN problem param.max_iter = 200; % Max. number of iterations for the TVDN problem param_TV.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator) param.nu_B2 = 1; % Bound on the norm of the operator A param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection param.pos_B2 = 1; %Positivity flag param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball % Solve TVDN problem with positivity constraint sol1 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param); % Compute SNR RSNR1 = 20*log10(norm(im,'fro') ... / norm(im-sol1,'fro')); % Example with only reality constraint param.pos_B2 = 0; %Positivity flag param.real_B2 = 1; %Reality flag % Solve TVDN problem sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param); % Compute SNR RSNR2 = 20*log10(norm(im,'fro') ... / norm(im-sol2,'fro')); %% Show results figure imagesc(sol1), axis off, axis image, colorbar title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB']) colormap gray figure imagesc(sol2), axis off, axis image, colorbar title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB']) colormap gray sopt-2.0.0/matlab/Example_TVDN2.m000066400000000000000000000054461277570055300164500ustar00rootroot00000000000000%% Example_TVDN2 % Two examples to demonstrate use of TVDN solver. Simple inpainting and % Fourier measurement examples are included. %% Clear workspace clc; clear; %% Define paths addpath misc/ addpath prox_operators/ %% Parameters input_snr = 30; % Noise level (on the measurements) %% Load an image im = im2double(imread('cameraman.tif')); % figure(1); imagesc(im); axis image; axis off; colormap gray; title('Original image'); drawnow; %% Create a mask with 33% of 1 (the rest is set to 0) % Mask mask = rand(size(im)) < 0.33; ind = find(mask==1); % Masking matrix (sparse matrix in matlab) Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im)); % Masking operator A = @(x) Ma*x(:); % Select 33% of the values in x; At = @(x) reshape(Ma'*x(:), size(im)); % Adjoint operator + reshape image %% First problem: Inpainting problem % Select 33% of pixels y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + randn(size(y))*sigma_noise; % Display the downsampled image figure(2); clf; subplot(121); imagesc(At(y)); axis image; axis off; colormap gray; title('Measured image'); drawnow; % Parameters for TVDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem param.max_iter = 200; % Max. number of iterations for the TVDN problem param_TV.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator) param.nu_B2 = 1; % Bound on the norm of the operator A param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.max_iter_B2 = 500; % Tolerance on noise epsilon = sqrt(chi2inv(0.99, numel(ind)))*sigma_noise; % Solve TVDN problem sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param); % Show reconstructed image figure(2); subplot(122); imagesc(sol); axis image; axis off; colormap gray; title('Reconstructed image'); drawnow; %% Second problem: Reconstruct from 33% of Fourier measurements % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1); At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im))); % Select 33% of Fourier coefficients y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); % Display the downsampled image figure(3); clf; subplot(121); imagesc(real(At(y))); axis image; axis off; colormap gray; title('Measured image'); drawnow; % Tolerance on noise epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise; % Solve TVDN problem sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param); % Show reconstructed image figure(3); subplot(122); imagesc(real(sol)); axis image; axis off; colormap gray; title('Reconstructed image'); drawnow; sopt-2.0.0/matlab/Example_TVDNoA.m000066400000000000000000000032031277570055300166330ustar00rootroot00000000000000%% Example TVDNoA % Example to demonstrate TVoA_B2 solver, where an additional operator is % included in the TV norm of the TVDN problem. %% Clear workspace clc; clear; %% Define paths addpath misc/ addpath prox_operators/ %% Parameters N = 32; input_snr = 1; % Noise level (on the measurements) randn('seed', 1); %% Load an image im_ref = phantom(N); % figure(1); imagesc(im_ref); axis image; axis off; colormap gray; title('Original image'); drawnow; %% Create an artifial operator to test prox_TVoS S = randn(N^2, N^2)/N^2; im = reshape(S\im_ref(:), N, N); % S*im is thus sparse in TV %% Add Gaussian i.i.d. noise to im y = im; sigma_noise = 10^(-input_snr/20)*std(im_ref(:)); y = y + randn(size(y))*sigma_noise; %% Solving modified ROF % Parameters for TVDN param.verbose = 2; % Print log or not param.gamma = 1; % Converge parameter param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem param.max_iter = 100; % Max. number of iterations for the TVDN problem param.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator) param.nu_B2 = 1; % Bound on the norm of the measurement operator (Id here) param.tight_B2 = 1; % Indicate that A is a tight frame (1) or not (0) param.nu_TV = norm(S)^2; % Bound on the norm of the operator S func_S = @(x) reshape(S*x(:), N, N); func_St = @(x) reshape(S'*x(:), N, N); % Tolerance on noise epsilon = sqrt(chi2inv(0.99, numel(im)))*sigma_noise; % Identity A = @(x) x; % Solve sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, A, func_S, func_St, param); % Show reconstructed image figure(2); imagesc(func_S(sol)); axis image; axis off; colormap gray; title('Reconstructed image'); drawnow; sopt-2.0.0/matlab/Example_weighted_BPDN.m000066400000000000000000000051271277570055300202120ustar00rootroot00000000000000%% Exampled_weighted_L1 % Example to demonstrate use of BPDN solver when incorporating weights % (performs one re-weighting of previous solution). %% Clear workspace clc; clear; %% Define paths addpath misc/ addpath prox_operators/ %% Parameters N = 64; input_snr = 30; % Noise level (on the measurements) randn('seed', 1); rand('seed', 1); %% Create an image with few spikes im = zeros(N); ind = randperm(N^2); im(ind(1:100)) = 1; % figure(1); subplot(221), imagesc(im); axis image; axis off; colormap gray; title('Original image'); drawnow; %% Create a mask % Mask mask = rand(size(im)) < 0.095; ind = find(mask==1); % Masking matrix (sparse matrix in matlab) Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im)); % Masking operator A = @(x) Ma*x(:); At = @(x) reshape(Ma'*x(:), size(im)); %% Reconstruct from a few Fourier measurements % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1); At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im))); % Sparsity operator Psit = @(x) x; Psi = Psit; % Select 33% of Fourier coefficients y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); % Display the downsampled image figure(1); subplot(222); imagesc(real(At(y))); axis image; axis off; colormap gray; title('Measured image'); drawnow; % Tolerance on noise epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise; % Parameters for BPDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem param.max_iter = 300; % Max. number of iterations for the TVDN problem param.nu_B2 = 1; % Bound on the norm of the operator A param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0) param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) param.pos_l1 = 1; % % Solve BPDN problem (without weights) sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); % Show reconstructed image figure(1); subplot(223); imagesc(real(sol)); axis image; axis off; colormap gray; title(['First estimate - ', ... num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow; % Refine the estimate param.weights = 1./(abs(sol)+1e-5); sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); % Show reconstructed image figure(1); subplot(224); imagesc(real(sol)); axis image; axis off; colormap gray; title(['Second estimate - ', ... num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow; sopt-2.0.0/matlab/Example_weighted_TVDN.m000066400000000000000000000055341277570055300202440ustar00rootroot00000000000000%% Exampled_weighted_TVDN % Example to demonstrate use of TVDN solver when incorporating weights % (performs one re-weighting of previous solution). %% Clear workspace clc; clear; %% Define paths addpath misc/ addpath prox_operators/ %% Parameters N = 64; input_snr = 30; % Noise level (on the measurements) randn('seed', 1); rand('seed', 1); %% Load image im = phantom(N); % figure(1); clf; subplot(141), imagesc(im); axis image; axis off; colormap gray; title('Original image'); drawnow; %% Create a mask % Mask mask = rand(size(im)) < 0.33; ind = find(mask==1); % Masking matrix (sparse matrix in matlab) Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im)); %% Measure a few Fourier measurements % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1); At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im))); % TV sparsity operator Psit = @(x) x; Psi = Psit; % Select 33% of Fourier coefficients y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); % Display the downsampled image figure(1); subplot(142); imagesc(real(At(y))); axis image; axis off; colormap gray; title('Measured image'); drawnow; %% Reconstruct with TV % Tolerance on noise epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise; % Parameters for TVDN param.verbose = 1; % Print log or not param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem param.max_iter = 200; % Max. nb. of iterations for the TVDN problem param.gamma = 1e-1; % Converge parameter param.nu_B2 = 1; % Bound on the norm of the operator A param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0) param.max_iter_TV = 500; % param.zero_weights_flag_TV = 0; % param.identical_weights_flag_TV = 1; % % Solve TVDN problem (without weights) sol_1 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param); % Show first reconstructed image figure(1); subplot(143); imagesc(real(sol_1)); axis image; axis off; colormap gray; title(['First estimate: ', ... num2str(sopt_mltb_SNR(im, real(sol_1))), 'dB']); drawnow; clc; %% Re-fine the estimate with weighted TV % Weights [param.weights_dx_TV param.weights_dy_TV] = sopt_mltb_gradient_op(real(sol_1)); param.weights_dx_TV = 1./(abs(param.weights_dx_TV)+1e-3); param.weights_dy_TV = 1./(abs(param.weights_dy_TV)+1e-3); param.identical_weights_flag_TV = 0; param.gamma = 1e-3; % First reconstruction with weights in the gradient param.zero_weights_flag_TV = 1; sol_2 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param); % Show second reconstructed image figure(1); subplot(144); imagesc(real(sol_2)); axis image; axis off; colormap gray; title(['Second estimate: ', ... num2str(sopt_mltb_SNR(im, real(sol_2))), 'dB']); drawnow; sopt-2.0.0/matlab/Experiment1.m000066400000000000000000000173511277570055300163370ustar00rootroot00000000000000%% Experiment1 % In this experiment we evaluate the performance of SARA for spread % spectrum acquisition. We use a 256x256 version of Lena as a test image. % Number of measurements is M = 0.2N and input SNR is set to 30 dB. These % parameters can be changed by modifying the variables p (for the % undersampling ratio) and input_snr (for the input SNR). %% Clear workspace clc clear; %% Define paths addpath misc/ addpath prox_operators/ addpath test_images/ %% Read image imagename = 'lena_256.tiff'; % Load image im = im2double(imread(imagename)); % Normalise im = im/max(max(im)); % Enforce positivity im(im<0) = 0; %% Parameters input_snr = 30; % Noise level (on the measurements) %Undersampling ratio M/N p=0.2; %% Sparsity operators %Wavelet decomposition depth nlevel=4; dwtmode('per'); [C,S]=wavedec2(im,nlevel,'db8'); ncoef=length(C); [C1,S1]=wavedec2(im,nlevel,'db1'); ncoef1=length(C1); [C2,S2]=wavedec2(im,nlevel,'db2'); ncoef2=length(C2); [C3,S3]=wavedec2(im,nlevel,'db3'); ncoef3=length(C3); [C4,S4]=wavedec2(im,nlevel,'db4'); ncoef4=length(C4); [C5,S5]=wavedec2(im,nlevel,'db5'); ncoef5=length(C5); [C6,S6]=wavedec2(im,nlevel,'db6'); ncoef6=length(C6); [C7,S7]=wavedec2(im,nlevel,'db7'); ncoef7=length(C7); %SARA Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';... wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';... wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+... waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+... waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8); %Db8 wavelet basis Psit2 = @(x) wavedec2(x, nlevel,'db8'); Psi2 = @(x) waverec2(x,S,'db8'); %Curvelet %CurveLab needs to be installed to run Curvelet simulations realv = 1; Cv = fdct_usfft(im,realv); Mod = sopt_mltb_struct2size(Cv); Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv); %% Spread spectrum operator % Mask mask = rand(size(im)) < p; ind = find(mask==1); % Masking matrix (sparse matrix in matlab) Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im)); %Spread spectrum sequence ss=rand(size(im)); C=(2*(ss<0.5)-1); A = @(x) Ma*reshape(fft2(C.*x)/sqrt(numel(ind)), numel(x), 1); At = @(x) C.*(ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind)))); % Sampling y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); % Tolerance on noise epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise; epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise; % Parameters for BPDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 5e-4; % Stopping criterion for the L1 problem param.max_iter = 200; % Max. number of iterations for the L1 problem param.nu_B2 = 1; % Bound on the norm of the operator A param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active param.max_iter_B2=300; param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) param.nu_L1 = 1; param.max_iter_L1 = 20; param.rel_obj_L1 = 1e-2; % Solve BPSA problem sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro')); % SARA % It uses the solution to BPSA as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8)); tol=1e-3; sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1); RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro')); % Solve BPBb8 problem sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param); RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro')); % RWBPDb8 % It uses the solution to BPDBb8 as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3); RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro')); % Parameters for Curvelet % Parameters for BPDN param3.verbose = 1; % Print log or not param3.gamma = 1e-1; % Converge parameter param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem param3.max_iter = 200; % Max. number of iterations for the L1 problem param3.nu_B2 = 1; % Bound on the norm of the operator A param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0) param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) % Solve BP Curvelet problem sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3); RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro')); % RW-Curvelet % It uses the solution to BPDBb8 as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5); RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro')); % Parameters for TVDN param1.verbose = 1; % Print log or not param1.gamma = 1e-1; % Converge parameter param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem param1.max_iter = 200; % Max. number of iterations for the TVDN problem param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator) param1.nu_B2 = 1; % Bound on the norm of the operator A param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param1.max_iter_B2 = 300; param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise % Solve TV problem sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1); RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro')); % RWTV % It uses the solution to TV as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7); RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro')); %Show reconstructed images figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray; title(['BPSA, SNR=',num2str(RSNR1), 'dB']) figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray; title(['SARA, SNR=',num2str(RSNR2), 'dB']) figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray; title(['BPDb8, SNR=',num2str(RSNR3), 'dB']) figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray; title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB']) figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray; title(['Curvelet, SNR=',num2str(RSNR5), 'dB']) figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray; title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB']) figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray; title(['TV, SNR=',num2str(RSNR7), 'dB']) figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray; title(['RW-TV, SNR=',num2str(RSNR8), 'dB']) sopt-2.0.0/matlab/Experiment2.m000066400000000000000000000172431277570055300163400ustar00rootroot00000000000000%% Experiment2 % In this experiment we study the performance of SARA with Gaussian random % matrices as measurements operators. Due to computational limitations for % the use of a dense sensing matrix, for this experiment we use a cropped % version of Lena, around the head, of dimension 128x128 as a test image. % Number of measurements is M = 0.3N and input SNR is set to 30 dB. These % parameters can be changed by modifying the variables p (for the % undersampling ratio) and input_snr (for the input SNR). %% Clear workspace clc clear; %% Define paths addpath misc/ addpath prox_operators/ addpath test_images/ %% Read image imagename = 'lena_256.tiff'; % Load image im1 = im2double(imread(imagename)); %Crope image a=70; b=96; im=im1(a+1:a+128,b+1:b+128); % Enforce positivity im(im<0) = 0; %% Parameters input_snr = 30; % Noise level (on the measurements) %Undersampling ratio M/N p=0.3; %% Sparsity operators %Wavelet decomposition depth nlevel=4; dwtmode('per'); [C,S]=wavedec2(im,nlevel,'db8'); ncoef=length(C); [C1,S1]=wavedec2(im,nlevel,'db1'); ncoef1=length(C1); [C2,S2]=wavedec2(im,nlevel,'db2'); ncoef2=length(C2); [C3,S3]=wavedec2(im,nlevel,'db3'); ncoef3=length(C3); [C4,S4]=wavedec2(im,nlevel,'db4'); ncoef4=length(C4); [C5,S5]=wavedec2(im,nlevel,'db5'); ncoef5=length(C5); [C6,S6]=wavedec2(im,nlevel,'db6'); ncoef6=length(C6); [C7,S7]=wavedec2(im,nlevel,'db7'); ncoef7=length(C7); %Sparsity averaging operator Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';... wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';... wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+... waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+... waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8); %Db8 wavelet basis Psit2 = @(x) wavedec2(x, nlevel,'db8'); Psi2 = @(x) waverec2(x,S,'db8'); %Curvelet %CurveLab needs to be installed to run Curvelet simulations realv = 1; Cv = fdct_usfft(im,realv); Mod = sopt_mltb_struct2size(Cv); Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv); %% Gaussian matrix operator num_meas=floor(p*numel(im)); Phi = randn(num_meas,numel(im))/sqrt(num_meas); bound=svds(Phi,1)^2; A = @(x) Phi*x(:); At = @(x) reshape(Phi'*x(:),size(im)); % Sampling y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)))*sigma_noise; % Tolerance on noise epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise; epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise; % Parameters for BPDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 5e-4; % Stopping criterion for the L1 problem param.max_iter = 200; % Max. number of iterations for the L1 problem param.nu_B2 = bound; % Bound on the norm of the operator A param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active param.max_iter_B2=300; param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) param.nu_L1 = 1; param.max_iter_L1 = 20; param.rel_obj_L1 = 1e-2; % Solve BPSA problem sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro')); % SARA % It uses the solution to BPSA as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8)); tol=1e-3; sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1); RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro')); % Solve BPBb8 problem sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param); RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro')); % RWBPDb8 % It uses the solution to BPDBb8 as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3); RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro')); % Parameters for Curvelet % Parameters for BPDN param3.verbose = 1; % Print log or not param3.gamma = 1e-1; % Converge parameter param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem param3.max_iter = 200; % Max. number of iterations for the L1 problem param3.nu_B2 = bound; % Bound on the norm of the operator A param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0) param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) % Solve BP Curvelet problem sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3); RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro')); % RW-Curvelet % It uses the solution to BPDBb8 as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5); RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro')); % Parameters for TVDN param1.verbose = 1; % Print log or not param1.gamma = 1e-1; % Converge parameter param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem param1.max_iter = 200; % Max. number of iterations for the TVDN problem param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator) param1.nu_B2 = bound; % Bound on the norm of the operator A param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param1.max_iter_B2 = 300; param1.pos_B2 = 1; % Solve TV problem sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1); RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro')); % RWTV % It uses the solution to TV as a warm start maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im))); tol=1e-3; sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7); RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro')); %Show reconstructed images figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray; title(['BPSA, SNR=',num2str(RSNR1), 'dB']) figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray; title(['SARA, SNR=',num2str(RSNR2), 'dB']) figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray; title(['BPDb8, SNR=',num2str(RSNR3), 'dB']) figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray; title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB']) figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray; title(['Curvelet, SNR=',num2str(RSNR5), 'dB']) figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray; title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB']) figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray; title(['TV, SNR=',num2str(RSNR7), 'dB']) figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray; title(['RW-TV, SNR=',num2str(RSNR8), 'dB']) sopt-2.0.0/matlab/Experiment3.m000066400000000000000000000123541277570055300163370ustar00rootroot00000000000000%% Experiement3 % In this experiment we illustrate the application of SARA to Fourier % imaging. We reconstruct a 224x168 positive brain image from standard % variable density sampling. Fourier measurements, for an undersampling % ratio of M = 0.05N and input SNR set to 30 dB. %% Clear workspace clc clear; %% Define paths addpath misc/ addpath prox_operators/ addpath test_images/ %% Read image % Load image load Brain_low_res im=abs(map_ref); % Normalise im = im/max(max(im)); % Enforce positivity im(im<0) = 0; %% Parameters input_snr = 30; % Noise level (on the measurements) %Undersampling ratio M/N %The range of p is 0 < p <= 0.5 since the vdsmask %function samples only half plane. Therefore, full %sampling is p = 0.5 p=0.05; %% Sparsity operators %Wavelet decomposition depth nlevel=4; dwtmode('per'); [C,S]=wavedec2(im,nlevel,'db8'); ncoef=length(C); [C1,S1]=wavedec2(im,nlevel,'db1'); ncoef1=length(C1); [C2,S2]=wavedec2(im,nlevel,'db2'); ncoef2=length(C2); [C3,S3]=wavedec2(im,nlevel,'db3'); ncoef3=length(C3); [C4,S4]=wavedec2(im,nlevel,'db4'); ncoef4=length(C4); [C5,S5]=wavedec2(im,nlevel,'db5'); ncoef5=length(C5); [C6,S6]=wavedec2(im,nlevel,'db6'); ncoef6=length(C6); [C7,S7]=wavedec2(im,nlevel,'db7'); ncoef7=length(C7); %Sparsity averaging operator Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';... wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';... wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+... waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+... waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+... waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8); %Db8 wavelet basis Psit2 = @(x) wavedec2(x, nlevel,'db8'); Psi2 = @(x) waverec2(x,S,'db8'); % Variable density mask mask = sopt_mltb_vdsmask(size(im,1),size(im,2),p); ind = find(mask==1); % Masking matrix (sparse matrix in matlab) Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im)); % Composition (Masking o Fourier) A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1); At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind)))); % Select p% of Fourier coefficients y = A(im); % Add Gaussian i.i.d. noise sigma_noise = 10^(-input_snr/20)*std(im(:)); y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2); % Tolerance on noise epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise; epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise; %% Parameters for BPDN param.verbose = 1; % Print log or not param.gamma = 1e-1; % Converge parameter param.rel_obj = 4e-4; % Stopping criterion for the L1 problem param.max_iter = 200; % Max. number of iterations for the L1 problem param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param.nu_B2 = 1; % Bound on the norm of the operator A param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0) param.nu_L1 = 1; param.max_iter_L1 = 20; param.rel_obj_L1 = 1e-2; % Solve SARA maxiter=10; sigma=sigma_noise*sqrt(numel(y)/(numel(im)*9)); tol=1e-3; sol1 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter); RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro')); %% Parameters for TVDN param1.verbose = 1; % Print log or not param1.gamma = 3e-1; % Converge parameter param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem param1.max_iter = 200; % Max. number of iterations for the TVDN problem param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator) param1.nu_B2 = 1; % Bound on the norm of the operator A param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0) param1.max_iter_B2 = 200; param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise % Solve TVDN problem sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1); RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro')); % Solve BPDN problem sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param); RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro')); figure, imagesc(sol1,[0 1]);axis image;axis off; colormap gray; title(['SARA, SNR=',num2str(RSNR1), 'dB']) figure, imagesc(sol2,[0 1]);axis image;axis off; colormap gray; title(['TV, SNR=',num2str(RSNR2), 'dB']) figure, imagesc(sol3,[0 1]);axis image;axis off; colormap gray; title(['BPDb8, SNR=',num2str(RSNR3), 'dB']) figure, imagesc(im, [0 1]); axis image; axis off; colormap gray; title('Original image') sopt-2.0.0/matlab/README.txt000066400000000000000000000054051277570055300154530ustar00rootroot00000000000000 SOPT: Sparse OPTimisation SARA algorithm for sparsity averaging ---------------------------------------------------------------- DESCRIPTION This is a Matlab implementation of the SARA algorithm presented in: [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-P. Thiran, and Y. Wiaux. "Sparsity averaging for compressive imaging", IEEE Signal Processing Letters, Vol. 20, No. 6, pp. 591-594, 2013 (arXiv:1208.2330). AUTHORS R. E. Carillo (http://people.epfl.ch/rafael.carrillo) G. Puy (http://people.epfl.ch/gilles.puy) J. D. McEwen (http://www.jasonmcewen.org) Y. Wiaux (http://basp.eps.hw.ac.uk) EXPERIMENTS To test a reconstruction with spread spectrum measurements, run the script Experiment1.m. If you want to run the same experiment with the cameraman test image just change the variable image name to 'cameraman_256.tiff'. To test a reconstruction with random Gaussian measurements, run the script Experiment2.m. To run the MRI example in the paper, run the script Experiment3.m. REFERENCES When referencing this code, please cite our related paper: [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-P. Thiran, and Y. Wiaux. "Sparsity averaging for compressive imaging", IEEE Signal Processing Letters, Vol. 20, No. 6, pp. 591-594, 2013 (arXiv:1208.2330). DOCUMENTATION See doc/index.html INSTALLATION To run the experiments the CurveLab toolbox (www.curvelet.org) must be installed. Otherwise the SOPT Matlab code should run as is, without any additional installation. DOWNLOAD https://github.com/basp-group/sopt SUPPORT If you have any questions or comments, feel free to contact Rafael Carrillo at: rafael {DOT} carrillo {AT} epfl {DOT} ch. NOTES The code is not optimized and is given for educational purpose. This is a first Matlab implementation of the code. A more general and optimised C code is found in the root folder. LICENSE SOPT: Sparse OPTimisation package Copyright (C) 2013 Rafael Carrillo, Gilles Puy, Jason McEwen, Yves Wiaux This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details (LICENSE.txt). You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. sopt-2.0.0/matlab/doc/000077500000000000000000000000001277570055300145165ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/alpha.png000066400000000000000000000004211277570055300163060ustar00rootroot00000000000000PNG  IHDRPIDATxQ0*p& =4 NfC@Pzb:`Fy84Φ{P9^ lJo˧U7wRYa$r'ͧGDUU ݦ [)ӓU6vV T5p9vy*jM7h6% 7]Ai6+hrxA~A""dfմ6bݙi | IENDB`sopt-2.0.0/matlab/doc/c++.png000066400000000000000000000005071277570055300155760ustar00rootroot00000000000000PNG  IHDRPbKGD pHYs  ~tIME+ +IDATx 0 *U*a7BZB|O&:;9?PD9N0sժ}YhaqB,3coVh(Sc V[kSkmYƍgO>aiZHP̬yiGRdž@tas?t\_ߍI Eaf:>_y)W[z˰IENDB`sopt-2.0.0/matlab/doc/c.png000066400000000000000000000003741277570055300154520ustar00rootroot00000000000000PNG  IHDRPIDATxQ0ң*ݺNc:q֬~OI0/. ~~D8;a,:Q8CkY;:gϋD1V1oUl^iә\4[S{]tn+x*=|ȢTY7؈#"d3в/B|2n't?{IENDB`sopt-2.0.0/matlab/doc/demoicon.gif000066400000000000000000000003261277570055300170030ustar00rootroot00000000000000GIF89a RUJJRZ9BJƾJB<ý!,S`&YE٦UdKXQ $ܪiPgL BA|U"aL9 BUr*ҪDh\7  ~ɏ+!;sopt-2.0.0/matlab/doc/down.png000066400000000000000000000002051277570055300161700ustar00rootroot00000000000000PNG  IHDR PLTEfs pHYsHHFk>%IDATxc```PSR|x d*l@ܺ? 5  $word, "match"=>$w, "index"=>$statIdx, "full"=>strlen($w)==strlen($word), "docs"=>array() ); } $w = readString($file); } $totalFreq=0; for ($count=$start;$count$idx,"freq"=>$freq,"rank"=>0.0); $totalFreq+=$freq; if ($statInfo["full"]) $totalfreq+=$freq; } // read name an url info for the doc for ($i=0;$i<$numDocs;$i++) { fseek($file,$docInfo[$i]["idx"]); $docInfo[$i]["name"]=readString($file); $docInfo[$i]["url"]=readString($file); } $statInfo["docs"]=$docInfo; } for ($count=$start;$count$key, "name"=>$di["name"], "rank"=>$rank ); } $docs[$key]["words"][] = array( "word"=>$wordInfo["word"], "match"=>$wordInfo["match"], "freq"=>$di["freq"] ); } } return $docs; } function normalize_ranking(&$docs) { $maxRank = 0.0000001; // compute maximal rank foreach ($docs as $doc) { if ($doc["rank"]>$maxRank) { $maxRank=$doc["rank"]; } } reset($docs); // normalize rankings while (list ($key, $val) = each ($docs)) { $docs[$key]["rank"]*=100/$maxRank; } } function filter_results($docs,&$requiredWords,&$forbiddenWords) { $filteredDocs=array(); while (list ($key, $val) = each ($docs)) { $words = &$docs[$key]["words"]; $copy=1; // copy entry by default if (sizeof($requiredWords)>0) { foreach ($requiredWords as $reqWord) { $found=0; foreach ($words as $wordInfo) { $found = $wordInfo["word"]==$reqWord; if ($found) break; } if (!$found) { $copy=0; // document contains none of the required words break; } } } if (sizeof($forbiddenWords)>0) { foreach ($words as $wordInfo) { if (in_array($wordInfo["word"],$forbiddenWords)) { $copy=0; // document contains a forbidden word break; } } } if ($copy) $filteredDocs[$key]=$docs[$key]; } return $filteredDocs; } function compare_rank($a,$b) { return ($a["rank"]>$b["rank"]) ? -1 : 1; } function sort_results($docs,&$sorted) { $sorted = $docs; usort($sorted,"compare_rank"); return $sorted; } function report_results(&$docs) { echo "\n"; echo " \n"; echo " \n"; echo " \n"; $numDocs = sizeof($docs); if ($numDocs==0) { echo " \n"; echo " \n"; echo " \n"; } else { echo " \n"; echo " \n"; echo " \n"; $num=1; foreach ($docs as $doc) { echo " \n"; echo " "; echo "\n"; echo " \n"; echo " \n"; echo " \n"; $num++; } } echo "

Search Results

".matches_text(0)."
".matches_text($numDocs); echo "\n"; echo "
$num.".$doc["name"]."
Matches: "; foreach ($doc["words"] as $wordInfo) { $word = $wordInfo["word"]; $matchRight = substr($wordInfo["match"],strlen($word)); echo "$word$matchRight(".$wordInfo["freq"].") "; } echo "
\n"; } function matches_text($num) { if ($num==0) { return 'Sorry, no documents matching your query.'; } else if ($num==1) { return 'Found 1 document matching your query.'; } else // $num>1 { return 'Found '.$num.' documents matching your query. Showing best matches first.'; } } function main($idxfile) { if(strcmp('4.1.0', phpversion()) > 0) { die("Error: PHP version 4.1.0 or above required!"); } if (!($file=fopen($idxfile,"rb"))) { die("Error: Search index file could NOT be opened!"); } if (readHeader($file)!="DOXS") { die("Error: Header of index file is invalid!"); } $query=""; if (array_key_exists("query", $_GET)) { $query=$_GET["query"]; } $results = array(); $requiredWords = array(); $forbiddenWords = array(); $foundWords = array(); $word=strtolower(strtok($query," ")); while ($word) // for each word in the search query { if (($word{0}=='+')) { $word=substr($word,1); $requiredWords[]=$word; } if (($word{0}=='-')) { $word=substr($word,1); $forbiddenWords[]=$word; } if (!in_array($word,$foundWords)) { $foundWords[]=$word; search($file,$word,$results); } $word=strtolower(strtok(" ")); } $docs = array(); combine_results($results,$docs); // filter out documents with forbidden word or that do not contain // required words $filteredDocs = filter_results($docs,$requiredWords,$forbiddenWords); // normalize rankings so they are in the range [0-100] normalize_ranking($filteredDocs); // sort the results based on rank $sorted = array(); sort_results($filteredDocs,$sorted); // report results to the user report_results($sorted); fclose($file); } ?> sopt-2.0.0/matlab/doc/fortran.png000066400000000000000000000004111277570055300166730ustar00rootroot00000000000000PNG  IHDRPIDATxQ q*p&z{`mڴ.K5@[GD0 0nKB1\øNB*hm8Vb]<'!].=U1PB]S{BTZY@49 lJK*\li69g|jжe'Dd{סul -˸#IENDB`sopt-2.0.0/matlab/doc/hp.png000066400000000000000000000003771277570055300156420ustar00rootroot00000000000000PNG  IHDRPIDATx @Mh ɬbvWD?!-O9X!`Bhu'V"q~L!4Ηpmugpƙ<9 }G9 21Ke[̼ٶCSضfLz0m5RYj«aT'+Vosm?KcKՊven;e$&>!IENDB`sopt-2.0.0/matlab/doc/index.html000066400000000000000000000107651277570055300165240ustar00rootroot00000000000000 Matlab Index

Matlab Index

Matlab Directories

Matlab Files found in these Directories

Example_BPDN sopt_mltb_SNR sopt_mltb_gradient_op_sphere sopt_mltb_solve_TVDNoA
Example_TVDN sopt_mltb_TV_norm sopt_mltb_modifypdf sopt_mltb_solve_rwBPDN
Example_TVDN2 sopt_mltb_adjcurvelet sopt_mltb_proj_B2 sopt_mltb_solve_rwTVDN
Example_TVDNoA sopt_mltb_div_op sopt_mltb_prox_L1 sopt_mltb_struct2size
Example_weighted_BPDN sopt_mltb_div_op_sphere sopt_mltb_prox_TV sopt_mltb_vdsmask
Example_weighted_TVDN sopt_mltb_fast_proj_B2 sopt_mltb_prox_TVoA
Experiment1 sopt_mltb_fwdcurvelet sopt_mltb_solve_BPDN
Experiment2 sopt_mltb_genmask sopt_mltb_solve_L2DN
Experiment3 sopt_mltb_gradient_op sopt_mltb_solve_TVDN

Generated on Fri 22-Feb-2013 15:54:46 by m2html © 2005
sopt-2.0.0/matlab/doc/left.png000066400000000000000000000002101277570055300161470ustar00rootroot00000000000000PNG  IHDR PLTEfs pHYsHHFk>(IDATxc```B5*0aH`ap``?P ^/IENDB`sopt-2.0.0/matlab/doc/linux.png000066400000000000000000000004201277570055300163570ustar00rootroot00000000000000PNG  IHDRPIDATxQ U3իԻ:B@SC%_JH@DN"1dtв,;5<*ǫ=O"D}v*l 99x4 UOTl< I\ᒧQ֗J=WmKZzM+a3#b%ݸt3ݙ 03,']~Yn'F|S2IENDB`sopt-2.0.0/matlab/doc/m2html.css000066400000000000000000000022441277570055300164350ustar00rootroot00000000000000body { background: white; color: black; font-family: arial,sans-serif; margin: 0; padding: 1ex; } div.fragment { width: 98%; border: 1px solid #CCCCCC; background-color: #f5f5f5; padding-left: 4px; margin: 4px; } div.box { width: 98%; background-color: #f5f5f5; border: 1px solid #CCCCCC; color: black; padding: 4px; } .comment { color: #228B22; } .string { color: #B20000; } .keyword { color: #0000FF; } .keywordtype { color: #604020; } .keywordflow { color: #e08000; } .preprocessor { color: #806020; } .stringliteral { color: #002080; } .charliteral { color: #008080; } a { text-decoration: none; } a:hover { background-color: #006699; color:#FFFFFF; } a.code { font-weight: normal; color: #A020F0; } a.code:hover { background-color: #FF0000; color: #FFFFFF; } h1 { background: transparent; color: #006699; font-size: x-large; text-align: center; } h2 { background: transparent; color: #006699; font-size: large; } address { font-size:small; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #eeeeff; } li { padding-left:5px; }sopt-2.0.0/matlab/doc/matlab/000077500000000000000000000000001277570055300157565ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/.DS_Store000066400000000000000000000140041277570055300174400ustar00rootroot00000000000000Bud1bwspblobmiscbwspblobbplist00  \WindowBounds[ShowSidebar]ShowStatusBar[ShowPathbar[ShowToolbar\SidebarWidth_{{1493, 398}, {1119, 778}}  ". Description of Example_BPDN
Home > matlab > Example_BPDN.m

Example_BPDN

PURPOSE ^

% Example_BPDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_BPDN
 Example to demonstrate use of BPDN solver.  A random Fourier sampling
 measurement operator is considered.  Daubechies 8 wavelets are used for
 the sparsifying operator.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_BPDN
0002 % Example to demonstrate use of BPDN solver.  A random Fourier sampling
0003 % measurement operator is considered.  Daubechies 8 wavelets are used for
0004 % the sparsifying operator.
0005 
0006 
0007 %% Clear workspace
0008 
0009 clc
0010 clear;
0011 
0012 
0013 %% Define paths
0014 
0015 addpath misc/
0016 addpath prox_operators/
0017 
0018 
0019 %% Define parameters
0020 
0021 % Coverages (half the plane for Fourier sampling)
0022 p = [0.50];
0023 
0024 % Noise level (on the measurements)
0025 input_snr = 30;
0026 
0027 
0028 %% Read image
0029 
0030 % Load image
0031 im = im2double(imread('cameraman.tif'));
0032 
0033 % Normalise
0034 im = im/max(max(im));
0035 
0036 % Enforce positivity
0037 im(im<0) = 0;
0038 
0039 
0040 %% Define sparsity operator
0041 
0042 dwtmode('per');
0043 
0044 % Decomposition level of the wavelet transform.
0045 nlevel = 4;
0046 
0047 % Daubechies 8 wavelet operator
0048 [C,S] = wavedec2(im,nlevel,'db8');
0049 
0050 Psit = @(x) wavedec2(x, nlevel, 'db8');
0051 Psi = @(x) waverec2(x, S, 'db8');
0052 
0053 
0054 %% Run simulations
0055 
0056 % Random Fourier sampling example
0057 %  Define mask
0058 %  Uniform sampling of the half Fourier plane
0059 mask = rand(size(im)) < p;
0060 mask(:,1:floor(size(im,2)/2))=0;
0061 mask = ifftshift(mask);
0062 mask(1,1)=0;
0063 mask(floor(size(im,1)/2):end,1)=0;
0064 
0065 ind = find(mask==1);
0066 Ma = sparse(1:numel(ind), ind, ...
0067   ones(numel(ind), 1), numel(ind), numel(im));
0068 
0069 % Composition (Masking o Fourier)
0070 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0071 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0072 
0073 % Apply measurement operator
0074 y = A(im);
0075 
0076 % Add Gaussian i.i.d. noise
0077 sigma_noise = 10^(-input_snr/20)*std(im(:));
0078 noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0079 y = y + noise;
0080 
0081 % Tolerance on noise
0082 epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise;
0083 epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise;
0084 tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball
0085 
0086 % Solve optimisation problem
0087 
0088 % Parameters for BPDN
0089 param.verbose = 1; % Print log or not
0090 param.gamma = 1e-1; % Convergence parameter
0091 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0092 param.max_iter = 200; % Max. number of iterations for the L1 problem
0093 param.nu_B2 = 1; % Bound on the norm of the operator A
0094 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0095 param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection
0096 param.pos_B2 = 1; %Positivity flag
0097 param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball
0098 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0099 %Optional parameters when Psit is not a tight frame:
0100 %param.nu_L1 = 1; % Bound on the norm of the operator Psit
0101 %param.max_iter_L1 = 200; %Max. number of iterations of the L1 prox
0102 %param.rel_obj_L1 = 1e-3; % Tolerance for the prox L1
0103 
0104 % Solve BPDN problem with positivity constraint
0105 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0106 
0107 % Compute SNR
0108 RSNR1 = 20*log10(norm(im,'fro') ...
0109   / norm(im-sol1,'fro'));
0110 
0111 % Example with only reality constraint
0112 param.pos_B2 = 0; %Positivity flag
0113 param.real_B2 = 1; %Reality flag
0114 
0115 % Solve BPDN problem
0116 sol2 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0117 
0118 % Compute SNR
0119 RSNR2 = 20*log10(norm(im,'fro') ...
0120   / norm(im-sol2,'fro'));
0121 
0122 
0123 %% Show results
0124 
0125 figure
0126 imagesc(sol1), axis off, axis image, colorbar
0127 title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB'])
0128 colormap gray
0129 
0130 figure
0131 imagesc(sol2), axis off, axis image, colorbar
0132 title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB'])
0133 colormap gray

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Example_TVDN.html.svn-base000066400000000000000000000167721277570055300254040ustar00rootroot00000000000000 Description of Example_TVDN
Home > matlab > Example_TVDN.m

Example_TVDN

PURPOSE ^

% Example_TVDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_TVDN
 Example to demonstrate use of TVDN solver.  A random Fourier sampling
 measurement operator is considered.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_TVDN
0002 % Example to demonstrate use of TVDN solver.  A random Fourier sampling
0003 % measurement operator is considered.
0004 
0005 
0006 %% Clear workspace
0007 
0008 clc
0009 clear;
0010 
0011 
0012 %% Define paths
0013 
0014 addpath misc/
0015 addpath prox_operators/
0016 
0017 
0018 %% Define parameters
0019 
0020 % Coverages (half the plane for Fourier sampling)
0021 p = [0.50];
0022 
0023 % Noise level (on the measurements)
0024 input_snr = 30;
0025 
0026 
0027 %% Read image
0028 
0029 % Load image
0030 im = im2double(imread('cameraman.tif'));
0031 
0032 % Normalise
0033 im = im/max(max(im));
0034 
0035 % Enforce positivity
0036 im(im<0) = 0;
0037 
0038 
0039 %% Run simulations
0040 
0041 %Random Fourier sampling example
0042 % Define mask
0043 % Uniform sampling of the half Fourier plane
0044 mask = rand(size(im)) < p;
0045 mask(:,1:floor(size(im,2)/2))=0;
0046 mask = ifftshift(mask);
0047 mask(1,1)=0;
0048 mask(floor(size(im,1)/2):end,1)=0;
0049 
0050 ind = find(mask==1);
0051 Ma = sparse(1:numel(ind), ind, ...
0052   ones(numel(ind), 1), numel(ind), numel(im));
0053 
0054 % Composition (Masking o Fourier)
0055 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0056 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0057 
0058 % Apply measurement operator
0059 y = A(im);
0060 
0061 % Add Gaussian i.i.d. noise
0062 sigma_noise = 10^(-input_snr/20)*std(im(:));
0063 noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0064 y = y + noise;
0065 
0066 % Tolerance on noise
0067 epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise;
0068 epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise;
0069 tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball
0070 
0071 % Solve optimisation problem
0072 
0073 % Parameters for TVDN
0074 param.verbose = 1; % Print log or not
0075 param.gamma = 1e-1; % Converge parameter
0076 param.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0077 param.max_iter = 200; % Max. number of iterations for the TVDN problem
0078 param_TV.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0079 param.nu_B2 = 1; % Bound on the norm of the operator A
0080 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0081 param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection
0082 param.pos_B2 = 1; %Positivity flag
0083 param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball
0084 
0085 % Solve TVDN problem with positivity constraint
0086 sol1 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0087 
0088 % Compute SNR
0089 RSNR1 = 20*log10(norm(im,'fro') ...
0090   / norm(im-sol1,'fro'));
0091 
0092 % Example with only reality constraint
0093 param.pos_B2 = 0; %Positivity flag
0094 param.real_B2 = 1; %Reality flag
0095 
0096 % Solve TVDN problem
0097 sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0098 
0099 % Compute SNR
0100 RSNR2 = 20*log10(norm(im,'fro') ...
0101   / norm(im-sol2,'fro'));
0102 
0103 
0104 %% Show results
0105 
0106 figure
0107 imagesc(sol1), axis off, axis image, colorbar
0108 title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB'])
0109 colormap gray
0110 
0111 figure
0112 imagesc(sol2), axis off, axis image, colorbar
0113 title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB'])
0114 colormap gray

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Example_TVDN2.html.svn-base000066400000000000000000000162141277570055300254550ustar00rootroot00000000000000 Description of Example_TVDN2
Home > matlab > Example_TVDN2.m

Example_TVDN2

PURPOSE ^

% Example_TVDN2

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_TVDN2
 Two examples to demonstrate use of TVDN solver.  Simple inpainting and
 Fourier measurement examples are included.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_TVDN2
0002 % Two examples to demonstrate use of TVDN solver.  Simple inpainting and
0003 % Fourier measurement examples are included.
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 input_snr = 30; % Noise level (on the measurements)
0016 
0017 %% Load an image
0018 im = im2double(imread('cameraman.tif'));
0019 %
0020 figure(1);
0021 imagesc(im); axis image; axis off;
0022 colormap gray; title('Original image'); drawnow;
0023 
0024 %% Create a mask with 33% of 1 (the rest is set to 0)
0025 % Mask
0026 mask = rand(size(im)) < 0.33; ind = find(mask==1);
0027 % Masking matrix (sparse matrix in matlab)
0028 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0029 % Masking operator
0030 A = @(x) Ma*x(:); % Select 33% of the values in x;
0031 At = @(x) reshape(Ma'*x(:), size(im)); % Adjoint operator + reshape image
0032 
0033 %% First problem: Inpainting problem
0034 % Select 33% of pixels
0035 y = A(im);
0036 % Add Gaussian i.i.d. noise
0037 sigma_noise = 10^(-input_snr/20)*std(im(:));
0038 y = y + randn(size(y))*sigma_noise;
0039 % Display the downsampled image
0040 figure(2); clf;
0041 subplot(121); imagesc(At(y)); axis image; axis off;
0042 colormap gray; title('Measured image'); drawnow;
0043 % Parameters for TVDN
0044 param.verbose = 1; % Print log or not
0045 param.gamma = 1e-1; % Converge parameter
0046 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0047 param.max_iter = 200; % Max. number of iterations for the TVDN problem
0048 param_TV.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0049 param.nu_B2 = 1; % Bound on the norm of the operator A
0050 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0051 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0052 param.max_iter_B2 = 500;
0053 % Tolerance on noise
0054 epsilon = sqrt(chi2inv(0.99, numel(ind)))*sigma_noise;
0055 % Solve TVDN problem
0056 sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0057 % Show reconstructed image
0058 figure(2);
0059 subplot(122); imagesc(sol); axis image; axis off;
0060 colormap gray; title('Reconstructed image'); drawnow;
0061 
0062 %% Second problem: Reconstruct from 33% of Fourier measurements
0063 % Composition (Masking o Fourier)
0064 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0065 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0066 % Select 33% of Fourier coefficients
0067 y = A(im);
0068 % Add Gaussian i.i.d. noise
0069 sigma_noise = 10^(-input_snr/20)*std(im(:));
0070 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0071 % Display the downsampled image
0072 figure(3); clf;
0073 subplot(121); imagesc(real(At(y))); axis image; axis off;
0074 colormap gray; title('Measured image'); drawnow;
0075 % Tolerance on noise
0076 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0077 % Solve TVDN problem
0078 sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0079 % Show reconstructed image
0080 figure(3);
0081 subplot(122); imagesc(real(sol)); axis image; axis off;
0082 colormap gray; title('Reconstructed image'); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Example_TVDNoA.html.svn-base000066400000000000000000000125111277570055300256470ustar00rootroot00000000000000 Description of Example_TVDNoA
Home > matlab > Example_TVDNoA.m

Example_TVDNoA

PURPOSE ^

% Example TVDNoA

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example TVDNoA
 Example to demonstrate TVoA_B2 solver, where an additional operator is
 included in the TV norm of the TVDN problem.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example TVDNoA
0002 % Example to demonstrate TVoA_B2 solver, where an additional operator is
0003 % included in the TV norm of the TVDN problem.
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 32;
0016 input_snr = 1; % Noise level (on the measurements)
0017 randn('seed', 1);
0018 
0019 %% Load an image
0020 im_ref = phantom(N);
0021 %
0022 figure(1);
0023 imagesc(im_ref); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create an artifial operator to test prox_TVoS
0027 S = randn(N^2, N^2)/N^2;
0028 im = reshape(S\im_ref(:), N, N); % S*im is thus sparse in TV
0029 
0030 %% Add Gaussian i.i.d. noise to im
0031 y = im;
0032 sigma_noise = 10^(-input_snr/20)*std(im_ref(:));
0033 y = y + randn(size(y))*sigma_noise;
0034 
0035 %% Solving modified ROF
0036 % Parameters for TVDN
0037 param.verbose = 2; % Print log or not
0038 param.gamma = 1; % Converge parameter
0039 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0040 param.max_iter = 100; % Max. number of iterations for the TVDN problem
0041 param.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0042 param.nu_B2 = 1; % Bound on the norm of the measurement operator (Id here)
0043 param.tight_B2 = 1; % Indicate that A is a tight frame (1) or not (0)
0044 param.nu_TV = norm(S)^2; % Bound on the norm of the operator S
0045 func_S = @(x) reshape(S*x(:), N, N);
0046 func_St = @(x) reshape(S'*x(:), N, N);
0047 % Tolerance on noise
0048 epsilon = sqrt(chi2inv(0.99, numel(im)))*sigma_noise;
0049 % Identity
0050 A = @(x) x;
0051 % Solve
0052 sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, A, func_S, func_St, param);
0053 % Show reconstructed image
0054 figure(2);
0055 imagesc(func_S(sol)); axis image; axis off;
0056 colormap gray; title('Reconstructed image'); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Example_weighted_BPDN.html.svn-base000066400000000000000000000160221277570055300272200ustar00rootroot00000000000000 Description of Example_weighted_BPDN
Home > matlab > Example_weighted_BPDN.m

Example_weighted_BPDN

PURPOSE ^

% Exampled_weighted_L1

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Exampled_weighted_L1
 Example to demonstrate use of BPDN solver when incorporating weights
 (performs one re-weighting of previous solution).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Exampled_weighted_L1
0002 % Example to demonstrate use of BPDN solver when incorporating weights
0003 % (performs one re-weighting of previous solution).
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 64;
0016 input_snr = 30; % Noise level (on the measurements)
0017 randn('seed', 1); rand('seed', 1);
0018 
0019 %% Create an image with few spikes
0020 im = zeros(N); ind = randperm(N^2); im(ind(1:100)) = 1;
0021 %
0022 figure(1);
0023 subplot(221), imagesc(im); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create a mask
0027 % Mask
0028 mask = rand(size(im)) < 0.095; ind = find(mask==1);
0029 % Masking matrix (sparse matrix in matlab)
0030 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0031 % Masking operator
0032 A = @(x) Ma*x(:);
0033 At = @(x) reshape(Ma'*x(:), size(im));
0034 
0035 %% Reconstruct from a few Fourier measurements
0036 
0037 % Composition (Masking o Fourier)
0038 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0039 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0040 
0041 % Sparsity operator
0042 Psit = @(x) x; Psi = Psit;
0043 
0044 % Select 33% of Fourier coefficients
0045 y = A(im);
0046 
0047 % Add Gaussian i.i.d. noise
0048 sigma_noise = 10^(-input_snr/20)*std(im(:));
0049 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0050 
0051 % Display the downsampled image
0052 figure(1);
0053 subplot(222); imagesc(real(At(y))); axis image; axis off;
0054 colormap gray; title('Measured image'); drawnow;
0055 
0056 % Tolerance on noise
0057 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0058 
0059 % Parameters for BPDN
0060 param.verbose = 1; % Print log or not
0061 param.gamma = 1e-1; % Converge parameter
0062 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0063 param.max_iter = 300; % Max. number of iterations for the TVDN problem
0064 param.nu_B2 = 1; % Bound on the norm of the operator A
0065 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0066 param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0067 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0068 param.pos_l1 = 1; %
0069 
0070 % Solve BPDN problem (without weights)
0071 sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0072 
0073 % Show reconstructed image
0074 figure(1);
0075 subplot(223); imagesc(real(sol)); axis image; axis off;
0076 colormap gray; title(['First estimate - ', ...
0077     num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow;
0078 
0079 % Refine the estimate
0080 param.weights = 1./(abs(sol)+1e-5);
0081 sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0082 
0083 % Show reconstructed image
0084 figure(1);
0085 subplot(224); imagesc(real(sol)); axis image; axis off;
0086 colormap gray; title(['Second estimate - ', ...
0087     num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Example_weighted_TVDN.html.svn-base000066400000000000000000000166741277570055300272650ustar00rootroot00000000000000 Description of Example_weighted_TVDN
Home > matlab > Example_weighted_TVDN.m

Example_weighted_TVDN

PURPOSE ^

% Exampled_weighted_TVDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Exampled_weighted_TVDN
 Example to demonstrate use of TVDN solver when incorporating weights
 (performs one re-weighting of previous solution).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Exampled_weighted_TVDN
0002 % Example to demonstrate use of TVDN solver when incorporating weights
0003 % (performs one re-weighting of previous solution).
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 64;
0016 input_snr = 30; % Noise level (on the measurements)
0017 randn('seed', 1); rand('seed', 1);
0018 
0019 %% Load image
0020 im = phantom(N);
0021 %
0022 figure(1); clf;
0023 subplot(141), imagesc(im); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create a mask
0027 % Mask
0028 mask = rand(size(im)) < 0.33; ind = find(mask==1);
0029 % Masking matrix (sparse matrix in matlab)
0030 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0031 
0032 %% Measure a few Fourier measurements
0033 
0034 % Composition (Masking o Fourier)
0035 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0036 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0037 
0038 % TV sparsity operator
0039 Psit = @(x) x; Psi = Psit;
0040 
0041 % Select 33% of Fourier coefficients
0042 y = A(im);
0043 
0044 % Add Gaussian i.i.d. noise
0045 sigma_noise = 10^(-input_snr/20)*std(im(:));
0046 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0047 
0048 % Display the downsampled image
0049 figure(1);
0050 subplot(142); imagesc(real(At(y))); axis image; axis off;
0051 colormap gray; title('Measured image'); drawnow;
0052 
0053 %% Reconstruct with TV
0054 
0055 % Tolerance on noise
0056 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0057 
0058 % Parameters for TVDN
0059 param.verbose = 1; % Print log or not
0060 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0061 param.max_iter = 200; % Max. nb. of iterations for the TVDN problem
0062 param.gamma = 1e-1; % Converge parameter
0063 param.nu_B2 = 1; % Bound on the norm of the operator A
0064 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0065 param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0066 param.max_iter_TV = 500; %
0067 param.zero_weights_flag_TV = 0; %
0068 param.identical_weights_flag_TV = 1; %
0069 
0070 % Solve TVDN problem (without weights)
0071 sol_1 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0072 
0073 % Show first reconstructed image
0074 figure(1);
0075 subplot(143); imagesc(real(sol_1)); axis image; axis off;
0076 colormap gray; 
0077 title(['First estimate: ', ...
0078     num2str(sopt_mltb_SNR(im, real(sol_1))), 'dB']);
0079 drawnow;
0080 clc;
0081 
0082 %% Re-fine the estimate with weighted TV
0083 % Weights
0084 [param.weights_dx_TV param.weights_dy_TV] = sopt_mltb_gradient_op(real(sol_1));
0085 param.weights_dx_TV = 1./(abs(param.weights_dx_TV)+1e-3);
0086 param.weights_dy_TV = 1./(abs(param.weights_dy_TV)+1e-3);
0087 param.identical_weights_flag_TV = 0;
0088 param.gamma = 1e-3;
0089 
0090 % First reconstruction with weights in the gradient
0091 param.zero_weights_flag_TV = 1;
0092 sol_2 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0093 % Show second reconstructed image
0094 figure(1);
0095 subplot(144); imagesc(real(sol_2)); axis image; axis off;
0096 colormap gray; 
0097 title(['Second estimate: ', ...
0098     num2str(sopt_mltb_SNR(im, real(sol_2))), 'dB']); 
0099 drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Experiment1.html.svn-base000066400000000000000000000426341277570055300253530ustar00rootroot00000000000000 Description of Experiment1
Home > matlab > Experiment1.m

Experiment1

PURPOSE ^

% Experiment1

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiment1
 In this experiment we evaluate the performance of SARA for spread 
 spectrum acquisition. We use a 256x256 version of Lena as a test image. 
 Number of measurements is M = 0.2N and input SNR is set to 30 dB. These
 parameters can be changed by modifying the variables p (for the
 undersampling ratio) and input_snr (for the input SNR).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiment1
0002 % In this experiment we evaluate the performance of SARA for spread
0003 % spectrum acquisition. We use a 256x256 version of Lena as a test image.
0004 % Number of measurements is M = 0.2N and input SNR is set to 30 dB. These
0005 % parameters can be changed by modifying the variables p (for the
0006 % undersampling ratio) and input_snr (for the input SNR).
0007 
0008 
0009 %% Clear workspace
0010 
0011 clc
0012 clear;
0013 
0014 
0015 %% Define paths
0016 
0017 addpath misc/
0018 addpath prox_operators/
0019 addpath test_images/
0020 
0021 
0022 
0023 %% Read image
0024 
0025 imagename = 'lena_256.tiff';
0026 
0027 % Load image
0028 im = im2double(imread(imagename));
0029 
0030 % Normalise
0031 im = im/max(max(im));
0032 
0033 % Enforce positivity
0034 im(im<0) = 0;
0035 
0036 %% Parameters
0037 
0038 input_snr = 30; % Noise level (on the measurements)
0039 
0040 %Undersampling ratio M/N
0041 p=0.2;
0042 
0043 
0044 %% Sparsity operators
0045 
0046 %Wavelet decomposition depth
0047 nlevel=4;
0048 
0049 dwtmode('per');
0050 [C,S]=wavedec2(im,nlevel,'db8'); 
0051 ncoef=length(C);
0052 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0053 ncoef1=length(C1);
0054 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0055 ncoef2=length(C2);
0056 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0057 ncoef3=length(C3);
0058 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0059 ncoef4=length(C4);
0060 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0061 ncoef5=length(C5);
0062 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0063 ncoef6=length(C6);
0064 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0065 ncoef7=length(C7);
0066 
0067 %SARA
0068 
0069 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0070     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0071     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0072 
0073 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0074     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0075     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0076     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0080 
0081 %Db8 wavelet basis
0082 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0083 Psi2 = @(x) waverec2(x,S,'db8');
0084 
0085 %Curvelet
0086 %CurveLab needs to be installed to run Curvelet simulations
0087 realv = 1;
0088 Cv = fdct_usfft(im,realv);
0089 Mod = sopt_mltb_struct2size(Cv);
0090 
0091 Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); 
0092 Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv);
0093 
0094 %% Spread spectrum operator
0095 % Mask
0096 mask = rand(size(im)) < p; 
0097 ind = find(mask==1);
0098 % Masking matrix (sparse matrix in matlab)
0099 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0100     
0101 %Spread spectrum sequence
0102     
0103 ss=rand(size(im));
0104 C=(2*(ss<0.5)-1);
0105 
0106 A = @(x) Ma*reshape(fft2(C.*x)/sqrt(numel(ind)), numel(x), 1);
0107 At = @(x) C.*(ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0108     
0109 % Sampling
0110 y = A(im);
0111 % Add Gaussian i.i.d. noise
0112 sigma_noise = 10^(-input_snr/20)*std(im(:));
0113 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0114     
0115     
0116 % Tolerance on noise
0117 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0118 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0119     
0120     
0121 % Parameters for BPDN
0122 param.verbose = 1; % Print log or not
0123 param.gamma = 1e-1; % Converge parameter
0124 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0125 param.max_iter = 200; % Max. number of iterations for the L1 problem
0126 param.nu_B2 = 1; % Bound on the norm of the operator A
0127 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0128 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0129 param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active
0130 param.max_iter_B2=300;
0131 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0132 param.nu_L1 = 1;
0133 param.max_iter_L1 = 20;
0134 param.rel_obj_L1 = 1e-2;
0135     
0136     
0137 % Solve BPSA problem
0138     
0139 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0140     
0141 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0142     
0143 % SARA
0144 % It uses the solution to BPSA as a warm start
0145 maxiter=10;
0146 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8));
0147 tol=1e-3;
0148   
0149 sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1);
0150 
0151 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0152 
0153 % Solve BPBb8 problem
0154     
0155 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0156     
0157 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0158     
0159 % RWBPDb8
0160 % It uses the solution to BPDBb8 as a warm start
0161 maxiter=10;
0162 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0163 tol=1e-3;
0164   
0165 sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3);
0166       
0167 RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro'));
0168 
0169 % Parameters for Curvelet
0170 
0171 % Parameters for BPDN
0172 param3.verbose = 1; % Print log or not
0173 param3.gamma = 1e-1; % Converge parameter
0174 param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0175 param3.max_iter = 200; % Max. number of iterations for the L1 problem
0176 param3.nu_B2 = 1; % Bound on the norm of the operator A
0177 param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0178 param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0179 param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0180 param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0181 
0182     
0183 
0184 
0185 % Solve BP Curvelet problem
0186     
0187 sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3);
0188     
0189 RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro'));
0190     
0191 % RW-Curvelet
0192 % It uses the solution to BPDBb8 as a warm start
0193 maxiter=10;
0194 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0195 tol=1e-3;
0196   
0197 sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5);
0198      
0199 RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro'));
0200 
0201     
0202 % Parameters for TVDN
0203 param1.verbose = 1; % Print log or not
0204 param1.gamma = 1e-1; % Converge parameter
0205 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0206 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0207 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0208 param1.nu_B2 = 1; % Bound on the norm of the operator A
0209 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0210 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0211 param1.max_iter_B2 = 300;
0212 param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0213     
0214 % Solve TV problem
0215     
0216 sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0217     
0218 RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro'));
0219     
0220 % RWTV
0221 % It uses the solution to TV as a warm start
0222 maxiter=10;
0223 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0224 tol=1e-3;
0225   
0226 sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7);
0227     
0228 RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro'));
0229 
0230 
0231 %Show reconstructed images
0232 
0233 figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray;
0234 title(['BPSA, SNR=',num2str(RSNR1), 'dB'])
0235 figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray;
0236 title(['SARA, SNR=',num2str(RSNR2), 'dB'])
0237 
0238 figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray;
0239 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0240 figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray;
0241 title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB'])
0242 
0243 figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray;
0244 title(['Curvelet, SNR=',num2str(RSNR5), 'dB'])
0245 figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray;
0246 title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB'])
0247 
0248 figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray;
0249 title(['TV, SNR=',num2str(RSNR7), 'dB'])
0250 figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray;
0251 title(['RW-TV, SNR=',num2str(RSNR8), 'dB'])
0252 
0253 
0254 
0255 
0256 
0257 
0258 
0259 
0260 
0261 
0262

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Experiment2.html.svn-base000066400000000000000000000426531277570055300253550ustar00rootroot00000000000000 Description of Experiment2
Home > matlab > Experiment2.m

Experiment2

PURPOSE ^

% Experiment2

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiment2
 In this experiment we study the performance of SARA with Gaussian random 
 matrices as measurements operators. Due to computational limitations for 
 the use of a dense sensing matrix, for this experiment we use a cropped 
 version of Lena, around the head, of dimension 128x128 as a test image. 
 Number of measurements is M = 0.3N and input SNR is set to 30 dB. These
 parameters can be changed by modifying the variables p (for the
 undersampling ratio) and input_snr (for the input SNR).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiment2
0002 % In this experiment we study the performance of SARA with Gaussian random
0003 % matrices as measurements operators. Due to computational limitations for
0004 % the use of a dense sensing matrix, for this experiment we use a cropped
0005 % version of Lena, around the head, of dimension 128x128 as a test image.
0006 % Number of measurements is M = 0.3N and input SNR is set to 30 dB. These
0007 % parameters can be changed by modifying the variables p (for the
0008 % undersampling ratio) and input_snr (for the input SNR).
0009 
0010 
0011 %% Clear workspace
0012 
0013 clc
0014 clear;
0015 
0016 
0017 %% Define paths
0018 
0019 addpath misc/
0020 addpath prox_operators/
0021 addpath test_images/
0022 
0023 
0024 %% Read image
0025 
0026 imagename = 'lena_256.tiff';
0027 
0028 % Load image
0029 im1 = im2double(imread(imagename));
0030 
0031 %Crope image
0032 a=70;
0033 b=96;
0034 im=im1(a+1:a+128,b+1:b+128);
0035 
0036 % Enforce positivity
0037 im(im<0) = 0;
0038 
0039 %% Parameters
0040 
0041 input_snr = 30; % Noise level (on the measurements)
0042 
0043 %Undersampling ratio M/N
0044 p=0.3;
0045 
0046 %% Sparsity operators
0047 
0048 %Wavelet decomposition depth
0049 nlevel=4;
0050 
0051 dwtmode('per');
0052 [C,S]=wavedec2(im,nlevel,'db8'); 
0053 ncoef=length(C);
0054 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0055 ncoef1=length(C1);
0056 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0057 ncoef2=length(C2);
0058 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0059 ncoef3=length(C3);
0060 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0061 ncoef4=length(C4);
0062 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0063 ncoef5=length(C5);
0064 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0065 ncoef6=length(C6);
0066 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0067 ncoef7=length(C7);
0068 
0069 %Sparsity averaging operator
0070 
0071 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0072     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0073     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0074 
0075 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0076     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0080     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0081     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0082 
0083 %Db8 wavelet basis
0084 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0085 Psi2 = @(x) waverec2(x,S,'db8');
0086 
0087 %Curvelet
0088 %CurveLab needs to be installed to run Curvelet simulations
0089 realv = 1;
0090 Cv = fdct_usfft(im,realv);
0091 Mod = sopt_mltb_struct2size(Cv);
0092 
0093 Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); 
0094 Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv);
0095 
0096 %% Gaussian matrix operator
0097 
0098 num_meas=floor(p*numel(im));
0099 
0100 Phi = randn(num_meas,numel(im))/sqrt(num_meas);
0101         
0102 bound=svds(Phi,1)^2;
0103      
0104 A = @(x) Phi*x(:);
0105     
0106 At = @(x) reshape(Phi'*x(:),size(im));
0107     
0108    
0109 % Sampling
0110 y = A(im);
0111 % Add Gaussian i.i.d. noise
0112 sigma_noise = 10^(-input_snr/20)*std(im(:));
0113 y = y + (randn(size(y)))*sigma_noise;
0114     
0115     
0116 % Tolerance on noise
0117 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0118 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0119     
0120     
0121 % Parameters for BPDN
0122 param.verbose = 1; % Print log or not
0123 param.gamma = 1e-1; % Converge parameter
0124 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0125 param.max_iter = 200; % Max. number of iterations for the L1 problem
0126 param.nu_B2 = bound; % Bound on the norm of the operator A
0127 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0128 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0129 param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active
0130 param.max_iter_B2=300;
0131 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0132 param.nu_L1 = 1;
0133 param.max_iter_L1 = 20;
0134 param.rel_obj_L1 = 1e-2;
0135     
0136     
0137 % Solve BPSA problem
0138     
0139 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0140     
0141 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0142     
0143 % SARA
0144 % It uses the solution to BPSA as a warm start
0145 maxiter=10;
0146 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8));
0147 tol=1e-3;
0148   
0149 sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1);
0150 
0151 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0152 
0153 % Solve BPBb8 problem
0154     
0155 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0156     
0157 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0158     
0159 % RWBPDb8
0160 % It uses the solution to BPDBb8 as a warm start
0161 maxiter=10;
0162 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0163 tol=1e-3;
0164   
0165 sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3);
0166       
0167 RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro'));
0168 
0169 % Parameters for Curvelet
0170 
0171 % Parameters for BPDN
0172 param3.verbose = 1; % Print log or not
0173 param3.gamma = 1e-1; % Converge parameter
0174 param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0175 param3.max_iter = 200; % Max. number of iterations for the L1 problem
0176 param3.nu_B2 = bound; % Bound on the norm of the operator A
0177 param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0178 param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0179 param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0180 param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0181 
0182     
0183 
0184 
0185 % Solve BP Curvelet problem
0186     
0187 sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3);
0188     
0189 RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro'));
0190     
0191 % RW-Curvelet
0192 % It uses the solution to BPDBb8 as a warm start
0193 maxiter=10;
0194 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0195 tol=1e-3;
0196   
0197 sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5);
0198      
0199 RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro'));
0200 
0201     
0202 % Parameters for TVDN
0203 param1.verbose = 1; % Print log or not
0204 param1.gamma = 1e-1; % Converge parameter
0205 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0206 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0207 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0208 param1.nu_B2 = bound; % Bound on the norm of the operator A
0209 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0210 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0211 param1.max_iter_B2 = 300;
0212 param1.pos_B2 = 1;
0213     
0214 % Solve TV problem
0215     
0216 sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0217     
0218 RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro'));
0219     
0220 % RWTV
0221 % It uses the solution to TV as a warm start
0222 maxiter=10;
0223 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0224 tol=1e-3;
0225   
0226 sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7);
0227     
0228 RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro'));
0229 
0230 %Show reconstructed images
0231 
0232 figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray;
0233 title(['BPSA, SNR=',num2str(RSNR1), 'dB'])
0234 figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray;
0235 title(['SARA, SNR=',num2str(RSNR2), 'dB'])
0236 
0237 figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray;
0238 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0239 figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray;
0240 title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB'])
0241 
0242 figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray;
0243 title(['Curvelet, SNR=',num2str(RSNR5), 'dB'])
0244 figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray;
0245 title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB'])
0246 
0247 figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray;
0248 title(['TV, SNR=',num2str(RSNR7), 'dB'])
0249 figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray;
0250 title(['RW-TV, SNR=',num2str(RSNR8), 'dB'])
0251 
0252 
0253 
0254 
0255 
0256 
0257 
0258 
0259 
0260 
0261

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/Experiment3.html.svn-base000066400000000000000000000304561277570055300253540ustar00rootroot00000000000000 Description of Experiment3
Home > matlab > Experiment3.m

Experiment3

PURPOSE ^

% Experiement3

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiement3
 In this experiment we illustrate the application of SARA to Fourier 
 imaging. We reconstruct a 224x168 positive brain image from standard 
 variable density sampling. Fourier measurements, for an undersampling 
 ratio of M = 0.05N and input SNR set to 30 dB.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiement3
0002 % In this experiment we illustrate the application of SARA to Fourier
0003 % imaging. We reconstruct a 224x168 positive brain image from standard
0004 % variable density sampling. Fourier measurements, for an undersampling
0005 % ratio of M = 0.05N and input SNR set to 30 dB.
0006 
0007 
0008 %% Clear workspace
0009 
0010 clc
0011 clear;
0012 
0013 
0014 %% Define paths
0015 
0016 addpath misc/
0017 addpath prox_operators/
0018 addpath test_images/
0019 
0020 
0021 %% Read image
0022 
0023 % Load image
0024 load Brain_low_res
0025 im=abs(map_ref);
0026 
0027 % Normalise
0028 im = im/max(max(im));
0029 
0030 % Enforce positivity
0031 im(im<0) = 0;
0032 
0033 %% Parameters
0034 
0035 input_snr = 30; % Noise level (on the measurements)
0036 
0037 %Undersampling ratio M/N
0038 %The range of p is 0 < p <= 0.5 since the vdsmask
0039 %function samples only half plane. Therefore, full
0040 %sampling is p = 0.5
0041 p=0.05;
0042 
0043 
0044 %% Sparsity operators
0045 
0046 %Wavelet decomposition depth
0047 nlevel=4;
0048 
0049 dwtmode('per');
0050 [C,S]=wavedec2(im,nlevel,'db8'); 
0051 ncoef=length(C);
0052 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0053 ncoef1=length(C1);
0054 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0055 ncoef2=length(C2);
0056 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0057 ncoef3=length(C3);
0058 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0059 ncoef4=length(C4);
0060 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0061 ncoef5=length(C5);
0062 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0063 ncoef6=length(C6);
0064 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0065 ncoef7=length(C7);
0066 
0067 %Sparsity averaging operator
0068 
0069 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0070     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0071     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0072 
0073 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0074     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0075     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0076     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0080 
0081 %Db8 wavelet basis
0082 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0083 Psi2 = @(x) waverec2(x,S,'db8');
0084 
0085 
0086 % Variable density mask
0087 mask = sopt_mltb_vdsmask(size(im,1),size(im,2),p);
0088 ind = find(mask==1);
0089 % Masking matrix (sparse matrix in matlab)
0090 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0091 
0092   
0093 % Composition (Masking o Fourier)
0094     
0095 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0096 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0097       
0098 % Select p% of Fourier coefficients
0099 y = A(im);
0100 % Add Gaussian i.i.d. noise
0101 sigma_noise = 10^(-input_snr/20)*std(im(:));
0102 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0103 
0104 
0105 % Tolerance on noise
0106 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0107 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0108 
0109 
0110 %% Parameters for BPDN
0111 param.verbose = 1; % Print log or not
0112 param.gamma = 1e-1; % Converge parameter
0113 param.rel_obj = 4e-4; % Stopping criterion for the L1 problem
0114 param.max_iter = 200; % Max. number of iterations for the L1 problem
0115 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0116 param.nu_B2 = 1; % Bound on the norm of the operator A
0117 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0118 param.pos_B2 = 1;  % Positivity constraint flag. (1) active (0) otherwise
0119 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0120 param.nu_L1 = 1;
0121 param.max_iter_L1 = 20;
0122 param.rel_obj_L1 = 1e-2;
0123     
0124 % Solve SARA
0125 maxiter=10;
0126 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*9));
0127 tol=1e-3;
0128 sol1 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter);
0129     
0130 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0131     
0132     
0133 %% Parameters for TVDN
0134 param1.verbose = 1; % Print log or not
0135 param1.gamma = 3e-1; % Converge parameter
0136 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0137 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0138 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0139 param1.nu_B2 = 1; % Bound on the norm of the operator A
0140 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0141 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0142 param1.max_iter_B2 = 200;
0143 param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0144 
0145 % Solve TVDN problem
0146 sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0147 
0148 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0149    
0150     
0151 % Solve BPDN problem
0152 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0153 
0154 
0155 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0156 
0157 figure, imagesc(sol1,[0 1]);axis image;axis off; colormap gray;
0158 title(['SARA, SNR=',num2str(RSNR1), 'dB'])
0159 figure, imagesc(sol2,[0 1]);axis image;axis off; colormap gray;
0160 title(['TV, SNR=',num2str(RSNR2), 'dB'])
0161 figure, imagesc(sol3,[0 1]);axis image;axis off; colormap gray;
0162 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0163 figure, imagesc(im, [0 1]); axis image; axis off; colormap gray;
0164 title('Original image')
0165     
0166     
0167     
0168     
0169     
0170     
0171     
0172 
0173 
0174 
0175 
0176 
0177 
0178 
0179 
0180 
0181 
0182 
0183

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/index.html.svn-base000066400000000000000000000073541277570055300242610ustar00rootroot00000000000000 Index for Directory matlab
< Master index Index for matlab >

Index for matlab

Matlab files in this directory:

 Example_BPDN% Example_BPDN
 Example_TVDN% Example_TVDN
 Example_TVDN2% Example_TVDN2
 Example_TVDNoA% Example TVDNoA
 Example_weighted_BPDN% Exampled_weighted_L1
 Example_weighted_TVDN% Exampled_weighted_TVDN
 Experiment1% Experiment1
 Experiment2% Experiment2
 Experiment3% Experiement3
 sopt_mltb_solve_BPDNsopt_mltb_solve_BPDN - Solve BPDN problem
 sopt_mltb_solve_L2DNsopt_mltb_solve_L2DN - Solve L2DN problem.
 sopt_mltb_solve_TVDNsopt_mltb_solve_TVDN - Solve TVDN problem
 sopt_mltb_solve_TVDNoAsopt_mltb_solve_TVDNoA - Solve augmented TVDN problem
 sopt_mltb_solve_rwBPDNsopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem
 sopt_mltb_solve_rwTVDNsopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

Subsequent directories:


Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_BPDN.html.svn-base000066400000000000000000000411461277570055300271650ustar00rootroot00000000000000 Description of sopt_mltb_solve_BPDN
Home > matlab > sopt_mltb_solve_BPDN.m

sopt_mltb_solve_BPDN

PURPOSE ^

sopt_mltb_solve_BPDN - Solve BPDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param)

DESCRIPTION ^

 sopt_mltb_solve_BPDN - Solve BPDN problem

 Solve the Basis Pursuit Denoising (BPDN) problem

   min ||Psit x||_1   s.t.  ||y-A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator, Psit is a sparfying transform and
 Psi its adjoint. The structure param should contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of L1 norm when solving for
       L1 proximal operator) (default = 1e-1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - rel_obj_L1: Used as stopping criterion for the proximal L1
       operator. Minimum relative change of the objective value between
       two successive estimates.

   - max_iter_L1: Used as stopping criterion for the proximal L1
       operator. Maximun number of iterations.
 
   - param.nu_L1: Bound on the norm^2 of the operator Psi, i.e.
       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
 
   - param.tight_L1: 1 if Psit is a tight frame, 0 otherwise 
       (default = 1).
 
   - param.weights: Weights for a weighted L1-norm defined
       by sum_i{weights_i.*abs(x_i)} (default = 1). 

   - pos_l1: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

 References:
 [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting 
 Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
 of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param)
0002 % sopt_mltb_solve_BPDN - Solve BPDN problem
0003 %
0004 % Solve the Basis Pursuit Denoising (BPDN) problem
0005 %
0006 %   min ||Psit x||_1   s.t.  ||y-A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator, Psit is a sparfying transform and
0010 % Psi its adjoint. The structure param should contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of L1 norm when solving for
0025 %       L1 proximal operator) (default = 1e-1).
0026 %
0027 %   - initsol: Initial solution for a warmstart.
0028 %
0029 %   Projection onto the L2-ball:
0030 %
0031 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0032 %
0033 %   - nu_B2: Bound on the norm of the operator A, i.e.
0034 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0035 %
0036 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0037 %       stops if
0038 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0039 %       (default = 1e-3).
0040 %
0041 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0042 %       L2 ball (default = 200).
0043 %
0044 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0045 %       default = 0).
0046 %
0047 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   Proximal L1 operator:
0051 %
0052 %   - rel_obj_L1: Used as stopping criterion for the proximal L1
0053 %       operator. Minimum relative change of the objective value between
0054 %       two successive estimates.
0055 %
0056 %   - max_iter_L1: Used as stopping criterion for the proximal L1
0057 %       operator. Maximun number of iterations.
0058 %
0059 %   - param.nu_L1: Bound on the norm^2 of the operator Psi, i.e.
0060 %       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
0061 %
0062 %   - param.tight_L1: 1 if Psit is a tight frame, 0 otherwise
0063 %       (default = 1).
0064 %
0065 %   - param.weights: Weights for a weighted L1-norm defined
0066 %       by sum_i{weights_i.*abs(x_i)} (default = 1).
0067 %
0068 %   - pos_l1: Positivity flag (1 to impose positivity, 0 otherwise;
0069 %       default = 0).
0070 %
0071 % References:
0072 % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting
0073 % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
0074 % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0075 
0076 % Optional input arguments
0077 if ~isfield(param, 'verbose'), param.verbose = 1; end
0078 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0079 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0080 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0081 if ~isfield(param, 'pos_l1'), param.pos_l1 = 0; end
0082 
0083 % Input arguments for projection onto the L2 ball
0084 param_B2.A = A; param_B2.At = At;
0085 param_B2.y = y; param_B2.epsilon = epsilon;
0086 param_B2.verbose = param.verbose;
0087 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0088 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0089 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0090 if isfield(param, 'max_iter_B2')
0091     param_B2.max_iter = param.max_iter_B2;
0092 end
0093 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0094 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0095 
0096 % Input arguments for prox L1
0097 param_L1.Psi = Psi; param_L1.Psit = Psit; param_L1.pos = param.pos_l1;
0098 param_L1.verbose = param.verbose; 
0099 %param_L1.verbose = 2;
0100 param_L1.rel_obj = param.rel_obj;
0101 if isfield(param, 'nu_L1')
0102     param_L1.nu = param.nu_L1;
0103 end
0104 if isfield(param, 'tight_L1')
0105     param_L1.tight = param.tight_L1;
0106 end
0107 if isfield(param, 'max_iter_L1')
0108     param_L1.max_iter = param.max_iter_L1;
0109 end
0110 if isfield(param, 'rel_obj_L1')
0111     param_L1.rel_obj = param.rel_obj_L1;
0112 end
0113 if isfield(param, 'weights')
0114     param_L1.weights = param.weights;
0115 else
0116     param_L1.weights = 1;
0117 end
0118 
0119 % Initialization
0120 if isfield(param,'initsol')
0121     xhat = param.initsol;
0122 else
0123     xhat = At(y); 
0124 end
0125 
0126 iter = 1; prev_norm = 0;
0127 
0128 % Main loop
0129 while 1
0130     
0131     if param.verbose >= 1
0132         fprintf('Iteration %i:\n', iter);
0133     end
0134     
0135     % Projection onto the L2-ball
0136     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0137     
0138     % Global stopping criterion
0139     dummy = Psit(sol);
0140     curr_norm = sum(param_L1.weights(:).*abs(dummy(:)));    
0141     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0142     if param.verbose >= 1
0143         fprintf('  ||x||_1 = %e, rel_norm = %e\n', ...
0144             curr_norm, rel_norm);
0145     end
0146     if (rel_norm < param.rel_obj)
0147         crit_BPDN = 'REL_NORM';
0148         break;
0149     elseif iter >= param.max_iter
0150         crit_BPDN = 'MAX_IT';
0151         break;
0152     end
0153     
0154     % Proximal L1 operator
0155     xhat = 2*sol - xhat;
0156     temp = sopt_mltb_prox_L1(xhat, param.gamma, param_L1);
0157     xhat = temp + sol - xhat;
0158     
0159     % Update variables
0160     iter = iter + 1;
0161     prev_norm = curr_norm;
0162     
0163 end
0164 
0165 % Log
0166 if param.verbose >= 1
0167   
0168     % L1 norm
0169     fprintf('\n Solution found:\n');
0170     fprintf(' Final L1 norm: %e\n', curr_norm);
0171     
0172     % Residual
0173     dummy = A(sol); res = norm(y(:)-dummy(:), 2);
0174     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res);
0175     
0176     % Stopping criterion
0177     fprintf(' %i iterations\n', iter);
0178     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0179     
0180 end
0181 
0182 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_L2DN.html.svn-base000066400000000000000000000314111277570055300271330ustar00rootroot00000000000000 Description of sopt_mltb_solve_L2DN
Home > matlab > sopt_mltb_solve_L2DN.m

sopt_mltb_solve_L2DN

PURPOSE ^

sopt_mltb_solve_L2DN - Solve L2DN problem.

SYNOPSIS ^

function sol = sopt_mltb_solve_L2DN(y, epsilon, A, At, param)

DESCRIPTION ^

 sopt_mltb_solve_L2DN - Solve L2DN problem.

 Solve the L2 denoising problem

   min ||x||_2   s.t.  ||y-A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator. The structure param should 
 contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_2 - ||x(t-1)||_2 | / ||x(t)||_2 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of L1 norm when solving for
       L1 proximal operator) (default = 1e-1).

   - param.weights: weightsfor a weighted L2-norm defined
       by norm(weights_i.*x_i,2) (default = 1).

   - initsol: Initial solution for a warmstart.

   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).

 References:
 [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting 
 Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
 of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_L2DN(y, epsilon, A, At, param)
0002 % sopt_mltb_solve_L2DN - Solve L2DN problem.
0003 %
0004 % Solve the L2 denoising problem
0005 %
0006 %   min ||x||_2   s.t.  ||y-A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator. The structure param should
0010 % contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_2 - ||x(t-1)||_2 | / ||x(t)||_2 < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of L1 norm when solving for
0025 %       L1 proximal operator) (default = 1e-1).
0026 %
0027 %   - param.weights: weightsfor a weighted L2-norm defined
0028 %       by norm(weights_i.*x_i,2) (default = 1).
0029 %
0030 %   - initsol: Initial solution for a warmstart.
0031 %
0032 %   Projection onto the L2-ball:
0033 %
0034 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0035 %
0036 %   - nu_B2: Bound on the norm of the operator A, i.e.
0037 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0038 %
0039 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0040 %       stops if
0041 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0042 %       (default = 1e-3).
0043 %
0044 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0045 %       L2 ball (default = 200).
0046 %
0047 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0051 %       default = 0).
0052 %
0053 % References:
0054 % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting
0055 % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
0056 % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0057 
0058 % Optional input arguments
0059 if ~isfield(param, 'verbose'), param.verbose = 1; end
0060 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0061 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0062 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0063 if ~isfield(param, 'weights'), param.weights = 1; end
0064 
0065 % Input arguments for projection onto the L2 ball
0066 param_B2.A = A; param_B2.At = At;
0067 param_B2.y = y; param_B2.epsilon = epsilon;
0068 param_B2.verbose = param.verbose;
0069 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0070 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0071 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0072 if isfield(param, 'max_iter_B2')
0073     param_B2.max_iter = param.max_iter_B2;
0074 end
0075 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0076 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0077 
0078 % Initialization
0079 if isfield(param,'initsol')
0080     xhat = param.initsol;
0081 else
0082     xhat = At(y); 
0083 end
0084 
0085 iter = 1; prev_norm = 0;
0086 
0087 % Main loop
0088 while 1
0089     
0090     %
0091     if param.verbose >= 1
0092         fprintf('Iteration %i:\n', iter);
0093     end
0094     
0095     % Projection onto the L2-ball
0096     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0097     
0098     % Global stopping criterion
0099     dummy = sol;
0100     curr_norm = norm(param.weights(:).*dummy(:));    
0101     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0102     if param.verbose >= 1
0103         fprintf('  ||x||_1 = %e, rel_norm = %e\n', ...
0104             curr_norm, rel_norm);
0105     end
0106     if (rel_norm < param.rel_obj)
0107         crit_BPDN = 'REL_NORM';
0108         break;
0109     elseif iter >= param.max_iter
0110         crit_BPDN = 'MAX_IT';
0111         break;
0112     end
0113     
0114     % Proximal L2 operator
0115     xhat = 2*sol - xhat;   
0116     temp = xhat ./ (1 + 2*param.weights);    
0117     xhat = temp + sol - xhat;
0118     
0119     % Update variables
0120     iter = iter + 1;
0121     prev_norm = curr_norm;
0122     
0123 end
0124 
0125 % Log
0126 if param.verbose >= 1
0127   
0128     % L1 norm
0129     fprintf('\n Solution found:\n');
0130     fprintf(' Final L1 norm: %e\n', curr_norm);
0131     
0132     % Residual
0133     dummy = A(sol); res = norm(y(:)-dummy(:), 2);
0134     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res);
0135     
0136     % Stopping criterion
0137     fprintf(' %i iterations\n', iter);
0138     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0139     
0140 end
0141 
0142 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_TVDN.html.svn-base000066400000000000000000000330451277570055300272140ustar00rootroot00000000000000 Description of sopt_mltb_solve_TVDN
Home > matlab > sopt_mltb_solve_TVDN.m

sopt_mltb_solve_TVDN

PURPOSE ^

sopt_mltb_solve_TVDN - Solve TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param)

DESCRIPTION ^

 sopt_mltb_solve_TVDN - Solve TVDN problem

 Solve the total variation denoising (TVDN) problem

   min ||x||_TV   s.t.  ||y - A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator. The structure param should
 contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of TV norm when solving for
       TV proximal operator) (default = 1e-1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - max_iter_TV: Used as stopping criterion for the proximal TV
       operator. Maximun number of iterations (default = 200).

 References:
 P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
 to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
 Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param)
0002 % sopt_mltb_solve_TVDN - Solve TVDN problem
0003 %
0004 % Solve the total variation denoising (TVDN) problem
0005 %
0006 %   min ||x||_TV   s.t.  ||y - A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator. The structure param should
0010 % contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of TV norm when solving for
0025 %       TV proximal operator) (default = 1e-1).
0026 %
0027 %   - initsol: Initial solution for a warmstart.
0028 %
0029 %   Projection onto the L2-ball:
0030 %
0031 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0032 %
0033 %   - nu_B2: Bound on the norm of the operator A, i.e.
0034 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0035 %
0036 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0037 %       stops if
0038 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0039 %       (default = 1e-3).
0040 %
0041 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0042 %       L2 ball (default = 200).
0043 %
0044 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0045 %       default = 0).
0046 %
0047 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   Proximal L1 operator:
0051 %
0052 %   - max_iter_TV: Used as stopping criterion for the proximal TV
0053 %       operator. Maximun number of iterations (default = 200).
0054 %
0055 % References:
0056 % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
0057 % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
0058 % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0059 
0060 % Optional input arguments
0061 if ~isfield(param, 'verbose'), param.verbose = 1; end
0062 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0063 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0064 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0065 
0066 % Input arguments for projection onto the L2 ball
0067 param_B2.A = A; param_B2.At = At;
0068 param_B2.y = y; param_B2.epsilon = epsilon;
0069 param_B2.verbose = param.verbose;
0070 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0071 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0072 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0073 if isfield(param, 'max_iter_B2')
0074     param_B2.max_iter = param.max_iter_B2;
0075 end
0076 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0077 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0078 
0079 % Input arguments for prox TV
0080 param_TV.verbose = param.verbose; param_TV.rel_obj = param.rel_obj;
0081 if isfield(param, 'max_iter_TV')
0082     param_TV.max_iter= param.max_iter_TV;
0083 end
0084 
0085 % Initialization
0086 if isfield(param,'initsol')
0087     xhat = param.initsol;
0088 else
0089     xhat = At(y); 
0090 end 
0091 
0092 iter = 1; prev_norm = 0;
0093 
0094 % Main loop
0095 while 1
0096     
0097     if param.verbose>=1
0098         fprintf('Iteration %i:\n', iter);
0099     end
0100     
0101     % Projection onto the L2-ball
0102     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0103     
0104     % Global stopping criterion
0105     curr_norm = sopt_mltb_TV_norm(sol, 0);
0106     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0107     if param.verbose >= 1
0108         fprintf('  ||x||_TV = %e, rel_norm = %e\n', ...
0109             curr_norm, rel_norm);
0110     end
0111     if (rel_norm < param.rel_obj)
0112         crit_BPDN = 'REL_NORM';
0113         break;
0114     elseif iter >= param.max_iter
0115         crit_BPDN = 'MAX_IT';
0116         break;
0117     end
0118     
0119     % Proximal L1 operator
0120     xhat = 2*sol - xhat;
0121     temp = sopt_mltb_prox_TV(xhat, param.gamma, param_TV);
0122     xhat = temp + sol - xhat;
0123     
0124     % Update variables
0125     iter = iter + 1;
0126     prev_norm = curr_norm;
0127     
0128 end
0129 
0130 % Log
0131 if param.verbose >= 1
0132   
0133     % L1 norm
0134     fprintf('\n Solution found:\n');
0135     fprintf(' Final TV norm: %e\n', curr_norm);
0136     
0137     % Residual
0138     temp = A(sol);
0139     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ...
0140         norm(y(:)-temp(:)));
0141     
0142     % Stopping criterion
0143     fprintf(' %i iterations\n', iter);
0144     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0145     
0146 end
0147 
0148 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_TVDNoA.html.svn-base000066400000000000000000000411271277570055300274740ustar00rootroot00000000000000 Description of sopt_mltb_solve_TVDNoA
Home > matlab > sopt_mltb_solve_TVDNoA.m

sopt_mltb_solve_TVDNoA

PURPOSE ^

sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, S, St, param)

DESCRIPTION ^

 sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem

 Solve the total variation denoising (TVDN) problem when an additional 
 linear operator S is incorporated in the TV norm, i.e. solve

   min ||S x||_TV   s.t.  ||y - A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator, S is the operator appearing in
 the TV norm and St the associated adjoint operator.  The structure param 
 should contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of TV norm when solving for
       TV proximal operator) (default = 1e-1).
 
   - nu_TV: Bound on the norm of the operator S, i.e.
       ||S x||^2 <= nu * ||x||^2 (default = 1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - max_iter_TV: Used as stopping criterion for the proximal TV
       operator. Maximun number of iterations (default = 200).

   - param.weights_dx_TV: Weights for a weighted TV-norm in the x
       direction (default = 1).

   - param.weights_dy_TV: Weights for a weighted TV-norm in the y
       direction (default = 1).

 References:
 P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach 
 to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of 
 Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, S, St, param)
0002 % sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem
0003 %
0004 % Solve the total variation denoising (TVDN) problem when an additional
0005 % linear operator S is incorporated in the TV norm, i.e. solve
0006 %
0007 %   min ||S x||_TV   s.t.  ||y - A x||_2 < epsilon
0008 %
0009 % where y contains the measurements, A is the forward measurement operator
0010 % and At the associated adjoint operator, S is the operator appearing in
0011 % the TV norm and St the associated adjoint operator.  The structure param
0012 % should contain the following fields:
0013 %
0014 %   General parameters:
0015 %
0016 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0017 %       2 = print main steps; default = 1).
0018 %
0019 %   - max_iter: Maximum number of iterations (default = 200).
0020 %
0021 %   - rel_obj: Minimum relative change of the objective value
0022 %       (default = 1e-4).  The algorithm stops if
0023 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0024 %       where x(t) is the estimate of the solution at iteration t.
0025 %
0026 %   - gamma: Convergence speed (weighting of TV norm when solving for
0027 %       TV proximal operator) (default = 1e-1).
0028 %
0029 %   - nu_TV: Bound on the norm of the operator S, i.e.
0030 %       ||S x||^2 <= nu * ||x||^2 (default = 1).
0031 %
0032 %   - initsol: Initial solution for a warmstart.
0033 %
0034 %   Projection onto the L2-ball:
0035 %
0036 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0037 %
0038 %   - nu_B2: Bound on the norm of the operator A, i.e.
0039 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0040 %
0041 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0042 %       stops if
0043 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0044 %       (default = 1e-3).
0045 %
0046 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0047 %       L2 ball (default = 200).
0048 %
0049 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0050 %       default = 0).
0051 %
0052 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0053 %       default = 0).
0054 %
0055 %   Proximal L1 operator:
0056 %
0057 %   - max_iter_TV: Used as stopping criterion for the proximal TV
0058 %       operator. Maximun number of iterations (default = 200).
0059 %
0060 %   - param.weights_dx_TV: Weights for a weighted TV-norm in the x
0061 %       direction (default = 1).
0062 %
0063 %   - param.weights_dy_TV: Weights for a weighted TV-norm in the y
0064 %       direction (default = 1).
0065 %
0066 % References:
0067 % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
0068 % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
0069 % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0070 
0071 % Optional input arguments
0072 if ~isfield(param, 'verbose'), param.verbose = 1; end
0073 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0074 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0075 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0076 if ~isfield(param, 'weights_dx_TV'), param.weights_dx_TV = 1.0; end
0077 if ~isfield(param, 'weights_dy_TV'), param.weights_dy_TV = 1.0; end
0078 if ~isfield(param, 'incNP'), param.incNP = false; end
0079 if ~isfield(param, 'sphere_flag'), param.sphere_flag = false; end
0080 
0081 % Input arguments for projection onto the L2 ball
0082 param_B2.A = A; param_B2.At = At;
0083 param_B2.y = y; param_B2.epsilon = epsilon;
0084 param_B2.verbose = param.verbose;
0085 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0086 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0087 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0088 if isfield(param, 'max_iter_B2')
0089     param_B2.max_iter = param.max_iter_B2;
0090 end
0091 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0092 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0093 
0094 % Input arguments for prox TVoA
0095 param_TV.A = S; param_TV.At = St;
0096 param_TV.verbose = param.verbose; 
0097 param_TV.rel_obj = param.rel_obj;
0098 param_TV.weights_dx = param.weights_dx_TV;
0099 param_TV.weights_dy = param.weights_dy_TV;
0100 if isfield(param, 'nu_TV')
0101    param_TV.nu = param.nu_TV; 
0102 end
0103 if isfield(param, 'max_iter_TV')
0104     param_TV.max_iter= param.max_iter_TV;
0105 end
0106 if isfield(param, 'zero_weights_flag_TV')
0107    param_TV.zero_weights_flag = param.zero_weights_flag_TV; 
0108 end
0109 if isfield(param, 'identical_weights_flag_TV'), 
0110    param_TV.identical_weights_flag = param.identical_weights_flag_TV;
0111 end
0112 if isfield(param, 'sphere_flag'), 
0113    param_TV.sphere_flag = param.sphere_flag;
0114    param_TV.incNP = param.incNP;
0115 end
0116 
0117 
0118 % Initialization
0119 if isfield(param,'initsol')
0120     xhat = param.initsol;
0121 else
0122     xhat = At(y); 
0123 end
0124 
0125 iter = 1; prev_norm = 0;
0126 
0127 % Main loop
0128 while 1
0129     
0130     %
0131     if param.verbose>=1
0132         fprintf('Iteration %i:\n', iter);
0133     end
0134     
0135     % Projection onto the L2-ball
0136     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);    
0137     
0138     % Global stopping criterion
0139     curr_norm = sopt_mltb_TV_norm(S(sol), param_TV.sphere_flag, param_TV.incNP, param_TV.weights_dx, param_TV.weights_dy);
0140     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0141     if param.verbose >= 1
0142         fprintf('  ||x||_TV = %e, rel_norm = %e\n', ...
0143             curr_norm, rel_norm);
0144     end
0145     if (rel_norm < param.rel_obj)
0146         crit_BPDN = 'REL_NORM';
0147         break;
0148     elseif iter >= param.max_iter
0149         crit_BPDN = 'MAX_IT';
0150         break;
0151     end
0152     
0153     % Proximal L1 operator
0154     xhat = 2*sol - xhat;
0155     temp = sopt_mltb_prox_TVoA(xhat, param.gamma, param_TV);
0156     xhat = temp + sol - xhat;
0157     
0158     % Update variables
0159     iter = iter + 1;
0160     prev_norm = curr_norm;
0161     
0162 end
0163 
0164 % Log
0165 if param.verbose>=1
0166     % L1 norm
0167     fprintf('\n Solution found:\n');
0168     fprintf(' Final TV norm: %e\n', curr_norm);
0169     
0170     % Residual
0171     temp = A(sol);
0172     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ...
0173         norm(y(:)-temp(:)));
0174     
0175     % Stopping criterion
0176     fprintf(' %i iterations\n', iter);
0177     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0178     
0179 end
0180 
0181 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_rwBPDN.html.svn-base000066400000000000000000000224301277570055300275310ustar00rootroot00000000000000 Description of sopt_mltb_solve_rwBPDN
Home > matlab > sopt_mltb_solve_rwBPDN.m

sopt_mltb_solve_rwBPDN

PURPOSE ^

sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit,paramT, sigma, tol, maxiter, initsol)

DESCRIPTION ^

 sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem

 Solve the reweighted L1 minimization function using an homotopy
 continuation method to approximate the L0 norm.  At each iteration the 
 following problem is solved:

   min_x ||W Psit x||_1   s.t.  ||y-A x||_2 < epsilon

 where W is a diagonal matrix with diagonal elements given by

   [W]_ii = delta(t)/(delta(t)+|[Psit x(t)]_i|).

 The input parameters are defined as follows.

   - y: Input data (measurements).

   - epsilon: Noise bound.

   - A: Forward measurement operator.

   - At: Adjoint measurement operator.

   - Psi: Synthesis sparsity transform.

   - Psit: Analysis sparsity transform.

   - paramT: Structure containing parameters for the L1 solver (see 
       documentation for sopt_mltb_solve_BPDN).  

   - sigma: Noise standard deviation in the analysis domain.

   - tol: Minimum relative change in the solution.
       The algorithm stops if 
           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
       where x(t) is the estimate of the solution at iteration t.

   - maxiter: Maximum number of iterations of the reweighted algorithm.

   - initsol: Initial solution for a warmstart.

 References:
 [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and 
 Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc. 
 Let., in press, 2013.
 [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging 
 Reweighted Analysis (SARA): a novel algorithm for radio-interferometric 
 imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, ...
0002   paramT, sigma, tol, maxiter, initsol)
0003 % sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem
0004 %
0005 % Solve the reweighted L1 minimization function using an homotopy
0006 % continuation method to approximate the L0 norm.  At each iteration the
0007 % following problem is solved:
0008 %
0009 %   min_x ||W Psit x||_1   s.t.  ||y-A x||_2 < epsilon
0010 %
0011 % where W is a diagonal matrix with diagonal elements given by
0012 %
0013 %   [W]_ii = delta(t)/(delta(t)+|[Psit x(t)]_i|).
0014 %
0015 % The input parameters are defined as follows.
0016 %
0017 %   - y: Input data (measurements).
0018 %
0019 %   - epsilon: Noise bound.
0020 %
0021 %   - A: Forward measurement operator.
0022 %
0023 %   - At: Adjoint measurement operator.
0024 %
0025 %   - Psi: Synthesis sparsity transform.
0026 %
0027 %   - Psit: Analysis sparsity transform.
0028 %
0029 %   - paramT: Structure containing parameters for the L1 solver (see
0030 %       documentation for sopt_mltb_solve_BPDN).
0031 %
0032 %   - sigma: Noise standard deviation in the analysis domain.
0033 %
0034 %   - tol: Minimum relative change in the solution.
0035 %       The algorithm stops if
0036 %           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
0037 %       where x(t) is the estimate of the solution at iteration t.
0038 %
0039 %   - maxiter: Maximum number of iterations of the reweighted algorithm.
0040 %
0041 %   - initsol: Initial solution for a warmstart.
0042 %
0043 % References:
0044 % [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and
0045 % Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc.
0046 % Let., in press, 2013.
0047 % [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging
0048 % Reweighted Analysis (SARA): a novel algorithm for radio-interferometric
0049 % imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.
0050 
0051 param=paramT;
0052 iter=0;
0053 rel_dist=1;
0054 
0055 if nargin<11
0056     fprintf('RW iteration: %i\n', iter);
0057     sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0058 else
0059     sol = initsol;
0060 end
0061 
0062 temp=Psit(sol);
0063 delta=std(temp(:));
0064 
0065 while (rel_dist>tol && iter<maxiter)
0066   
0067     iter=iter+1;
0068     delta=max(sigma/10,delta);
0069     fprintf('RW iteration: %i\n', iter);
0070     fprintf('delta = %e\n', delta);
0071     
0072     % Weights
0073     weights=abs(Psit(sol));
0074     param.weights=delta./(delta+weights);
0075     
0076     % Warm start
0077     param.initsol=sol;
0078     param.gamma=1e-1*max(weights(:));
0079     sol1=sol;
0080     
0081     % Weighted L1 problem
0082     sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0083     
0084     % Relative distance
0085     rel_dist=norm(sol(:)-sol1(:))/norm(sol1(:));
0086     fprintf('Relative distance = %e\n\n', rel_dist);
0087     delta = delta/10;
0088     
0089 end
0090

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/.svn/text-base/sopt_mltb_solve_rwTVDN.html.svn-base000066400000000000000000000217451277570055300275710ustar00rootroot00000000000000 Description of sopt_mltb_solve_rwTVDN
Home > matlab > sopt_mltb_solve_rwTVDN.m

sopt_mltb_solve_rwTVDN

PURPOSE ^

sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, paramT,sigma, tol, maxiter, initsol)

DESCRIPTION ^

 sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

 Solve the reweighted TV minimization function using an homotopy
 continuation method to approximate the L0 norm of the magnitude of the 
 gradient.  At each iteration the following problem is solved:

   min_x ||W x||_TV   s.t.  ||y-A x||_2 < epsilon

 where W is a diagonal matrix with diagonal elements given by esentially
 the inverse of the graident.
   
 The input parameters are defined as follows.

   - y: Input data (measurements).

   - epsilon: Noise bound.

   - A: Forward measurement operator.

   - At: Adjoint measurement operator.

   - paramT: Structure containing parameters for the TV solver (see 
       documentation for sopt_mltb_solve_TVDN).  

   - sigma: Noise standard deviation in the analysis domain.

   - tol: Minimum relative change in the solution.
       The algorithm stops if 
           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
       where x(t) is the estimate of the solution at iteration t.

   - maxiter: Maximum number of iterations of the reweighted algorithm.

   - initsol: Initial solution for a warmstart.

 References:
 [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and 
 Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc. 
 Let., in press, 2013.
 [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging 
 Reweighted Analysis (SARA): a novel algorithm for radio-interferometric 
 imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, paramT, ...
0002   sigma, tol, maxiter, initsol)
0003 % sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem
0004 %
0005 % Solve the reweighted TV minimization function using an homotopy
0006 % continuation method to approximate the L0 norm of the magnitude of the
0007 % gradient.  At each iteration the following problem is solved:
0008 %
0009 %   min_x ||W x||_TV   s.t.  ||y-A x||_2 < epsilon
0010 %
0011 % where W is a diagonal matrix with diagonal elements given by esentially
0012 % the inverse of the graident.
0013 %
0014 % The input parameters are defined as follows.
0015 %
0016 %   - y: Input data (measurements).
0017 %
0018 %   - epsilon: Noise bound.
0019 %
0020 %   - A: Forward measurement operator.
0021 %
0022 %   - At: Adjoint measurement operator.
0023 %
0024 %   - paramT: Structure containing parameters for the TV solver (see
0025 %       documentation for sopt_mltb_solve_TVDN).
0026 %
0027 %   - sigma: Noise standard deviation in the analysis domain.
0028 %
0029 %   - tol: Minimum relative change in the solution.
0030 %       The algorithm stops if
0031 %           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
0032 %       where x(t) is the estimate of the solution at iteration t.
0033 %
0034 %   - maxiter: Maximum number of iterations of the reweighted algorithm.
0035 %
0036 %   - initsol: Initial solution for a warmstart.
0037 %
0038 % References:
0039 % [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and
0040 % Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc.
0041 % Let., in press, 2013.
0042 % [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging
0043 % Reweighted Analysis (SARA): a novel algorithm for radio-interferometric
0044 % imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.
0045 
0046 Psit = @(x) x; Psi=@(x) x;
0047 
0048 param=paramT;
0049 iter=0;
0050 rel_dist=1;
0051 
0052 if nargin<9
0053     fprintf('RW iteration: %i\n', iter);
0054     sol = sopt_mltb_solve_TVoA_B2(y, epsilon, A, At, Psi, Psit, param);
0055 else
0056     sol = initsol;
0057 end
0058 
0059 
0060 delta=std(sol(:));
0061 
0062 while (rel_dist>tol && iter<maxiter)
0063   
0064     iter=iter+1;
0065     delta=max(sigma/10,delta);
0066     fprintf('RW iteration: %i\n', iter);
0067     fprintf('delta = %e\n', delta);
0068     
0069     %Warm start
0070     param.initsol=sol;
0071     sol1=sol;
0072     
0073     % Weights
0074     [param.weights_dx_TV param.weights_dy_TV] = sopt_mltb_gradient_op(real(sol));
0075     param.weights_dx_TV = delta./(abs(param.weights_dx_TV)+delta);
0076     param.weights_dy_TV = delta./(abs(param.weights_dy_TV)+delta);
0077     param.identical_weights_flag_TV = 0;
0078     param.gamma=1e-1*max(abs(sol1(:)));
0079     
0080     %Weighted TV problem
0081     sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0082 
0083     %Relative distance
0084     rel_dist=norm(sol(:)-sol1(:))/norm(sol1(:)); 
0085     fprintf('relative distance = %e\n\n', rel_dist);
0086     delta = delta/10;
0087     
0088 end
0089

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_BPDN.html000066400000000000000000000210721277570055300210440ustar00rootroot00000000000000 Description of Example_BPDN
Home > matlab > Example_BPDN.m

Example_BPDN

PURPOSE ^

% Example_BPDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_BPDN
 Example to demonstrate use of BPDN solver.  A random Fourier sampling
 measurement operator is considered.  Daubechies 8 wavelets are used for
 the sparsifying operator.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_BPDN
0002 % Example to demonstrate use of BPDN solver.  A random Fourier sampling
0003 % measurement operator is considered.  Daubechies 8 wavelets are used for
0004 % the sparsifying operator.
0005 
0006 
0007 %% Clear workspace
0008 
0009 clc
0010 clear;
0011 
0012 
0013 %% Define paths
0014 
0015 addpath misc/
0016 addpath prox_operators/
0017 
0018 
0019 %% Define parameters
0020 
0021 % Coverages (half the plane for Fourier sampling)
0022 p = [0.50];
0023 
0024 % Noise level (on the measurements)
0025 input_snr = 30;
0026 
0027 
0028 %% Read image
0029 
0030 % Load image
0031 im = im2double(imread('cameraman.tif'));
0032 
0033 % Normalise
0034 im = im/max(max(im));
0035 
0036 % Enforce positivity
0037 im(im<0) = 0;
0038 
0039 
0040 %% Define sparsity operator
0041 
0042 dwtmode('per');
0043 
0044 % Decomposition level of the wavelet transform.
0045 nlevel = 4;
0046 
0047 % Daubechies 8 wavelet operator
0048 [C,S] = wavedec2(im,nlevel,'db8');
0049 
0050 Psit = @(x) wavedec2(x, nlevel, 'db8');
0051 Psi = @(x) waverec2(x, S, 'db8');
0052 
0053 
0054 %% Run simulations
0055 
0056 % Random Fourier sampling example
0057 %  Define mask
0058 %  Uniform sampling of the half Fourier plane
0059 mask = rand(size(im)) < p;
0060 mask(:,1:floor(size(im,2)/2))=0;
0061 mask = ifftshift(mask);
0062 mask(1,1)=0;
0063 mask(floor(size(im,1)/2):end,1)=0;
0064 
0065 ind = find(mask==1);
0066 Ma = sparse(1:numel(ind), ind, ...
0067   ones(numel(ind), 1), numel(ind), numel(im));
0068 
0069 % Composition (Masking o Fourier)
0070 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0071 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0072 
0073 % Apply measurement operator
0074 y = A(im);
0075 
0076 % Add Gaussian i.i.d. noise
0077 sigma_noise = 10^(-input_snr/20)*std(im(:));
0078 noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0079 y = y + noise;
0080 
0081 % Tolerance on noise
0082 epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise;
0083 epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise;
0084 tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball
0085 
0086 % Solve optimisation problem
0087 
0088 % Parameters for BPDN
0089 param.verbose = 1; % Print log or not
0090 param.gamma = 1e-1; % Convergence parameter
0091 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0092 param.max_iter = 200; % Max. number of iterations for the L1 problem
0093 param.nu_B2 = 1; % Bound on the norm of the operator A
0094 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0095 param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection
0096 param.pos_B2 = 1; %Positivity flag
0097 param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball
0098 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0099 %Optional parameters when Psit is not a tight frame:
0100 %param.nu_L1 = 1; % Bound on the norm of the operator Psit
0101 %param.max_iter_L1 = 200; %Max. number of iterations of the L1 prox
0102 %param.rel_obj_L1 = 1e-3; % Tolerance for the prox L1
0103 
0104 % Solve BPDN problem with positivity constraint
0105 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0106 
0107 % Compute SNR
0108 RSNR1 = 20*log10(norm(im,'fro') ...
0109   / norm(im-sol1,'fro'));
0110 
0111 % Example with only reality constraint
0112 param.pos_B2 = 0; %Positivity flag
0113 param.real_B2 = 1; %Reality flag
0114 
0115 % Solve BPDN problem
0116 sol2 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0117 
0118 % Compute SNR
0119 RSNR2 = 20*log10(norm(im,'fro') ...
0120   / norm(im-sol2,'fro'));
0121 
0122 
0123 %% Show results
0124 
0125 figure
0126 imagesc(sol1), axis off, axis image, colorbar
0127 title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB'])
0128 colormap gray
0129 
0130 figure
0131 imagesc(sol2), axis off, axis image, colorbar
0132 title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB'])
0133 colormap gray

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_TVDN.html000066400000000000000000000167721277570055300211070ustar00rootroot00000000000000 Description of Example_TVDN
Home > matlab > Example_TVDN.m

Example_TVDN

PURPOSE ^

% Example_TVDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_TVDN
 Example to demonstrate use of TVDN solver.  A random Fourier sampling
 measurement operator is considered.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_TVDN
0002 % Example to demonstrate use of TVDN solver.  A random Fourier sampling
0003 % measurement operator is considered.
0004 
0005 
0006 %% Clear workspace
0007 
0008 clc
0009 clear;
0010 
0011 
0012 %% Define paths
0013 
0014 addpath misc/
0015 addpath prox_operators/
0016 
0017 
0018 %% Define parameters
0019 
0020 % Coverages (half the plane for Fourier sampling)
0021 p = [0.50];
0022 
0023 % Noise level (on the measurements)
0024 input_snr = 30;
0025 
0026 
0027 %% Read image
0028 
0029 % Load image
0030 im = im2double(imread('cameraman.tif'));
0031 
0032 % Normalise
0033 im = im/max(max(im));
0034 
0035 % Enforce positivity
0036 im(im<0) = 0;
0037 
0038 
0039 %% Run simulations
0040 
0041 %Random Fourier sampling example
0042 % Define mask
0043 % Uniform sampling of the half Fourier plane
0044 mask = rand(size(im)) < p;
0045 mask(:,1:floor(size(im,2)/2))=0;
0046 mask = ifftshift(mask);
0047 mask(1,1)=0;
0048 mask(floor(size(im,1)/2):end,1)=0;
0049 
0050 ind = find(mask==1);
0051 Ma = sparse(1:numel(ind), ind, ...
0052   ones(numel(ind), 1), numel(ind), numel(im));
0053 
0054 % Composition (Masking o Fourier)
0055 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0056 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0057 
0058 % Apply measurement operator
0059 y = A(im);
0060 
0061 % Add Gaussian i.i.d. noise
0062 sigma_noise = 10^(-input_snr/20)*std(im(:));
0063 noise = (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0064 y = y + noise;
0065 
0066 % Tolerance on noise
0067 epsilon = sqrt(numel(y) + 2*sqrt(numel(y)))*sigma_noise;
0068 epsilon_up = sqrt(numel(y) + 2.1*sqrt(numel(y)))*sigma_noise;
0069 tol_B2 = (epsilon_up/epsilon)-1; % Tolerance for the projection onto the L2-ball
0070 
0071 % Solve optimisation problem
0072 
0073 % Parameters for TVDN
0074 param.verbose = 1; % Print log or not
0075 param.gamma = 1e-1; % Converge parameter
0076 param.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0077 param.max_iter = 200; % Max. number of iterations for the TVDN problem
0078 param_TV.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0079 param.nu_B2 = 1; % Bound on the norm of the operator A
0080 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0081 param.max_iter_B2 = 200; %Max. number of iterations of the L2-ball projection
0082 param.pos_B2 = 1; %Positivity flag
0083 param.tol_B2 = tol_B2; % Tolerance for the projection onto the L2-ball
0084 
0085 % Solve TVDN problem with positivity constraint
0086 sol1 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0087 
0088 % Compute SNR
0089 RSNR1 = 20*log10(norm(im,'fro') ...
0090   / norm(im-sol1,'fro'));
0091 
0092 % Example with only reality constraint
0093 param.pos_B2 = 0; %Positivity flag
0094 param.real_B2 = 1; %Reality flag
0095 
0096 % Solve TVDN problem
0097 sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0098 
0099 % Compute SNR
0100 RSNR2 = 20*log10(norm(im,'fro') ...
0101   / norm(im-sol2,'fro'));
0102 
0103 
0104 %% Show results
0105 
0106 figure
0107 imagesc(sol1), axis off, axis image, colorbar
0108 title(['Rec. with positivity const. SNR=',num2str(RSNR1), 'dB'])
0109 colormap gray
0110 
0111 figure
0112 imagesc(sol2), axis off, axis image, colorbar
0113 title(['Rec. with reality const. SNR=',num2str(RSNR2), 'dB'])
0114 colormap gray

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_TVDN2.html000066400000000000000000000162141277570055300211600ustar00rootroot00000000000000 Description of Example_TVDN2
Home > matlab > Example_TVDN2.m

Example_TVDN2

PURPOSE ^

% Example_TVDN2

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example_TVDN2
 Two examples to demonstrate use of TVDN solver.  Simple inpainting and
 Fourier measurement examples are included.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example_TVDN2
0002 % Two examples to demonstrate use of TVDN solver.  Simple inpainting and
0003 % Fourier measurement examples are included.
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 input_snr = 30; % Noise level (on the measurements)
0016 
0017 %% Load an image
0018 im = im2double(imread('cameraman.tif'));
0019 %
0020 figure(1);
0021 imagesc(im); axis image; axis off;
0022 colormap gray; title('Original image'); drawnow;
0023 
0024 %% Create a mask with 33% of 1 (the rest is set to 0)
0025 % Mask
0026 mask = rand(size(im)) < 0.33; ind = find(mask==1);
0027 % Masking matrix (sparse matrix in matlab)
0028 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0029 % Masking operator
0030 A = @(x) Ma*x(:); % Select 33% of the values in x;
0031 At = @(x) reshape(Ma'*x(:), size(im)); % Adjoint operator + reshape image
0032 
0033 %% First problem: Inpainting problem
0034 % Select 33% of pixels
0035 y = A(im);
0036 % Add Gaussian i.i.d. noise
0037 sigma_noise = 10^(-input_snr/20)*std(im(:));
0038 y = y + randn(size(y))*sigma_noise;
0039 % Display the downsampled image
0040 figure(2); clf;
0041 subplot(121); imagesc(At(y)); axis image; axis off;
0042 colormap gray; title('Measured image'); drawnow;
0043 % Parameters for TVDN
0044 param.verbose = 1; % Print log or not
0045 param.gamma = 1e-1; % Converge parameter
0046 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0047 param.max_iter = 200; % Max. number of iterations for the TVDN problem
0048 param_TV.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0049 param.nu_B2 = 1; % Bound on the norm of the operator A
0050 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0051 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0052 param.max_iter_B2 = 500;
0053 % Tolerance on noise
0054 epsilon = sqrt(chi2inv(0.99, numel(ind)))*sigma_noise;
0055 % Solve TVDN problem
0056 sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0057 % Show reconstructed image
0058 figure(2);
0059 subplot(122); imagesc(sol); axis image; axis off;
0060 colormap gray; title('Reconstructed image'); drawnow;
0061 
0062 %% Second problem: Reconstruct from 33% of Fourier measurements
0063 % Composition (Masking o Fourier)
0064 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0065 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0066 % Select 33% of Fourier coefficients
0067 y = A(im);
0068 % Add Gaussian i.i.d. noise
0069 sigma_noise = 10^(-input_snr/20)*std(im(:));
0070 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0071 % Display the downsampled image
0072 figure(3); clf;
0073 subplot(121); imagesc(real(At(y))); axis image; axis off;
0074 colormap gray; title('Measured image'); drawnow;
0075 % Tolerance on noise
0076 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0077 % Solve TVDN problem
0078 sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param);
0079 % Show reconstructed image
0080 figure(3);
0081 subplot(122); imagesc(real(sol)); axis image; axis off;
0082 colormap gray; title('Reconstructed image'); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_TVDNoA.html000066400000000000000000000125111277570055300213520ustar00rootroot00000000000000 Description of Example_TVDNoA
Home > matlab > Example_TVDNoA.m

Example_TVDNoA

PURPOSE ^

% Example TVDNoA

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Example TVDNoA
 Example to demonstrate TVoA_B2 solver, where an additional operator is
 included in the TV norm of the TVDN problem.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Example TVDNoA
0002 % Example to demonstrate TVoA_B2 solver, where an additional operator is
0003 % included in the TV norm of the TVDN problem.
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 32;
0016 input_snr = 1; % Noise level (on the measurements)
0017 randn('seed', 1);
0018 
0019 %% Load an image
0020 im_ref = phantom(N);
0021 %
0022 figure(1);
0023 imagesc(im_ref); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create an artifial operator to test prox_TVoS
0027 S = randn(N^2, N^2)/N^2;
0028 im = reshape(S\im_ref(:), N, N); % S*im is thus sparse in TV
0029 
0030 %% Add Gaussian i.i.d. noise to im
0031 y = im;
0032 sigma_noise = 10^(-input_snr/20)*std(im_ref(:));
0033 y = y + randn(size(y))*sigma_noise;
0034 
0035 %% Solving modified ROF
0036 % Parameters for TVDN
0037 param.verbose = 2; % Print log or not
0038 param.gamma = 1; % Converge parameter
0039 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0040 param.max_iter = 100; % Max. number of iterations for the TVDN problem
0041 param.max_iter_TV = 100; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0042 param.nu_B2 = 1; % Bound on the norm of the measurement operator (Id here)
0043 param.tight_B2 = 1; % Indicate that A is a tight frame (1) or not (0)
0044 param.nu_TV = norm(S)^2; % Bound on the norm of the operator S
0045 func_S = @(x) reshape(S*x(:), N, N);
0046 func_St = @(x) reshape(S'*x(:), N, N);
0047 % Tolerance on noise
0048 epsilon = sqrt(chi2inv(0.99, numel(im)))*sigma_noise;
0049 % Identity
0050 A = @(x) x;
0051 % Solve
0052 sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, A, func_S, func_St, param);
0053 % Show reconstructed image
0054 figure(2);
0055 imagesc(func_S(sol)); axis image; axis off;
0056 colormap gray; title('Reconstructed image'); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_weighted_BPDN.html000066400000000000000000000160221277570055300227230ustar00rootroot00000000000000 Description of Example_weighted_BPDN
Home > matlab > Example_weighted_BPDN.m

Example_weighted_BPDN

PURPOSE ^

% Exampled_weighted_L1

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Exampled_weighted_L1
 Example to demonstrate use of BPDN solver when incorporating weights
 (performs one re-weighting of previous solution).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Exampled_weighted_L1
0002 % Example to demonstrate use of BPDN solver when incorporating weights
0003 % (performs one re-weighting of previous solution).
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 64;
0016 input_snr = 30; % Noise level (on the measurements)
0017 randn('seed', 1); rand('seed', 1);
0018 
0019 %% Create an image with few spikes
0020 im = zeros(N); ind = randperm(N^2); im(ind(1:100)) = 1;
0021 %
0022 figure(1);
0023 subplot(221), imagesc(im); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create a mask
0027 % Mask
0028 mask = rand(size(im)) < 0.095; ind = find(mask==1);
0029 % Masking matrix (sparse matrix in matlab)
0030 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0031 % Masking operator
0032 A = @(x) Ma*x(:);
0033 At = @(x) reshape(Ma'*x(:), size(im));
0034 
0035 %% Reconstruct from a few Fourier measurements
0036 
0037 % Composition (Masking o Fourier)
0038 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0039 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0040 
0041 % Sparsity operator
0042 Psit = @(x) x; Psi = Psit;
0043 
0044 % Select 33% of Fourier coefficients
0045 y = A(im);
0046 
0047 % Add Gaussian i.i.d. noise
0048 sigma_noise = 10^(-input_snr/20)*std(im(:));
0049 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0050 
0051 % Display the downsampled image
0052 figure(1);
0053 subplot(222); imagesc(real(At(y))); axis image; axis off;
0054 colormap gray; title('Measured image'); drawnow;
0055 
0056 % Tolerance on noise
0057 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0058 
0059 % Parameters for BPDN
0060 param.verbose = 1; % Print log or not
0061 param.gamma = 1e-1; % Converge parameter
0062 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0063 param.max_iter = 300; % Max. number of iterations for the TVDN problem
0064 param.nu_B2 = 1; % Bound on the norm of the operator A
0065 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0066 param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0067 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0068 param.pos_l1 = 1; %
0069 
0070 % Solve BPDN problem (without weights)
0071 sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0072 
0073 % Show reconstructed image
0074 figure(1);
0075 subplot(223); imagesc(real(sol)); axis image; axis off;
0076 colormap gray; title(['First estimate - ', ...
0077     num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow;
0078 
0079 % Refine the estimate
0080 param.weights = 1./(abs(sol)+1e-5);
0081 sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0082 
0083 % Show reconstructed image
0084 figure(1);
0085 subplot(224); imagesc(real(sol)); axis image; axis off;
0086 colormap gray; title(['Second estimate - ', ...
0087     num2str(sopt_mltb_SNR(im, real(sol))), 'dB']); drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Example_weighted_TVDN.html000066400000000000000000000166741277570055300227700ustar00rootroot00000000000000 Description of Example_weighted_TVDN
Home > matlab > Example_weighted_TVDN.m

Example_weighted_TVDN

PURPOSE ^

% Exampled_weighted_TVDN

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Exampled_weighted_TVDN
 Example to demonstrate use of TVDN solver when incorporating weights
 (performs one re-weighting of previous solution).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Exampled_weighted_TVDN
0002 % Example to demonstrate use of TVDN solver when incorporating weights
0003 % (performs one re-weighting of previous solution).
0004 
0005 
0006 %% Clear workspace
0007 clc;
0008 clear;
0009 
0010 %% Define paths
0011 addpath misc/
0012 addpath prox_operators/
0013 
0014 %% Parameters
0015 N = 64;
0016 input_snr = 30; % Noise level (on the measurements)
0017 randn('seed', 1); rand('seed', 1);
0018 
0019 %% Load image
0020 im = phantom(N);
0021 %
0022 figure(1); clf;
0023 subplot(141), imagesc(im); axis image; axis off;
0024 colormap gray; title('Original image'); drawnow;
0025 
0026 %% Create a mask
0027 % Mask
0028 mask = rand(size(im)) < 0.33; ind = find(mask==1);
0029 % Masking matrix (sparse matrix in matlab)
0030 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0031 
0032 %% Measure a few Fourier measurements
0033 
0034 % Composition (Masking o Fourier)
0035 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(im)), numel(x), 1);
0036 At = @(x) ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(im)));
0037 
0038 % TV sparsity operator
0039 Psit = @(x) x; Psi = Psit;
0040 
0041 % Select 33% of Fourier coefficients
0042 y = A(im);
0043 
0044 % Add Gaussian i.i.d. noise
0045 sigma_noise = 10^(-input_snr/20)*std(im(:));
0046 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0047 
0048 % Display the downsampled image
0049 figure(1);
0050 subplot(142); imagesc(real(At(y))); axis image; axis off;
0051 colormap gray; title('Measured image'); drawnow;
0052 
0053 %% Reconstruct with TV
0054 
0055 % Tolerance on noise
0056 epsilon = sqrt(chi2inv(0.99, 2*numel(ind))/2)*sigma_noise;
0057 
0058 % Parameters for TVDN
0059 param.verbose = 1; % Print log or not
0060 param.rel_obj = 1e-4; % Stopping criterion for the TVDN problem
0061 param.max_iter = 200; % Max. nb. of iterations for the TVDN problem
0062 param.gamma = 1e-1; % Converge parameter
0063 param.nu_B2 = 1; % Bound on the norm of the operator A
0064 param.tol_B2 = 1e-4; % Tolerance for the projection onto the L2-ball
0065 param.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0066 param.max_iter_TV = 500; %
0067 param.zero_weights_flag_TV = 0; %
0068 param.identical_weights_flag_TV = 1; %
0069 
0070 % Solve TVDN problem (without weights)
0071 sol_1 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0072 
0073 % Show first reconstructed image
0074 figure(1);
0075 subplot(143); imagesc(real(sol_1)); axis image; axis off;
0076 colormap gray; 
0077 title(['First estimate: ', ...
0078     num2str(sopt_mltb_SNR(im, real(sol_1))), 'dB']);
0079 drawnow;
0080 clc;
0081 
0082 %% Re-fine the estimate with weighted TV
0083 % Weights
0084 [param.weights_dx_TV param.weights_dy_TV] = sopt_mltb_gradient_op(real(sol_1));
0085 param.weights_dx_TV = 1./(abs(param.weights_dx_TV)+1e-3);
0086 param.weights_dy_TV = 1./(abs(param.weights_dy_TV)+1e-3);
0087 param.identical_weights_flag_TV = 0;
0088 param.gamma = 1e-3;
0089 
0090 % First reconstruction with weights in the gradient
0091 param.zero_weights_flag_TV = 1;
0092 sol_2 = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0093 % Show second reconstructed image
0094 figure(1);
0095 subplot(144); imagesc(real(sol_2)); axis image; axis off;
0096 colormap gray; 
0097 title(['Second estimate: ', ...
0098     num2str(sopt_mltb_SNR(im, real(sol_2))), 'dB']); 
0099 drawnow;

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Experiment1.html000066400000000000000000000426341277570055300210560ustar00rootroot00000000000000 Description of Experiment1
Home > matlab > Experiment1.m

Experiment1

PURPOSE ^

% Experiment1

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiment1
 In this experiment we evaluate the performance of SARA for spread 
 spectrum acquisition. We use a 256x256 version of Lena as a test image. 
 Number of measurements is M = 0.2N and input SNR is set to 30 dB. These
 parameters can be changed by modifying the variables p (for the
 undersampling ratio) and input_snr (for the input SNR).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiment1
0002 % In this experiment we evaluate the performance of SARA for spread
0003 % spectrum acquisition. We use a 256x256 version of Lena as a test image.
0004 % Number of measurements is M = 0.2N and input SNR is set to 30 dB. These
0005 % parameters can be changed by modifying the variables p (for the
0006 % undersampling ratio) and input_snr (for the input SNR).
0007 
0008 
0009 %% Clear workspace
0010 
0011 clc
0012 clear;
0013 
0014 
0015 %% Define paths
0016 
0017 addpath misc/
0018 addpath prox_operators/
0019 addpath test_images/
0020 
0021 
0022 
0023 %% Read image
0024 
0025 imagename = 'lena_256.tiff';
0026 
0027 % Load image
0028 im = im2double(imread(imagename));
0029 
0030 % Normalise
0031 im = im/max(max(im));
0032 
0033 % Enforce positivity
0034 im(im<0) = 0;
0035 
0036 %% Parameters
0037 
0038 input_snr = 30; % Noise level (on the measurements)
0039 
0040 %Undersampling ratio M/N
0041 p=0.2;
0042 
0043 
0044 %% Sparsity operators
0045 
0046 %Wavelet decomposition depth
0047 nlevel=4;
0048 
0049 dwtmode('per');
0050 [C,S]=wavedec2(im,nlevel,'db8'); 
0051 ncoef=length(C);
0052 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0053 ncoef1=length(C1);
0054 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0055 ncoef2=length(C2);
0056 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0057 ncoef3=length(C3);
0058 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0059 ncoef4=length(C4);
0060 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0061 ncoef5=length(C5);
0062 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0063 ncoef6=length(C6);
0064 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0065 ncoef7=length(C7);
0066 
0067 %SARA
0068 
0069 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0070     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0071     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0072 
0073 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0074     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0075     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0076     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0080 
0081 %Db8 wavelet basis
0082 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0083 Psi2 = @(x) waverec2(x,S,'db8');
0084 
0085 %Curvelet
0086 %CurveLab needs to be installed to run Curvelet simulations
0087 realv = 1;
0088 Cv = fdct_usfft(im,realv);
0089 Mod = sopt_mltb_struct2size(Cv);
0090 
0091 Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); 
0092 Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv);
0093 
0094 %% Spread spectrum operator
0095 % Mask
0096 mask = rand(size(im)) < p; 
0097 ind = find(mask==1);
0098 % Masking matrix (sparse matrix in matlab)
0099 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0100     
0101 %Spread spectrum sequence
0102     
0103 ss=rand(size(im));
0104 C=(2*(ss<0.5)-1);
0105 
0106 A = @(x) Ma*reshape(fft2(C.*x)/sqrt(numel(ind)), numel(x), 1);
0107 At = @(x) C.*(ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0108     
0109 % Sampling
0110 y = A(im);
0111 % Add Gaussian i.i.d. noise
0112 sigma_noise = 10^(-input_snr/20)*std(im(:));
0113 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0114     
0115     
0116 % Tolerance on noise
0117 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0118 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0119     
0120     
0121 % Parameters for BPDN
0122 param.verbose = 1; % Print log or not
0123 param.gamma = 1e-1; % Converge parameter
0124 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0125 param.max_iter = 200; % Max. number of iterations for the L1 problem
0126 param.nu_B2 = 1; % Bound on the norm of the operator A
0127 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0128 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0129 param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active
0130 param.max_iter_B2=300;
0131 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0132 param.nu_L1 = 1;
0133 param.max_iter_L1 = 20;
0134 param.rel_obj_L1 = 1e-2;
0135     
0136     
0137 % Solve BPSA problem
0138     
0139 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0140     
0141 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0142     
0143 % SARA
0144 % It uses the solution to BPSA as a warm start
0145 maxiter=10;
0146 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8));
0147 tol=1e-3;
0148   
0149 sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1);
0150 
0151 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0152 
0153 % Solve BPBb8 problem
0154     
0155 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0156     
0157 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0158     
0159 % RWBPDb8
0160 % It uses the solution to BPDBb8 as a warm start
0161 maxiter=10;
0162 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0163 tol=1e-3;
0164   
0165 sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3);
0166       
0167 RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro'));
0168 
0169 % Parameters for Curvelet
0170 
0171 % Parameters for BPDN
0172 param3.verbose = 1; % Print log or not
0173 param3.gamma = 1e-1; % Converge parameter
0174 param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0175 param3.max_iter = 200; % Max. number of iterations for the L1 problem
0176 param3.nu_B2 = 1; % Bound on the norm of the operator A
0177 param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0178 param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0179 param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0180 param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0181 
0182     
0183 
0184 
0185 % Solve BP Curvelet problem
0186     
0187 sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3);
0188     
0189 RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro'));
0190     
0191 % RW-Curvelet
0192 % It uses the solution to BPDBb8 as a warm start
0193 maxiter=10;
0194 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0195 tol=1e-3;
0196   
0197 sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5);
0198      
0199 RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro'));
0200 
0201     
0202 % Parameters for TVDN
0203 param1.verbose = 1; % Print log or not
0204 param1.gamma = 1e-1; % Converge parameter
0205 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0206 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0207 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0208 param1.nu_B2 = 1; % Bound on the norm of the operator A
0209 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0210 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0211 param1.max_iter_B2 = 300;
0212 param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0213     
0214 % Solve TV problem
0215     
0216 sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0217     
0218 RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro'));
0219     
0220 % RWTV
0221 % It uses the solution to TV as a warm start
0222 maxiter=10;
0223 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0224 tol=1e-3;
0225   
0226 sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7);
0227     
0228 RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro'));
0229 
0230 
0231 %Show reconstructed images
0232 
0233 figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray;
0234 title(['BPSA, SNR=',num2str(RSNR1), 'dB'])
0235 figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray;
0236 title(['SARA, SNR=',num2str(RSNR2), 'dB'])
0237 
0238 figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray;
0239 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0240 figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray;
0241 title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB'])
0242 
0243 figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray;
0244 title(['Curvelet, SNR=',num2str(RSNR5), 'dB'])
0245 figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray;
0246 title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB'])
0247 
0248 figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray;
0249 title(['TV, SNR=',num2str(RSNR7), 'dB'])
0250 figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray;
0251 title(['RW-TV, SNR=',num2str(RSNR8), 'dB'])
0252 
0253 
0254 
0255 
0256 
0257 
0258 
0259 
0260 
0261 
0262

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Experiment2.html000066400000000000000000000426531277570055300210600ustar00rootroot00000000000000 Description of Experiment2
Home > matlab > Experiment2.m

Experiment2

PURPOSE ^

% Experiment2

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiment2
 In this experiment we study the performance of SARA with Gaussian random 
 matrices as measurements operators. Due to computational limitations for 
 the use of a dense sensing matrix, for this experiment we use a cropped 
 version of Lena, around the head, of dimension 128x128 as a test image. 
 Number of measurements is M = 0.3N and input SNR is set to 30 dB. These
 parameters can be changed by modifying the variables p (for the
 undersampling ratio) and input_snr (for the input SNR).

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiment2
0002 % In this experiment we study the performance of SARA with Gaussian random
0003 % matrices as measurements operators. Due to computational limitations for
0004 % the use of a dense sensing matrix, for this experiment we use a cropped
0005 % version of Lena, around the head, of dimension 128x128 as a test image.
0006 % Number of measurements is M = 0.3N and input SNR is set to 30 dB. These
0007 % parameters can be changed by modifying the variables p (for the
0008 % undersampling ratio) and input_snr (for the input SNR).
0009 
0010 
0011 %% Clear workspace
0012 
0013 clc
0014 clear;
0015 
0016 
0017 %% Define paths
0018 
0019 addpath misc/
0020 addpath prox_operators/
0021 addpath test_images/
0022 
0023 
0024 %% Read image
0025 
0026 imagename = 'lena_256.tiff';
0027 
0028 % Load image
0029 im1 = im2double(imread(imagename));
0030 
0031 %Crope image
0032 a=70;
0033 b=96;
0034 im=im1(a+1:a+128,b+1:b+128);
0035 
0036 % Enforce positivity
0037 im(im<0) = 0;
0038 
0039 %% Parameters
0040 
0041 input_snr = 30; % Noise level (on the measurements)
0042 
0043 %Undersampling ratio M/N
0044 p=0.3;
0045 
0046 %% Sparsity operators
0047 
0048 %Wavelet decomposition depth
0049 nlevel=4;
0050 
0051 dwtmode('per');
0052 [C,S]=wavedec2(im,nlevel,'db8'); 
0053 ncoef=length(C);
0054 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0055 ncoef1=length(C1);
0056 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0057 ncoef2=length(C2);
0058 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0059 ncoef3=length(C3);
0060 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0061 ncoef4=length(C4);
0062 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0063 ncoef5=length(C5);
0064 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0065 ncoef6=length(C6);
0066 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0067 ncoef7=length(C7);
0068 
0069 %Sparsity averaging operator
0070 
0071 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0072     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0073     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0074 
0075 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0076     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0080     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0081     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0082 
0083 %Db8 wavelet basis
0084 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0085 Psi2 = @(x) waverec2(x,S,'db8');
0086 
0087 %Curvelet
0088 %CurveLab needs to be installed to run Curvelet simulations
0089 realv = 1;
0090 Cv = fdct_usfft(im,realv);
0091 Mod = sopt_mltb_struct2size(Cv);
0092 
0093 Psit3 = @(x) sopt_mltb_fwdcurvelet(x,realv); 
0094 Psi3 = @(x) sopt_mltb_adjcurvelet(x,Mod,realv);
0095 
0096 %% Gaussian matrix operator
0097 
0098 num_meas=floor(p*numel(im));
0099 
0100 Phi = randn(num_meas,numel(im))/sqrt(num_meas);
0101         
0102 bound=svds(Phi,1)^2;
0103      
0104 A = @(x) Phi*x(:);
0105     
0106 At = @(x) reshape(Phi'*x(:),size(im));
0107     
0108    
0109 % Sampling
0110 y = A(im);
0111 % Add Gaussian i.i.d. noise
0112 sigma_noise = 10^(-input_snr/20)*std(im(:));
0113 y = y + (randn(size(y)))*sigma_noise;
0114     
0115     
0116 % Tolerance on noise
0117 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0118 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0119     
0120     
0121 % Parameters for BPDN
0122 param.verbose = 1; % Print log or not
0123 param.gamma = 1e-1; % Converge parameter
0124 param.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0125 param.max_iter = 200; % Max. number of iterations for the L1 problem
0126 param.nu_B2 = bound; % Bound on the norm of the operator A
0127 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0128 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0129 param.pos_B2 = 1; %Positivity constraint: (1) active, (0) not active
0130 param.max_iter_B2=300;
0131 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0132 param.nu_L1 = 1;
0133 param.max_iter_L1 = 20;
0134 param.rel_obj_L1 = 1e-2;
0135     
0136     
0137 % Solve BPSA problem
0138     
0139 sol1 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0140     
0141 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0142     
0143 % SARA
0144 % It uses the solution to BPSA as a warm start
0145 maxiter=10;
0146 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*8));
0147 tol=1e-3;
0148   
0149 sol2 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter, sol1);
0150 
0151 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0152 
0153 % Solve BPBb8 problem
0154     
0155 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0156     
0157 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0158     
0159 % RWBPDb8
0160 % It uses the solution to BPDBb8 as a warm start
0161 maxiter=10;
0162 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0163 tol=1e-3;
0164   
0165 sol4 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi2, Psit2, param, sigma, tol, maxiter, sol3);
0166       
0167 RSNR4=20*log10(norm(im,'fro')/norm(im-sol4,'fro'));
0168 
0169 % Parameters for Curvelet
0170 
0171 % Parameters for BPDN
0172 param3.verbose = 1; % Print log or not
0173 param3.gamma = 1e-1; % Converge parameter
0174 param3.rel_obj = 5e-4; % Stopping criterion for the L1 problem
0175 param3.max_iter = 200; % Max. number of iterations for the L1 problem
0176 param3.nu_B2 = bound; % Bound on the norm of the operator A
0177 param3.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0178 param3.tight_B2 = 1; % Indicate if A is a tight frame (1) or not (0)
0179 param3.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0180 param3.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0181 
0182     
0183 
0184 
0185 % Solve BP Curvelet problem
0186     
0187 sol5 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi3, Psit3, param3);
0188     
0189 RSNR5=20*log10(norm(im,'fro')/norm(im-sol5,'fro'));
0190     
0191 % RW-Curvelet
0192 % It uses the solution to BPDBb8 as a warm start
0193 maxiter=10;
0194 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0195 tol=1e-3;
0196   
0197 sol6 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi3, Psit3, param3, sigma, tol, maxiter, sol5);
0198      
0199 RSNR6=20*log10(norm(im,'fro')/norm(im-sol6,'fro'));
0200 
0201     
0202 % Parameters for TVDN
0203 param1.verbose = 1; % Print log or not
0204 param1.gamma = 1e-1; % Converge parameter
0205 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0206 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0207 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0208 param1.nu_B2 = bound; % Bound on the norm of the operator A
0209 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0210 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0211 param1.max_iter_B2 = 300;
0212 param1.pos_B2 = 1;
0213     
0214 % Solve TV problem
0215     
0216 sol7 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0217     
0218 RSNR7=20*log10(norm(im,'fro')/norm(im-sol7,'fro'));
0219     
0220 % RWTV
0221 % It uses the solution to TV as a warm start
0222 maxiter=10;
0223 sigma=sigma_noise*sqrt(numel(y)/(numel(im)));
0224 tol=1e-3;
0225   
0226 sol8 = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, param1,sigma, tol, maxiter, sol7);
0227     
0228 RSNR8=20*log10(norm(im,'fro')/norm(im-sol8,'fro'));
0229 
0230 %Show reconstructed images
0231 
0232 figure, imagesc(sol1,[0 1]); axis image; axis off; colormap gray;
0233 title(['BPSA, SNR=',num2str(RSNR1), 'dB'])
0234 figure, imagesc(sol2,[0 1]); axis image; axis off; colormap gray;
0235 title(['SARA, SNR=',num2str(RSNR2), 'dB'])
0236 
0237 figure, imagesc(sol3,[0 1]); axis image; axis off; colormap gray;
0238 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0239 figure, imagesc(sol4,[0 1]); axis image; axis off; colormap gray;
0240 title(['RW- BPDb8, SNR=',num2str(RSNR4), 'dB'])
0241 
0242 figure, imagesc(sol5,[0 1]); axis image; axis off; colormap gray;
0243 title(['Curvelet, SNR=',num2str(RSNR5), 'dB'])
0244 figure, imagesc(sol6,[0 1]); axis image; axis off; colormap gray;
0245 title(['RW-Curvelet, SNR=',num2str(RSNR6), 'dB'])
0246 
0247 figure, imagesc(sol7,[0 1]); axis image; axis off; colormap gray;
0248 title(['TV, SNR=',num2str(RSNR7), 'dB'])
0249 figure, imagesc(sol8,[0 1]); axis image; axis off; colormap gray;
0250 title(['RW-TV, SNR=',num2str(RSNR8), 'dB'])
0251 
0252 
0253 
0254 
0255 
0256 
0257 
0258 
0259 
0260 
0261

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/Experiment3.html000066400000000000000000000304561277570055300210570ustar00rootroot00000000000000 Description of Experiment3
Home > matlab > Experiment3.m

Experiment3

PURPOSE ^

% Experiement3

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

% Experiement3
 In this experiment we illustrate the application of SARA to Fourier 
 imaging. We reconstruct a 224x168 positive brain image from standard 
 variable density sampling. Fourier measurements, for an undersampling 
 ratio of M = 0.05N and input SNR set to 30 dB.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 %% Experiement3
0002 % In this experiment we illustrate the application of SARA to Fourier
0003 % imaging. We reconstruct a 224x168 positive brain image from standard
0004 % variable density sampling. Fourier measurements, for an undersampling
0005 % ratio of M = 0.05N and input SNR set to 30 dB.
0006 
0007 
0008 %% Clear workspace
0009 
0010 clc
0011 clear;
0012 
0013 
0014 %% Define paths
0015 
0016 addpath misc/
0017 addpath prox_operators/
0018 addpath test_images/
0019 
0020 
0021 %% Read image
0022 
0023 % Load image
0024 load Brain_low_res
0025 im=abs(map_ref);
0026 
0027 % Normalise
0028 im = im/max(max(im));
0029 
0030 % Enforce positivity
0031 im(im<0) = 0;
0032 
0033 %% Parameters
0034 
0035 input_snr = 30; % Noise level (on the measurements)
0036 
0037 %Undersampling ratio M/N
0038 %The range of p is 0 < p <= 0.5 since the vdsmask
0039 %function samples only half plane. Therefore, full
0040 %sampling is p = 0.5
0041 p=0.05;
0042 
0043 
0044 %% Sparsity operators
0045 
0046 %Wavelet decomposition depth
0047 nlevel=4;
0048 
0049 dwtmode('per');
0050 [C,S]=wavedec2(im,nlevel,'db8'); 
0051 ncoef=length(C);
0052 [C1,S1]=wavedec2(im,nlevel,'db1'); 
0053 ncoef1=length(C1);
0054 [C2,S2]=wavedec2(im,nlevel,'db2'); 
0055 ncoef2=length(C2);
0056 [C3,S3]=wavedec2(im,nlevel,'db3'); 
0057 ncoef3=length(C3);
0058 [C4,S4]=wavedec2(im,nlevel,'db4'); 
0059 ncoef4=length(C4);
0060 [C5,S5]=wavedec2(im,nlevel,'db5'); 
0061 ncoef5=length(C5);
0062 [C6,S6]=wavedec2(im,nlevel,'db6'); 
0063 ncoef6=length(C6);
0064 [C7,S7]=wavedec2(im,nlevel,'db7'); 
0065 ncoef7=length(C7);
0066 
0067 %Sparsity averaging operator
0068 
0069 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';wavedec2(x,nlevel,'db3')';...
0070     wavedec2(x,nlevel,'db4')'; wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';...
0071     wavedec2(x,nlevel,'db7')';wavedec2(x,nlevel,'db8')']/sqrt(8); 
0072 
0073 Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+...
0074     waverec2(x(ncoef1+ncoef2+1:ncoef1+ncoef2+ncoef3),S3,'db3')+...
0075     waverec2(x(ncoef1+ncoef2+ncoef3+1:ncoef1+ncoef2+ncoef3+ncoef4),S4,'db4')+...
0076     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5),S5,'db5')+...
0077     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6),S6,'db6')+...
0078     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7),S7,'db7')+...
0079     waverec2(x(ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+1:ncoef1+ncoef2+ncoef3+ncoef4+ncoef5+ncoef6+ncoef7+ncoef),S,'db8'))/sqrt(8);
0080 
0081 %Db8 wavelet basis
0082 Psit2 = @(x) wavedec2(x, nlevel,'db8'); 
0083 Psi2 = @(x) waverec2(x,S,'db8');
0084 
0085 
0086 % Variable density mask
0087 mask = sopt_mltb_vdsmask(size(im,1),size(im,2),p);
0088 ind = find(mask==1);
0089 % Masking matrix (sparse matrix in matlab)
0090 Ma = sparse(1:numel(ind), ind, ones(numel(ind), 1), numel(ind), numel(im));
0091 
0092   
0093 % Composition (Masking o Fourier)
0094     
0095 A = @(x) Ma*reshape(fft2(x)/sqrt(numel(ind)), numel(x), 1);
0096 At = @(x) (ifft2(reshape(Ma'*x(:), size(im))*sqrt(numel(ind))));
0097       
0098 % Select p% of Fourier coefficients
0099 y = A(im);
0100 % Add Gaussian i.i.d. noise
0101 sigma_noise = 10^(-input_snr/20)*std(im(:));
0102 y = y + (randn(size(y)) + 1i*randn(size(y)))*sigma_noise/sqrt(2);
0103 
0104 
0105 % Tolerance on noise
0106 epsilon = sqrt(numel(y)+2*sqrt(numel(y)))*sigma_noise;
0107 epsilon_up = sqrt(numel(y)+2.1*sqrt(numel(y)))*sigma_noise;
0108 
0109 
0110 %% Parameters for BPDN
0111 param.verbose = 1; % Print log or not
0112 param.gamma = 1e-1; % Converge parameter
0113 param.rel_obj = 4e-4; % Stopping criterion for the L1 problem
0114 param.max_iter = 200; % Max. number of iterations for the L1 problem
0115 param.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0116 param.nu_B2 = 1; % Bound on the norm of the operator A
0117 param.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0118 param.pos_B2 = 1;  % Positivity constraint flag. (1) active (0) otherwise
0119 param.tight_L1 = 1; % Indicate if Psit is a tight frame (1) or not (0)
0120 param.nu_L1 = 1;
0121 param.max_iter_L1 = 20;
0122 param.rel_obj_L1 = 1e-2;
0123     
0124 % Solve SARA
0125 maxiter=10;
0126 sigma=sigma_noise*sqrt(numel(y)/(numel(im)*9));
0127 tol=1e-3;
0128 sol1 = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, param, sigma, tol, maxiter);
0129     
0130 RSNR1=20*log10(norm(im,'fro')/norm(im-sol1,'fro'));
0131     
0132     
0133 %% Parameters for TVDN
0134 param1.verbose = 1; % Print log or not
0135 param1.gamma = 3e-1; % Converge parameter
0136 param1.rel_obj = 5e-4; % Stopping criterion for the TVDN problem
0137 param1.max_iter = 200; % Max. number of iterations for the TVDN problem
0138 param1.max_iter_TV = 200; % Max. nb. of iter. for the sub-problem (proximal TV operator)
0139 param1.nu_B2 = 1; % Bound on the norm of the operator A
0140 param1.tol_B2 = 1-(epsilon/epsilon_up); % Tolerance for the projection onto the L2-ball
0141 param1.tight_B2 = 0; % Indicate if A is a tight frame (1) or not (0)
0142 param1.max_iter_B2 = 200;
0143 param1.pos_B2 = 1; % Positivity constraint flag. (1) active (0) otherwise
0144 
0145 % Solve TVDN problem
0146 sol2 = sopt_mltb_solve_TVDN(y, epsilon, A, At, param1);
0147 
0148 RSNR2=20*log10(norm(im,'fro')/norm(im-sol2,'fro'));
0149    
0150     
0151 % Solve BPDN problem
0152 sol3 = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi2, Psit2, param);
0153 
0154 
0155 RSNR3=20*log10(norm(im,'fro')/norm(im-sol3,'fro'));
0156 
0157 figure, imagesc(sol1,[0 1]);axis image;axis off; colormap gray;
0158 title(['SARA, SNR=',num2str(RSNR1), 'dB'])
0159 figure, imagesc(sol2,[0 1]);axis image;axis off; colormap gray;
0160 title(['TV, SNR=',num2str(RSNR2), 'dB'])
0161 figure, imagesc(sol3,[0 1]);axis image;axis off; colormap gray;
0162 title(['BPDb8, SNR=',num2str(RSNR3), 'dB'])
0163 figure, imagesc(im, [0 1]); axis image; axis off; colormap gray;
0164 title('Original image')
0165     
0166     
0167     
0168     
0169     
0170     
0171     
0172 
0173 
0174 
0175 
0176 
0177 
0178 
0179 
0180 
0181 
0182 
0183

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/index.html000066400000000000000000000073541277570055300177640ustar00rootroot00000000000000 Index for Directory matlab
< Master index Index for matlab >

Index for matlab

Matlab files in this directory:

 Example_BPDN% Example_BPDN
 Example_TVDN% Example_TVDN
 Example_TVDN2% Example_TVDN2
 Example_TVDNoA% Example TVDNoA
 Example_weighted_BPDN% Exampled_weighted_L1
 Example_weighted_TVDN% Exampled_weighted_TVDN
 Experiment1% Experiment1
 Experiment2% Experiment2
 Experiment3% Experiement3
 sopt_mltb_solve_BPDNsopt_mltb_solve_BPDN - Solve BPDN problem
 sopt_mltb_solve_L2DNsopt_mltb_solve_L2DN - Solve L2DN problem.
 sopt_mltb_solve_TVDNsopt_mltb_solve_TVDN - Solve TVDN problem
 sopt_mltb_solve_TVDNoAsopt_mltb_solve_TVDNoA - Solve augmented TVDN problem
 sopt_mltb_solve_rwBPDNsopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem
 sopt_mltb_solve_rwTVDNsopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

Subsequent directories:


Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/000077500000000000000000000000001277570055300167115ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/misc/.svn/000077500000000000000000000000001277570055300175755ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/misc/.svn/all-wcprops000066400000000000000000000036021277570055300217640ustar00rootroot00000000000000K 25 svn:wc:ra_dav:version-url V 51 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc END sopt_mltb_fwdcurvelet.html K 25 svn:wc:ra_dav:version-url V 78 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_fwdcurvelet.html END sopt_mltb_gradient_op.html K 25 svn:wc:ra_dav:version-url V 78 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_gradient_op.html END sopt_mltb_div_op.html K 25 svn:wc:ra_dav:version-url V 73 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_div_op.html END sopt_mltb_gradient_op_sphere.html K 25 svn:wc:ra_dav:version-url V 85 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_gradient_op_sphere.html END sopt_mltb_modifypdf.html K 25 svn:wc:ra_dav:version-url V 76 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_modifypdf.html END sopt_mltb_struct2size.html K 25 svn:wc:ra_dav:version-url V 78 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_struct2size.html END sopt_mltb_SNR.html K 25 svn:wc:ra_dav:version-url V 70 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_SNR.html END index.html K 25 svn:wc:ra_dav:version-url V 62 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/index.html END sopt_mltb_TV_norm.html K 25 svn:wc:ra_dav:version-url V 74 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_TV_norm.html END sopt_mltb_genmask.html K 25 svn:wc:ra_dav:version-url V 74 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_genmask.html END sopt_mltb_div_op_sphere.html K 25 svn:wc:ra_dav:version-url V 80 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_div_op_sphere.html END sopt_mltb_adjcurvelet.html K 25 svn:wc:ra_dav:version-url V 78 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_adjcurvelet.html END sopt_mltb_vdsmask.html K 25 svn:wc:ra_dav:version-url V 74 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/misc/sopt_mltb_vdsmask.html END sopt-2.0.0/matlab/doc/matlab/misc/.svn/entries000066400000000000000000000047241277570055300212000ustar00rootroot0000000000000010 dir 238 https://svn.epfl.ch/svn/sopt/trunk/matlab/doc/matlab/misc https://svn.epfl.ch/svn/sopt 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 970ed402-9328-4b70-8940-a90ce832aee1 sopt_mltb_fwdcurvelet.html file 2013-02-22T16:01:56.000000Z 61a0afe7e1051dc663bd813e1946c991 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4018 sopt_mltb_gradient_op.html file 2013-02-22T16:01:56.000000Z e9e53c757aa0220be1de8391a45e1c8e 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4290 sopt_mltb_div_op.html file 2013-02-22T16:01:56.000000Z f767067fa21bf8a7dd2648939365f06d 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4153 sopt_mltb_gradient_op_sphere.html file 2013-02-22T16:01:56.000000Z b0006e097fcc454e00f339ca786d607b 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 5896 sopt_mltb_modifypdf.html file 2013-02-22T16:01:56.000000Z e697c0b0875c1de406230cb54cc36181 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4983 sopt_mltb_struct2size.html file 2013-02-22T16:01:56.000000Z 60316959c86e3778d036f3a6df6363da 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 3818 sopt_mltb_SNR.html file 2013-02-22T16:01:56.000000Z 86b350223ad23e2d92d3fe209cc3e133 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 3975 index.html file 2013-02-22T16:01:56.000000Z b0f89bce4130abc4f87f642aa8b78fe0 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 3461 sopt_mltb_TV_norm.html file 2013-02-22T16:01:56.000000Z d14c505596d34092576f2f6ee3239888 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 6268 sopt_mltb_genmask.html file 2013-02-22T16:01:56.000000Z 93760df61086aca94f64462a975b7618 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4002 sopt_mltb_div_op_sphere.html file 2013-02-22T16:01:56.000000Z f5bb5a2ef42036cc1fa9f6303946661e 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 5252 sopt_mltb_adjcurvelet.html file 2013-02-22T16:01:56.000000Z 7b04f5f1d1c1efc204e0be9b6f9f351a 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 4614 sopt_mltb_vdsmask.html file 2013-02-22T16:01:56.000000Z 31d41f1ec21b4ed34cf5908ed92f5048 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 6317 sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/000077500000000000000000000000001277570055300214715ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/index.html.svn-base000066400000000000000000000066051277570055300252120ustar00rootroot00000000000000 Index for Directory matlab/misc
< Master index Index for matlab/misc >

Index for matlab/misc

Matlab files in this directory:

 sopt_mltb_SNRSNR - Compute the SNR between two images
 sopt_mltb_TV_normsopt_mltb_TV_norm - Compute TV norm
 sopt_mltb_adjcurveletsopt_mltb_adjcurvelet - Adjoint curvelet transform
 sopt_mltb_div_opsopt_mltb_div_op - Compute divergence
 sopt_mltb_div_op_spheresopt_mltb_div_op_sphere - Compute divergence on sphere
 sopt_mltb_fwdcurveletsopt_mltb_fwdcurvelet - Forward curvelet transform
 sopt_mltb_genmasksopt_mltb_genmask - Generate mask
 sopt_mltb_gradient_opsopt_mltb_gradient_op - Compute gradient
 sopt_mltb_gradient_op_spheresopt_mltb_gradient_op_sphere - Compute gradient on sphere
 sopt_mltb_modifypdfsopt_mltb_modifypdf - Modify PDF of sampling profile
 sopt_mltb_struct2sizesopt_mltb_struct2size - Compute curvelet data structure
 sopt_mltb_vdsmasksopt_mltb_vdsmask - Create variable density sampling profile

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_SNR.html.svn-base000066400000000000000000000076071277570055300266330ustar00rootroot00000000000000 Description of sopt_mltb_SNR
Home > matlab > misc > sopt_mltb_SNR.m

sopt_mltb_SNR

PURPOSE ^

SNR - Compute the SNR between two images

SYNOPSIS ^

function snr = sopt_mltb_SNR(map_init, map_recon)

DESCRIPTION ^

 SNR - Compute the SNR between two images
 
 C omputes the SNR between the maps map_init and map_recon.  The SNR is 
 computed by
    10 * log10( var(MAP_INIT) / var(MAP_INIT-MAP_NOISY) )
  where var stands for the matlab built-in function that computes the
  variance.

 Inputs:

   - map_init: Initial image.

   - map_recon: Reconstructed image.

 Outputs:

   - snr: SNR.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function snr = sopt_mltb_SNR(map_init, map_recon)
0002 % SNR - Compute the SNR between two images
0003 %
0004 % C omputes the SNR between the maps map_init and map_recon.  The SNR is
0005 % computed by
0006 %    10 * log10( var(MAP_INIT) / var(MAP_INIT-MAP_NOISY) )
0007 %  where var stands for the matlab built-in function that computes the
0008 %  variance.
0009 %
0010 % Inputs:
0011 %
0012 %   - map_init: Initial image.
0013 %
0014 %   - map_recon: Reconstructed image.
0015 %
0016 % Outputs:
0017 %
0018 %   - snr: SNR.
0019 
0020 noise = map_init(:)-map_recon(:);
0021 var_init = var(map_init(:));
0022 var_den = var(noise(:));
0023 snr = 10 * log10(var_init/var_den);
0024 
0025 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_TV_norm.html.svn-base000066400000000000000000000141741277570055300275520ustar00rootroot00000000000000 Description of sopt_mltb_TV_norm
Home > matlab > misc > sopt_mltb_TV_norm.m

sopt_mltb_TV_norm

PURPOSE ^

sopt_mltb_TV_norm - Compute TV norm

SYNOPSIS ^

function y = sopt_mltb_TV_norm(u, sphere_flag,incNP, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_TV_norm - Compute TV norm

 Compute the TV of an image on the plane or sphere.

 Inputs:

   - u: Image to compute TV norm of.

   - sphere_flag: Flag indicating whether to compute the TV norm on the
       sphere (1 = on sphere, 2 = on plane).

   - includeNP: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:

   - y: TV norm of image.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function y = sopt_mltb_TV_norm(u, sphere_flag, ...
0002     incNP, weights_dx, weights_dy)
0003 % sopt_mltb_TV_norm - Compute TV norm
0004 %
0005 % Compute the TV of an image on the plane or sphere.
0006 %
0007 % Inputs:
0008 %
0009 %   - u: Image to compute TV norm of.
0010 %
0011 %   - sphere_flag: Flag indicating whether to compute the TV norm on the
0012 %       sphere (1 = on sphere, 2 = on plane).
0013 %
0014 %   - includeNP: Flag indicating whether the North pole is included
0015 %       in the sampling grid (1 = North pole included, 0 = North pole not
0016 %       included).
0017 %
0018 %   - weights_dx: Weights in the x (phi) direction.
0019 %
0020 %   - weights_dy: Weights in the y (theta) direction.
0021 %
0022 % Outputs:
0023 %
0024 %   - y: TV norm of image.
0025 
0026 if sphere_flag
0027     if nargin>3 
0028         [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP, weights_dx, weights_dy);
0029     else
0030         [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP);
0031     end
0032 else
0033     if nargin>3 
0034         [dx, dy] = sopt_mltb_gradient_op(u, weights_dx, weights_dy);
0035     else
0036         [dx, dy] = sopt_mltb_gradient_op(u);
0037     end
0038 end
0039 temp = sqrt(abs(dx).^2 + abs(dy).^2);
0040 y = sum(temp(:));
0041 
0042 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_adjcurvelet.html.svn-base000066400000000000000000000110061277570055300304650ustar00rootroot00000000000000 Description of sopt_mltb_adjcurvelet
Home > matlab > misc > sopt_mltb_adjcurvelet.m

sopt_mltb_adjcurvelet

PURPOSE ^

sopt_mltb_adjcurvelet - Adjoint curvelet transform

SYNOPSIS ^

function restim = sopt_mltb_adjcurvelet(coef, Mod, real)

DESCRIPTION ^

 sopt_mltb_adjcurvelet - Adjoint curvelet transform

 Compute the adjoint curvelet transform from the curvelet
 coefficient vector.

 Inputs:

   - coef: Input curvelet coefficient vector.

   - Mod: Data structure that stores sizes of the curvelet transform 
       generated from the CurveLab toolbox.

   - real: Flag indicating if the transform is real or complex (1 = real,  
       0 = complex).

 Outputs:

   - restim: Estimated image from the Curvelet coefficients.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function restim = sopt_mltb_adjcurvelet(coef, Mod, real)
0002 % sopt_mltb_adjcurvelet - Adjoint curvelet transform
0003 %
0004 % Compute the adjoint curvelet transform from the curvelet
0005 % coefficient vector.
0006 %
0007 % Inputs:
0008 %
0009 %   - coef: Input curvelet coefficient vector.
0010 %
0011 %   - Mod: Data structure that stores sizes of the curvelet transform
0012 %       generated from the CurveLab toolbox.
0013 %
0014 %   - real: Flag indicating if the transform is real or complex (1 = real,
0015 %       0 = complex).
0016 %
0017 % Outputs:
0018 %
0019 %   - restim: Estimated image from the Curvelet coefficients.
0020 
0021 CR=cell(size(Mod));
0022 marker=0;
0023 
0024 for s=1:length(Mod)
0025    CR{s} = cell(size(Mod{s}));
0026    for w=1:length(Mod{s})
0027      m=Mod{s}{w}(1);
0028      n=Mod{s}{w}(2);
0029      CR{s}{w}=reshape(coef(marker+1:marker+(m*n)),m,n);
0030      marker=marker+m*n;
0031    end
0032 end
0033  
0034 % Apply adjoint curvelet transform
0035 restim = ifdct_usfft(CR,real);

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_div_op.html.svn-base000066400000000000000000000100711277570055300274360ustar00rootroot00000000000000 Description of sopt_mltb_div_op
Home > matlab > misc > sopt_mltb_div_op.m

sopt_mltb_div_op

PURPOSE ^

sopt_mltb_div_op - Compute divergence

SYNOPSIS ^

function I = sopt_mltb_div_op(dx, dy, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_div_op - Compute divergence

 Compute the divergence (adjoint of the gradient) of a two dimensional
 signal from the horizontal and vertical gradients.

 Inputs:

   - dx: Gradient in x.

   - dy: Gradient in y.

   - weights_dx: Weights in the x direction.

   - weights_dy: Weights in the y direction.

 Outputs:

   - I: Divergence.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function I = sopt_mltb_div_op(dx, dy, weights_dx, weights_dy)
0002 % sopt_mltb_div_op - Compute divergence
0003 %
0004 % Compute the divergence (adjoint of the gradient) of a two dimensional
0005 % signal from the horizontal and vertical gradients.
0006 %
0007 % Inputs:
0008 %
0009 %   - dx: Gradient in x.
0010 %
0011 %   - dy: Gradient in y.
0012 %
0013 %   - weights_dx: Weights in the x direction.
0014 %
0015 %   - weights_dy: Weights in the y direction.
0016 %
0017 % Outputs:
0018 %
0019 %   - I: Divergence.
0020 
0021 if nargin > 2
0022     dx = dx .* conj(weights_dx);
0023     dy = dy .* conj(weights_dy);
0024 end
0025 
0026 I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)];
0027 I = I + [dy(:, 1) , dy(:, 2:end-1)-dy(:, 1:end-2) , -dy(:, end-1)];
0028 
0029 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_div_op_sphere.html.svn-base000066400000000000000000000122041277570055300310040ustar00rootroot00000000000000 Description of sopt_mltb_div_op_sphere
Home > matlab > misc > sopt_mltb_div_op_sphere.m

sopt_mltb_div_op_sphere

PURPOSE ^

sopt_mltb_div_op_sphere - Compute divergence on sphere

SYNOPSIS ^

function I = sopt_mltb_div_op_sphere(dx, dy, includeNorthpole,weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_div_op_sphere - Compute divergence on sphere

 Compute the divergence (adjoint of the gradient) of a two dimensional
 signal on the sphere.  The phi direction (x) is periodic, while the theta
 direction (y) is not.

 Inputs:

   - dx: Gradient in x.

   - dy: Gradient in y.

   - includeNorthPole: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:

   - I: Divergence.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function I = sopt_mltb_div_op_sphere(dx, dy, includeNorthpole, ...
0002   weights_dx, weights_dy)
0003 % sopt_mltb_div_op_sphere - Compute divergence on sphere
0004 %
0005 % Compute the divergence (adjoint of the gradient) of a two dimensional
0006 % signal on the sphere.  The phi direction (x) is periodic, while the theta
0007 % direction (y) is not.
0008 %
0009 % Inputs:
0010 %
0011 %   - dx: Gradient in x.
0012 %
0013 %   - dy: Gradient in y.
0014 %
0015 %   - includeNorthPole: Flag indicating whether the North pole is included
0016 %       in the sampling grid (1 = North pole included, 0 = North pole not
0017 %       included).
0018 %
0019 %   - weights_dx: Weights in the x (phi) direction.
0020 %
0021 %   - weights_dy: Weights in the y (theta) direction.
0022 %
0023 % Outputs:
0024 %
0025 %   - I: Divergence.
0026 
0027 if nargin > 3
0028     dx = dx .* conj(weights_dx);
0029     dy = dy .* conj(weights_dy);
0030 end
0031 if(includeNorthpole)
0032     I = [zeros(1, size(dx,2)) ; dx(2, :); dx(3:end-1, :)-dx(2:end-2, :); -dx(end-1, :)];
0033     I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)];
0034 else
0035     I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)];
0036     I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)];
0037 end
0038 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_fwdcurvelet.html.svn-base000066400000000000000000000076621277570055300305240ustar00rootroot00000000000000 Description of sopt_mltb_fwdcurvelet
Home > matlab > misc > sopt_mltb_fwdcurvelet.m

sopt_mltb_fwdcurvelet

PURPOSE ^

sopt_mltb_fwdcurvelet - Forward curvelet transform

SYNOPSIS ^

function coef = sopt_mltb_fwdcurvelet(im,real)

DESCRIPTION ^

 sopt_mltb_fwdcurvelet - Forward curvelet transform

 Compute the forward curvelet transform of an image and stores it in
 vector coef.

 Inputs:

   - im: Input image.

   - real: Flag indicating if the transform is real or complex (1 = real,  
       0 = complex).

 Outputs:

   - coef: Curvelet coefficients.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function coef = sopt_mltb_fwdcurvelet(im,real)
0002 % sopt_mltb_fwdcurvelet - Forward curvelet transform
0003 %
0004 % Compute the forward curvelet transform of an image and stores it in
0005 % vector coef.
0006 %
0007 % Inputs:
0008 %
0009 %   - im: Input image.
0010 %
0011 %   - real: Flag indicating if the transform is real or complex (1 = real,
0012 %       0 = complex).
0013 %
0014 % Outputs:
0015 %
0016 %   - coef: Curvelet coefficients.
0017 
0018 C = fdct_usfft(im,real); 
0019 
0020 % Compute vector version of curvelets coeffcients
0021 coef = [];
0022 
0023 for s=1:length(C)
0024   for w=1:length(C{s})
0025     A = C{s}{w};
0026     coef= [coef; A(:)];
0027   end
0028 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_genmask.html.svn-base000066400000000000000000000076421277570055300276150ustar00rootroot00000000000000 Description of sopt_mltb_genmask
Home > matlab > misc > sopt_mltb_genmask.m

sopt_mltb_genmask

PURPOSE ^

sopt_mltb_genmask - Generate mask

SYNOPSIS ^

function mask = sopt_mltb_genmask(pdf, seed)

DESCRIPTION ^

 sopt_mltb_genmask - Generate mask

 Generate a binary mask with variable density sampling. It is used
 in sopt_mltb_vdsmask in the generation of variable density sampling
 profiles.

 Inputs:

   - pdf: Sampling profile function.

   - seed: Seed for the random number generator. Optional.

 Outputs:

   - mask: Binary mask.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function mask = sopt_mltb_genmask(pdf, seed)
0002 % sopt_mltb_genmask - Generate mask
0003 %
0004 % Generate a binary mask with variable density sampling. It is used
0005 % in sopt_mltb_vdsmask in the generation of variable density sampling
0006 % profiles.
0007 %
0008 % Inputs:
0009 %
0010 %   - pdf: Sampling profile function.
0011 %
0012 %   - seed: Seed for the random number generator. Optional.
0013 %
0014 % Outputs:
0015 %
0016 %   - mask: Binary mask.
0017 
0018 if nargin==2
0019     rand('seed', seed);
0020 end
0021 
0022 mask = rand(size(pdf))<pdf;
0023

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_gradient_op.html.svn-base000066400000000000000000000103021277570055300304460ustar00rootroot00000000000000 Description of sopt_mltb_gradient_op
Home > matlab > misc > sopt_mltb_gradient_op.m

sopt_mltb_gradient_op

PURPOSE ^

sopt_mltb_gradient_op - Compute gradient

SYNOPSIS ^

function [dx, dy] = sopt_mltb_gradient_op(I, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_gradient_op - Compute gradient

 Compute the gradient of a two dimensional signal.

 Inputs:

   - I: Input two dimesional signal.

   - weights_dx: Weights in the x direction.

   - weights_dy: Weights in the y direction.

 Outputs:
 
   - dx: Gradient in x direction.
 
   - dy: Gradient in y direction.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [dx, dy] = sopt_mltb_gradient_op(I, weights_dx, weights_dy)
0002 % sopt_mltb_gradient_op - Compute gradient
0003 %
0004 % Compute the gradient of a two dimensional signal.
0005 %
0006 % Inputs:
0007 %
0008 %   - I: Input two dimesional signal.
0009 %
0010 %   - weights_dx: Weights in the x direction.
0011 %
0012 %   - weights_dy: Weights in the y direction.
0013 %
0014 % Outputs:
0015 %
0016 %   - dx: Gradient in x direction.
0017 %
0018 %   - dy: Gradient in y direction.
0019 
0020 dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0021 dy = [I(:, 2:end)-I(:, 1:end-1) , zeros(size(I, 1), 1)];
0022 
0023 if nargin>1
0024     dx = dx .* weights_dx;
0025     dy = dy .* weights_dy;
0026 end
0027 
0028 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_gradient_op_sphere.html.svn-base000066400000000000000000000134101277570055300320170ustar00rootroot00000000000000 Description of sopt_mltb_gradient_op_sphere
Home > matlab > misc > sopt_mltb_gradient_op_sphere.m

sopt_mltb_gradient_op_sphere

PURPOSE ^

sopt_mltb_gradient_op_sphere - Compute gradient on sphere

SYNOPSIS ^

function [dx, dy] = sopt_mltb_gradient_op_sphere(I, includeNorthpole,weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_gradient_op_sphere - Compute gradient on sphere

 Compute the gradientof a signal on the sphere.  The phi direction (x) is
 periodic, while the theta direction (y) is not.

 Inputs:

   - I: Input two dimesional signal on the sphere.

   - includeNorthPole: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:
 
   - dx: Gradient in x (phi) direction.
 
   - dy: Gradient in y (theta) direction.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [dx, dy] = sopt_mltb_gradient_op_sphere(I, includeNorthpole, ...
0002   weights_dx, weights_dy)
0003 % sopt_mltb_gradient_op_sphere - Compute gradient on sphere
0004 %
0005 % Compute the gradientof a signal on the sphere.  The phi direction (x) is
0006 % periodic, while the theta direction (y) is not.
0007 %
0008 % Inputs:
0009 %
0010 %   - I: Input two dimesional signal on the sphere.
0011 %
0012 %   - includeNorthPole: Flag indicating whether the North pole is included
0013 %       in the sampling grid (1 = North pole included, 0 = North pole not
0014 %       included).
0015 %
0016 %   - weights_dx: Weights in the x (phi) direction.
0017 %
0018 %   - weights_dy: Weights in the y (theta) direction.
0019 %
0020 % Outputs:
0021 %
0022 %   - dx: Gradient in x (phi) direction.
0023 %
0024 %   - dy: Gradient in y (theta) direction.
0025 
0026 dx = zeros(size(I, 1),size(I, 2));
0027 I_big = zeros(size(I, 1)+2,size(I, 2));
0028 I_big(2:end-1, 1:end) = I;
0029 
0030 % Theta direction
0031 if(includeNorthpole)
0032     dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0033     dx(1,:) = zeros();
0034 else
0035     dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0036 end
0037 
0038 % Phi direction
0039 if(includeNorthpole)
0040     dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)];
0041 else
0042     dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)];
0043 end
0044 
0045 if nargin>2
0046     dx = dx .* weights_dx;
0047     dy = dy .* weights_dy;
0048 end
0049 
0050 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_modifypdf.html.svn-base000066400000000000000000000115671277570055300301520ustar00rootroot00000000000000 Description of sopt_mltb_modifypdf
Home > matlab > misc > sopt_mltb_modifypdf.m

sopt_mltb_modifypdf

PURPOSE ^

sopt_mltb_modifypdf - Modify PDF of sampling profile

SYNOPSIS ^

function [new_pdf, alpha] = sopt_mltb_modifypdf(pdf, nb_meas)

DESCRIPTION ^

 sopt_mltb_modifypdf - Modify PDF of sampling profile
 
 Checks PDF of the sampling profile and normalizes it. It is used
 in sopt_mltb_vdsmask in the generation of variable density sampling
 profiles.

 Inputs:

   - pdf: Sampling profile function.

   - nb_meas: Number of measurements.

 Outputs:

   - new_pdf: New sampling profile function.

   - alpha: DC level for the required number of samples.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [new_pdf, alpha] = sopt_mltb_modifypdf(pdf, nb_meas)
0002 % sopt_mltb_modifypdf - Modify PDF of sampling profile
0003 %
0004 % Checks PDF of the sampling profile and normalizes it. It is used
0005 % in sopt_mltb_vdsmask in the generation of variable density sampling
0006 % profiles.
0007 %
0008 % Inputs:
0009 %
0010 %   - pdf: Sampling profile function.
0011 %
0012 %   - nb_meas: Number of measurements.
0013 %
0014 % Outputs:
0015 %
0016 %   - new_pdf: New sampling profile function.
0017 %
0018 %   - alpha: DC level for the required number of samples.
0019 
0020 if sum(pdf(:)<0)>0
0021     error('PDF contains negative values');
0022 end
0023 pdf = pdf/max(pdf(:));
0024 
0025 % Find alpha
0026 alpha_min = -1; alpha_max = 1;
0027 while 1
0028     alpha = (alpha_min + alpha_max)/2;
0029     new_pdf = pdf + alpha;
0030     new_pdf(new_pdf>1) = 1; new_pdf(new_pdf<0) = 0;
0031     M = round(sum(new_pdf(:)));
0032     if M > nb_meas
0033         alpha_max = alpha;
0034     elseif M < nb_meas
0035         alpha_min = alpha;
0036     else
0037         break;
0038     end
0039 end
0040

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_struct2size.html.svn-base000066400000000000000000000073521277570055300304670ustar00rootroot00000000000000 Description of sopt_mltb_struct2size
Home > matlab > misc > sopt_mltb_struct2size.m

sopt_mltb_struct2size

PURPOSE ^

sopt_mltb_struct2size - Compute curvelet data structure

SYNOPSIS ^

function Mod = sopt_mltb_struct2size(C)

DESCRIPTION ^

sopt_mltb_struct2size - Compute curvelet data structure

 Compute data structure to store the sizes of the curvelet transform 
 generated from the CurveLab toolbox.

 Inputs:

   - C: Curvelet coefficients arranged in the original format.

 Outputs:

   - Mod: Data structure with the appropiate sizes.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function Mod = sopt_mltb_struct2size(C)
0002 %sopt_mltb_struct2size - Compute curvelet data structure
0003 %
0004 % Compute data structure to store the sizes of the curvelet transform
0005 % generated from the CurveLab toolbox.
0006 %
0007 % Inputs:
0008 %
0009 %   - C: Curvelet coefficients arranged in the original format.
0010 %
0011 % Outputs:
0012 %
0013 %   - Mod: Data structure with the appropiate sizes.
0014 
0015  Mod=cell(size(C));
0016  for s=1:length(C)
0017    Mod{s} = cell(size(C{s}));
0018    for w=1:length(C{s})
0019      [m,n]=size(C{s}{w});
0020      Mod{s}{w}=[m,n];
0021    end
0022  end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/.svn/text-base/sopt_mltb_vdsmask.html.svn-base000066400000000000000000000142551277570055300276360ustar00rootroot00000000000000 Description of sopt_mltb_vdsmask
Home > matlab > misc > sopt_mltb_vdsmask.m

sopt_mltb_vdsmask

PURPOSE ^

sopt_mltb_vdsmask - Create variable density sampling profile

SYNOPSIS ^

function mask = sopt_mltb_vdsmask(N,M,p)

DESCRIPTION ^

 sopt_mltb_vdsmask - Create variable density sampling profile

 Creates a binary mask generated from a variable density sampling 
 profile for two dimensional images in the frequency domain.   The mask 
 contains on average p*N*M ones's.

 Inputs:

   - N and M: Size of mask.

   - p: Coverage percentage.

 Note: The undersampling ratio is passed as 2*p and then the function
 only takes samples in half plane to account for signal reality. The range
 of p is 0 < p <= 0.5.

 Outputs:

   - mask: Binary mask with the sampling profile in the frequency domain.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function mask = sopt_mltb_vdsmask(N,M,p)
0002 % sopt_mltb_vdsmask - Create variable density sampling profile
0003 %
0004 % Creates a binary mask generated from a variable density sampling
0005 % profile for two dimensional images in the frequency domain.   The mask
0006 % contains on average p*N*M ones's.
0007 %
0008 % Inputs:
0009 %
0010 %   - N and M: Size of mask.
0011 %
0012 %   - p: Coverage percentage.
0013 %
0014 % Note: The undersampling ratio is passed as 2*p and then the function
0015 % only takes samples in half plane to account for signal reality. The range
0016 % of p is 0 < p <= 0.5.
0017 %
0018 % Outputs:
0019 %
0020 %   - mask: Binary mask with the sampling profile in the frequency domain.
0021 
0022 p = 2*p;
0023 
0024 if p==1
0025     mask=ones(N,M);
0026 else
0027     
0028     nb_meas=round(p*N*M);
0029     tol=ceil(p*N*M)-floor(p*N*M);
0030     d=1;
0031 
0032     [x,y] = meshgrid(linspace(-1, 1, M), linspace(-1, 1, N)); % Cartesian grid
0033     r = sqrt(x.^2+y.^2); r = r/max(r(:)); % Polar grid
0034 
0035     alpha=-1;
0036     it=0;
0037     maxit=20;
0038     while (alpha<-0.01 || alpha>0.01) && it<maxit
0039         pdf = (1-r).^d;
0040         [new_pdf,alpha] = sopt_mltb_modifypdf(pdf, nb_meas);
0041         if alpha<0
0042             d=d+0.1;
0043         else
0044             d=d-0.1;
0045         end
0046         it=it+1;
0047     end
0048 
0049     mask = zeros(size(new_pdf));
0050     while sum(mask(:))>nb_meas+tol || sum(mask(:))<nb_meas-tol
0051         mask = sopt_mltb_genmask(new_pdf);
0052     end
0053 
0054 end
0055 
0056 %Samples in half plane to account for signal reality.
0057 M1=floor(M/2);
0058 mask(:,1:M1)=0;
0059 mask = ifftshift(mask);
0060 
0061 N1=floor(N/2);
0062 mask(N1+1:N,1)=0;
0063

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/index.html000066400000000000000000000066051277570055300207150ustar00rootroot00000000000000 Index for Directory matlab/misc
< Master index Index for matlab/misc >

Index for matlab/misc

Matlab files in this directory:

 sopt_mltb_SNRSNR - Compute the SNR between two images
 sopt_mltb_TV_normsopt_mltb_TV_norm - Compute TV norm
 sopt_mltb_adjcurveletsopt_mltb_adjcurvelet - Adjoint curvelet transform
 sopt_mltb_div_opsopt_mltb_div_op - Compute divergence
 sopt_mltb_div_op_spheresopt_mltb_div_op_sphere - Compute divergence on sphere
 sopt_mltb_fwdcurveletsopt_mltb_fwdcurvelet - Forward curvelet transform
 sopt_mltb_genmasksopt_mltb_genmask - Generate mask
 sopt_mltb_gradient_opsopt_mltb_gradient_op - Compute gradient
 sopt_mltb_gradient_op_spheresopt_mltb_gradient_op_sphere - Compute gradient on sphere
 sopt_mltb_modifypdfsopt_mltb_modifypdf - Modify PDF of sampling profile
 sopt_mltb_struct2sizesopt_mltb_struct2size - Compute curvelet data structure
 sopt_mltb_vdsmasksopt_mltb_vdsmask - Create variable density sampling profile

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_SNR.html000066400000000000000000000076071277570055300223360ustar00rootroot00000000000000 Description of sopt_mltb_SNR
Home > matlab > misc > sopt_mltb_SNR.m

sopt_mltb_SNR

PURPOSE ^

SNR - Compute the SNR between two images

SYNOPSIS ^

function snr = sopt_mltb_SNR(map_init, map_recon)

DESCRIPTION ^

 SNR - Compute the SNR between two images
 
 C omputes the SNR between the maps map_init and map_recon.  The SNR is 
 computed by
    10 * log10( var(MAP_INIT) / var(MAP_INIT-MAP_NOISY) )
  where var stands for the matlab built-in function that computes the
  variance.

 Inputs:

   - map_init: Initial image.

   - map_recon: Reconstructed image.

 Outputs:

   - snr: SNR.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function snr = sopt_mltb_SNR(map_init, map_recon)
0002 % SNR - Compute the SNR between two images
0003 %
0004 % C omputes the SNR between the maps map_init and map_recon.  The SNR is
0005 % computed by
0006 %    10 * log10( var(MAP_INIT) / var(MAP_INIT-MAP_NOISY) )
0007 %  where var stands for the matlab built-in function that computes the
0008 %  variance.
0009 %
0010 % Inputs:
0011 %
0012 %   - map_init: Initial image.
0013 %
0014 %   - map_recon: Reconstructed image.
0015 %
0016 % Outputs:
0017 %
0018 %   - snr: SNR.
0019 
0020 noise = map_init(:)-map_recon(:);
0021 var_init = var(map_init(:));
0022 var_den = var(noise(:));
0023 snr = 10 * log10(var_init/var_den);
0024 
0025 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_TV_norm.html000066400000000000000000000141741277570055300232550ustar00rootroot00000000000000 Description of sopt_mltb_TV_norm
Home > matlab > misc > sopt_mltb_TV_norm.m

sopt_mltb_TV_norm

PURPOSE ^

sopt_mltb_TV_norm - Compute TV norm

SYNOPSIS ^

function y = sopt_mltb_TV_norm(u, sphere_flag,incNP, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_TV_norm - Compute TV norm

 Compute the TV of an image on the plane or sphere.

 Inputs:

   - u: Image to compute TV norm of.

   - sphere_flag: Flag indicating whether to compute the TV norm on the
       sphere (1 = on sphere, 2 = on plane).

   - includeNP: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:

   - y: TV norm of image.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function y = sopt_mltb_TV_norm(u, sphere_flag, ...
0002     incNP, weights_dx, weights_dy)
0003 % sopt_mltb_TV_norm - Compute TV norm
0004 %
0005 % Compute the TV of an image on the plane or sphere.
0006 %
0007 % Inputs:
0008 %
0009 %   - u: Image to compute TV norm of.
0010 %
0011 %   - sphere_flag: Flag indicating whether to compute the TV norm on the
0012 %       sphere (1 = on sphere, 2 = on plane).
0013 %
0014 %   - includeNP: Flag indicating whether the North pole is included
0015 %       in the sampling grid (1 = North pole included, 0 = North pole not
0016 %       included).
0017 %
0018 %   - weights_dx: Weights in the x (phi) direction.
0019 %
0020 %   - weights_dy: Weights in the y (theta) direction.
0021 %
0022 % Outputs:
0023 %
0024 %   - y: TV norm of image.
0025 
0026 if sphere_flag
0027     if nargin>3 
0028         [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP, weights_dx, weights_dy);
0029     else
0030         [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP);
0031     end
0032 else
0033     if nargin>3 
0034         [dx, dy] = sopt_mltb_gradient_op(u, weights_dx, weights_dy);
0035     else
0036         [dx, dy] = sopt_mltb_gradient_op(u);
0037     end
0038 end
0039 temp = sqrt(abs(dx).^2 + abs(dy).^2);
0040 y = sum(temp(:));
0041 
0042 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_adjcurvelet.html000066400000000000000000000110061277570055300241700ustar00rootroot00000000000000 Description of sopt_mltb_adjcurvelet
Home > matlab > misc > sopt_mltb_adjcurvelet.m

sopt_mltb_adjcurvelet

PURPOSE ^

sopt_mltb_adjcurvelet - Adjoint curvelet transform

SYNOPSIS ^

function restim = sopt_mltb_adjcurvelet(coef, Mod, real)

DESCRIPTION ^

 sopt_mltb_adjcurvelet - Adjoint curvelet transform

 Compute the adjoint curvelet transform from the curvelet
 coefficient vector.

 Inputs:

   - coef: Input curvelet coefficient vector.

   - Mod: Data structure that stores sizes of the curvelet transform 
       generated from the CurveLab toolbox.

   - real: Flag indicating if the transform is real or complex (1 = real,  
       0 = complex).

 Outputs:

   - restim: Estimated image from the Curvelet coefficients.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function restim = sopt_mltb_adjcurvelet(coef, Mod, real)
0002 % sopt_mltb_adjcurvelet - Adjoint curvelet transform
0003 %
0004 % Compute the adjoint curvelet transform from the curvelet
0005 % coefficient vector.
0006 %
0007 % Inputs:
0008 %
0009 %   - coef: Input curvelet coefficient vector.
0010 %
0011 %   - Mod: Data structure that stores sizes of the curvelet transform
0012 %       generated from the CurveLab toolbox.
0013 %
0014 %   - real: Flag indicating if the transform is real or complex (1 = real,
0015 %       0 = complex).
0016 %
0017 % Outputs:
0018 %
0019 %   - restim: Estimated image from the Curvelet coefficients.
0020 
0021 CR=cell(size(Mod));
0022 marker=0;
0023 
0024 for s=1:length(Mod)
0025    CR{s} = cell(size(Mod{s}));
0026    for w=1:length(Mod{s})
0027      m=Mod{s}{w}(1);
0028      n=Mod{s}{w}(2);
0029      CR{s}{w}=reshape(coef(marker+1:marker+(m*n)),m,n);
0030      marker=marker+m*n;
0031    end
0032 end
0033  
0034 % Apply adjoint curvelet transform
0035 restim = ifdct_usfft(CR,real);

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_div_op.html000066400000000000000000000100711277570055300231410ustar00rootroot00000000000000 Description of sopt_mltb_div_op
Home > matlab > misc > sopt_mltb_div_op.m

sopt_mltb_div_op

PURPOSE ^

sopt_mltb_div_op - Compute divergence

SYNOPSIS ^

function I = sopt_mltb_div_op(dx, dy, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_div_op - Compute divergence

 Compute the divergence (adjoint of the gradient) of a two dimensional
 signal from the horizontal and vertical gradients.

 Inputs:

   - dx: Gradient in x.

   - dy: Gradient in y.

   - weights_dx: Weights in the x direction.

   - weights_dy: Weights in the y direction.

 Outputs:

   - I: Divergence.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function I = sopt_mltb_div_op(dx, dy, weights_dx, weights_dy)
0002 % sopt_mltb_div_op - Compute divergence
0003 %
0004 % Compute the divergence (adjoint of the gradient) of a two dimensional
0005 % signal from the horizontal and vertical gradients.
0006 %
0007 % Inputs:
0008 %
0009 %   - dx: Gradient in x.
0010 %
0011 %   - dy: Gradient in y.
0012 %
0013 %   - weights_dx: Weights in the x direction.
0014 %
0015 %   - weights_dy: Weights in the y direction.
0016 %
0017 % Outputs:
0018 %
0019 %   - I: Divergence.
0020 
0021 if nargin > 2
0022     dx = dx .* conj(weights_dx);
0023     dy = dy .* conj(weights_dy);
0024 end
0025 
0026 I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)];
0027 I = I + [dy(:, 1) , dy(:, 2:end-1)-dy(:, 1:end-2) , -dy(:, end-1)];
0028 
0029 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_div_op_sphere.html000066400000000000000000000122041277570055300245070ustar00rootroot00000000000000 Description of sopt_mltb_div_op_sphere
Home > matlab > misc > sopt_mltb_div_op_sphere.m

sopt_mltb_div_op_sphere

PURPOSE ^

sopt_mltb_div_op_sphere - Compute divergence on sphere

SYNOPSIS ^

function I = sopt_mltb_div_op_sphere(dx, dy, includeNorthpole,weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_div_op_sphere - Compute divergence on sphere

 Compute the divergence (adjoint of the gradient) of a two dimensional
 signal on the sphere.  The phi direction (x) is periodic, while the theta
 direction (y) is not.

 Inputs:

   - dx: Gradient in x.

   - dy: Gradient in y.

   - includeNorthPole: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:

   - I: Divergence.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function I = sopt_mltb_div_op_sphere(dx, dy, includeNorthpole, ...
0002   weights_dx, weights_dy)
0003 % sopt_mltb_div_op_sphere - Compute divergence on sphere
0004 %
0005 % Compute the divergence (adjoint of the gradient) of a two dimensional
0006 % signal on the sphere.  The phi direction (x) is periodic, while the theta
0007 % direction (y) is not.
0008 %
0009 % Inputs:
0010 %
0011 %   - dx: Gradient in x.
0012 %
0013 %   - dy: Gradient in y.
0014 %
0015 %   - includeNorthPole: Flag indicating whether the North pole is included
0016 %       in the sampling grid (1 = North pole included, 0 = North pole not
0017 %       included).
0018 %
0019 %   - weights_dx: Weights in the x (phi) direction.
0020 %
0021 %   - weights_dy: Weights in the y (theta) direction.
0022 %
0023 % Outputs:
0024 %
0025 %   - I: Divergence.
0026 
0027 if nargin > 3
0028     dx = dx .* conj(weights_dx);
0029     dy = dy .* conj(weights_dy);
0030 end
0031 if(includeNorthpole)
0032     I = [zeros(1, size(dx,2)) ; dx(2, :); dx(3:end-1, :)-dx(2:end-2, :); -dx(end-1, :)];
0033     I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)];
0034 else
0035     I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)];
0036     I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)];
0037 end
0038 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_fwdcurvelet.html000066400000000000000000000076621277570055300242270ustar00rootroot00000000000000 Description of sopt_mltb_fwdcurvelet
Home > matlab > misc > sopt_mltb_fwdcurvelet.m

sopt_mltb_fwdcurvelet

PURPOSE ^

sopt_mltb_fwdcurvelet - Forward curvelet transform

SYNOPSIS ^

function coef = sopt_mltb_fwdcurvelet(im,real)

DESCRIPTION ^

 sopt_mltb_fwdcurvelet - Forward curvelet transform

 Compute the forward curvelet transform of an image and stores it in
 vector coef.

 Inputs:

   - im: Input image.

   - real: Flag indicating if the transform is real or complex (1 = real,  
       0 = complex).

 Outputs:

   - coef: Curvelet coefficients.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function coef = sopt_mltb_fwdcurvelet(im,real)
0002 % sopt_mltb_fwdcurvelet - Forward curvelet transform
0003 %
0004 % Compute the forward curvelet transform of an image and stores it in
0005 % vector coef.
0006 %
0007 % Inputs:
0008 %
0009 %   - im: Input image.
0010 %
0011 %   - real: Flag indicating if the transform is real or complex (1 = real,
0012 %       0 = complex).
0013 %
0014 % Outputs:
0015 %
0016 %   - coef: Curvelet coefficients.
0017 
0018 C = fdct_usfft(im,real); 
0019 
0020 % Compute vector version of curvelets coeffcients
0021 coef = [];
0022 
0023 for s=1:length(C)
0024   for w=1:length(C{s})
0025     A = C{s}{w};
0026     coef= [coef; A(:)];
0027   end
0028 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_genmask.html000066400000000000000000000076421277570055300233200ustar00rootroot00000000000000 Description of sopt_mltb_genmask
Home > matlab > misc > sopt_mltb_genmask.m

sopt_mltb_genmask

PURPOSE ^

sopt_mltb_genmask - Generate mask

SYNOPSIS ^

function mask = sopt_mltb_genmask(pdf, seed)

DESCRIPTION ^

 sopt_mltb_genmask - Generate mask

 Generate a binary mask with variable density sampling. It is used
 in sopt_mltb_vdsmask in the generation of variable density sampling
 profiles.

 Inputs:

   - pdf: Sampling profile function.

   - seed: Seed for the random number generator. Optional.

 Outputs:

   - mask: Binary mask.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function mask = sopt_mltb_genmask(pdf, seed)
0002 % sopt_mltb_genmask - Generate mask
0003 %
0004 % Generate a binary mask with variable density sampling. It is used
0005 % in sopt_mltb_vdsmask in the generation of variable density sampling
0006 % profiles.
0007 %
0008 % Inputs:
0009 %
0010 %   - pdf: Sampling profile function.
0011 %
0012 %   - seed: Seed for the random number generator. Optional.
0013 %
0014 % Outputs:
0015 %
0016 %   - mask: Binary mask.
0017 
0018 if nargin==2
0019     rand('seed', seed);
0020 end
0021 
0022 mask = rand(size(pdf))<pdf;
0023

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_gradient_op.html000066400000000000000000000103021277570055300241510ustar00rootroot00000000000000 Description of sopt_mltb_gradient_op
Home > matlab > misc > sopt_mltb_gradient_op.m

sopt_mltb_gradient_op

PURPOSE ^

sopt_mltb_gradient_op - Compute gradient

SYNOPSIS ^

function [dx, dy] = sopt_mltb_gradient_op(I, weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_gradient_op - Compute gradient

 Compute the gradient of a two dimensional signal.

 Inputs:

   - I: Input two dimesional signal.

   - weights_dx: Weights in the x direction.

   - weights_dy: Weights in the y direction.

 Outputs:
 
   - dx: Gradient in x direction.
 
   - dy: Gradient in y direction.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [dx, dy] = sopt_mltb_gradient_op(I, weights_dx, weights_dy)
0002 % sopt_mltb_gradient_op - Compute gradient
0003 %
0004 % Compute the gradient of a two dimensional signal.
0005 %
0006 % Inputs:
0007 %
0008 %   - I: Input two dimesional signal.
0009 %
0010 %   - weights_dx: Weights in the x direction.
0011 %
0012 %   - weights_dy: Weights in the y direction.
0013 %
0014 % Outputs:
0015 %
0016 %   - dx: Gradient in x direction.
0017 %
0018 %   - dy: Gradient in y direction.
0019 
0020 dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0021 dy = [I(:, 2:end)-I(:, 1:end-1) , zeros(size(I, 1), 1)];
0022 
0023 if nargin>1
0024     dx = dx .* weights_dx;
0025     dy = dy .* weights_dy;
0026 end
0027 
0028 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_gradient_op_sphere.html000066400000000000000000000134101277570055300255220ustar00rootroot00000000000000 Description of sopt_mltb_gradient_op_sphere
Home > matlab > misc > sopt_mltb_gradient_op_sphere.m

sopt_mltb_gradient_op_sphere

PURPOSE ^

sopt_mltb_gradient_op_sphere - Compute gradient on sphere

SYNOPSIS ^

function [dx, dy] = sopt_mltb_gradient_op_sphere(I, includeNorthpole,weights_dx, weights_dy)

DESCRIPTION ^

 sopt_mltb_gradient_op_sphere - Compute gradient on sphere

 Compute the gradientof a signal on the sphere.  The phi direction (x) is
 periodic, while the theta direction (y) is not.

 Inputs:

   - I: Input two dimesional signal on the sphere.

   - includeNorthPole: Flag indicating whether the North pole is included
       in the sampling grid (1 = North pole included, 0 = North pole not
       included).

   - weights_dx: Weights in the x (phi) direction.

   - weights_dy: Weights in the y (theta) direction.

 Outputs:
 
   - dx: Gradient in x (phi) direction.
 
   - dy: Gradient in y (theta) direction.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [dx, dy] = sopt_mltb_gradient_op_sphere(I, includeNorthpole, ...
0002   weights_dx, weights_dy)
0003 % sopt_mltb_gradient_op_sphere - Compute gradient on sphere
0004 %
0005 % Compute the gradientof a signal on the sphere.  The phi direction (x) is
0006 % periodic, while the theta direction (y) is not.
0007 %
0008 % Inputs:
0009 %
0010 %   - I: Input two dimesional signal on the sphere.
0011 %
0012 %   - includeNorthPole: Flag indicating whether the North pole is included
0013 %       in the sampling grid (1 = North pole included, 0 = North pole not
0014 %       included).
0015 %
0016 %   - weights_dx: Weights in the x (phi) direction.
0017 %
0018 %   - weights_dy: Weights in the y (theta) direction.
0019 %
0020 % Outputs:
0021 %
0022 %   - dx: Gradient in x (phi) direction.
0023 %
0024 %   - dy: Gradient in y (theta) direction.
0025 
0026 dx = zeros(size(I, 1),size(I, 2));
0027 I_big = zeros(size(I, 1)+2,size(I, 2));
0028 I_big(2:end-1, 1:end) = I;
0029 
0030 % Theta direction
0031 if(includeNorthpole)
0032     dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0033     dx(1,:) = zeros();
0034 else
0035     dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))];
0036 end
0037 
0038 % Phi direction
0039 if(includeNorthpole)
0040     dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)];
0041 else
0042     dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)];
0043 end
0044 
0045 if nargin>2
0046     dx = dx .* weights_dx;
0047     dy = dy .* weights_dy;
0048 end
0049 
0050 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_modifypdf.html000066400000000000000000000115671277570055300236550ustar00rootroot00000000000000 Description of sopt_mltb_modifypdf
Home > matlab > misc > sopt_mltb_modifypdf.m

sopt_mltb_modifypdf

PURPOSE ^

sopt_mltb_modifypdf - Modify PDF of sampling profile

SYNOPSIS ^

function [new_pdf, alpha] = sopt_mltb_modifypdf(pdf, nb_meas)

DESCRIPTION ^

 sopt_mltb_modifypdf - Modify PDF of sampling profile
 
 Checks PDF of the sampling profile and normalizes it. It is used
 in sopt_mltb_vdsmask in the generation of variable density sampling
 profiles.

 Inputs:

   - pdf: Sampling profile function.

   - nb_meas: Number of measurements.

 Outputs:

   - new_pdf: New sampling profile function.

   - alpha: DC level for the required number of samples.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [new_pdf, alpha] = sopt_mltb_modifypdf(pdf, nb_meas)
0002 % sopt_mltb_modifypdf - Modify PDF of sampling profile
0003 %
0004 % Checks PDF of the sampling profile and normalizes it. It is used
0005 % in sopt_mltb_vdsmask in the generation of variable density sampling
0006 % profiles.
0007 %
0008 % Inputs:
0009 %
0010 %   - pdf: Sampling profile function.
0011 %
0012 %   - nb_meas: Number of measurements.
0013 %
0014 % Outputs:
0015 %
0016 %   - new_pdf: New sampling profile function.
0017 %
0018 %   - alpha: DC level for the required number of samples.
0019 
0020 if sum(pdf(:)<0)>0
0021     error('PDF contains negative values');
0022 end
0023 pdf = pdf/max(pdf(:));
0024 
0025 % Find alpha
0026 alpha_min = -1; alpha_max = 1;
0027 while 1
0028     alpha = (alpha_min + alpha_max)/2;
0029     new_pdf = pdf + alpha;
0030     new_pdf(new_pdf>1) = 1; new_pdf(new_pdf<0) = 0;
0031     M = round(sum(new_pdf(:)));
0032     if M > nb_meas
0033         alpha_max = alpha;
0034     elseif M < nb_meas
0035         alpha_min = alpha;
0036     else
0037         break;
0038     end
0039 end
0040

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_struct2size.html000066400000000000000000000073521277570055300241720ustar00rootroot00000000000000 Description of sopt_mltb_struct2size
Home > matlab > misc > sopt_mltb_struct2size.m

sopt_mltb_struct2size

PURPOSE ^

sopt_mltb_struct2size - Compute curvelet data structure

SYNOPSIS ^

function Mod = sopt_mltb_struct2size(C)

DESCRIPTION ^

sopt_mltb_struct2size - Compute curvelet data structure

 Compute data structure to store the sizes of the curvelet transform 
 generated from the CurveLab toolbox.

 Inputs:

   - C: Curvelet coefficients arranged in the original format.

 Outputs:

   - Mod: Data structure with the appropiate sizes.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function Mod = sopt_mltb_struct2size(C)
0002 %sopt_mltb_struct2size - Compute curvelet data structure
0003 %
0004 % Compute data structure to store the sizes of the curvelet transform
0005 % generated from the CurveLab toolbox.
0006 %
0007 % Inputs:
0008 %
0009 %   - C: Curvelet coefficients arranged in the original format.
0010 %
0011 % Outputs:
0012 %
0013 %   - Mod: Data structure with the appropiate sizes.
0014 
0015  Mod=cell(size(C));
0016  for s=1:length(C)
0017    Mod{s} = cell(size(C{s}));
0018    for w=1:length(C{s})
0019      [m,n]=size(C{s}{w});
0020      Mod{s}{w}=[m,n];
0021    end
0022  end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/misc/sopt_mltb_vdsmask.html000066400000000000000000000142551277570055300233410ustar00rootroot00000000000000 Description of sopt_mltb_vdsmask
Home > matlab > misc > sopt_mltb_vdsmask.m

sopt_mltb_vdsmask

PURPOSE ^

sopt_mltb_vdsmask - Create variable density sampling profile

SYNOPSIS ^

function mask = sopt_mltb_vdsmask(N,M,p)

DESCRIPTION ^

 sopt_mltb_vdsmask - Create variable density sampling profile

 Creates a binary mask generated from a variable density sampling 
 profile for two dimensional images in the frequency domain.   The mask 
 contains on average p*N*M ones's.

 Inputs:

   - N and M: Size of mask.

   - p: Coverage percentage.

 Note: The undersampling ratio is passed as 2*p and then the function
 only takes samples in half plane to account for signal reality. The range
 of p is 0 < p <= 0.5.

 Outputs:

   - mask: Binary mask with the sampling profile in the frequency domain.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function mask = sopt_mltb_vdsmask(N,M,p)
0002 % sopt_mltb_vdsmask - Create variable density sampling profile
0003 %
0004 % Creates a binary mask generated from a variable density sampling
0005 % profile for two dimensional images in the frequency domain.   The mask
0006 % contains on average p*N*M ones's.
0007 %
0008 % Inputs:
0009 %
0010 %   - N and M: Size of mask.
0011 %
0012 %   - p: Coverage percentage.
0013 %
0014 % Note: The undersampling ratio is passed as 2*p and then the function
0015 % only takes samples in half plane to account for signal reality. The range
0016 % of p is 0 < p <= 0.5.
0017 %
0018 % Outputs:
0019 %
0020 %   - mask: Binary mask with the sampling profile in the frequency domain.
0021 
0022 p = 2*p;
0023 
0024 if p==1
0025     mask=ones(N,M);
0026 else
0027     
0028     nb_meas=round(p*N*M);
0029     tol=ceil(p*N*M)-floor(p*N*M);
0030     d=1;
0031 
0032     [x,y] = meshgrid(linspace(-1, 1, M), linspace(-1, 1, N)); % Cartesian grid
0033     r = sqrt(x.^2+y.^2); r = r/max(r(:)); % Polar grid
0034 
0035     alpha=-1;
0036     it=0;
0037     maxit=20;
0038     while (alpha<-0.01 || alpha>0.01) && it<maxit
0039         pdf = (1-r).^d;
0040         [new_pdf,alpha] = sopt_mltb_modifypdf(pdf, nb_meas);
0041         if alpha<0
0042             d=d+0.1;
0043         else
0044             d=d-0.1;
0045         end
0046         it=it+1;
0047     end
0048 
0049     mask = zeros(size(new_pdf));
0050     while sum(mask(:))>nb_meas+tol || sum(mask(:))<nb_meas-tol
0051         mask = sopt_mltb_genmask(new_pdf);
0052     end
0053 
0054 end
0055 
0056 %Samples in half plane to account for signal reality.
0057 M1=floor(M/2);
0058 mask(:,1:M1)=0;
0059 mask = ifftshift(mask);
0060 
0061 N1=floor(N/2);
0062 mask(N1+1:N,1)=0;
0063

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/000077500000000000000000000000001277570055300210445ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/000077500000000000000000000000001277570055300217305ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/all-wcprops000066400000000000000000000017241277570055300241220ustar00rootroot00000000000000K 25 svn:wc:ra_dav:version-url V 61 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators END sopt_mltb_fast_proj_B2.html K 25 svn:wc:ra_dav:version-url V 89 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/sopt_mltb_fast_proj_B2.html END sopt_mltb_proj_B2.html K 25 svn:wc:ra_dav:version-url V 84 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/sopt_mltb_proj_B2.html END sopt_mltb_prox_TV.html K 25 svn:wc:ra_dav:version-url V 84 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/sopt_mltb_prox_TV.html END sopt_mltb_prox_TVoA.html K 25 svn:wc:ra_dav:version-url V 86 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/sopt_mltb_prox_TVoA.html END index.html K 25 svn:wc:ra_dav:version-url V 72 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/index.html END sopt_mltb_prox_L1.html K 25 svn:wc:ra_dav:version-url V 84 /svn/sopt/!svn/ver/231/trunk/matlab/doc/matlab/prox_operators/sopt_mltb_prox_L1.html END sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/entries000066400000000000000000000023731277570055300233310ustar00rootroot0000000000000010 dir 238 https://svn.epfl.ch/svn/sopt/trunk/matlab/doc/matlab/prox_operators https://svn.epfl.ch/svn/sopt 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 970ed402-9328-4b70-8940-a90ce832aee1 sopt_mltb_fast_proj_B2.html file 2013-02-22T16:01:55.000000Z 551dc363a55150eb0c4d685ee8010c3b 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 14279 sopt_mltb_proj_B2.html file 2013-02-22T16:01:55.000000Z 65400f4cb7f858f4df6bef14d7ed901d 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 11973 sopt_mltb_prox_TV.html file 2013-02-22T16:01:55.000000Z 8534523b89ac7301aaff5d753adbdeaa 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 8254 sopt_mltb_prox_TVoA.html file 2013-02-22T16:01:55.000000Z 335d9c688ad0668db6b94bdb901e4214 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 12711 index.html file 2013-02-22T16:01:55.000000Z f27e1c90313ec5d05ba5b26011339580 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 2207 sopt_mltb_prox_L1.html file 2013-02-22T16:01:55.000000Z cef6f99e1978276c3a16b5f418512371 2013-02-22T15:55:11.317825Z 231 jason.mcewen@ucl.ac.uk 11948 sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/000077500000000000000000000000001277570055300236245ustar00rootroot00000000000000sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/index.html.svn-base000066400000000000000000000042371277570055300273440ustar00rootroot00000000000000 Index for Directory matlab/prox_operators
< Master index Index for matlab/prox_operators >

Index for matlab/prox_operators

Matlab files in this directory:

 sopt_mltb_fast_proj_B2sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball
 sopt_mltb_proj_B2sopt_mltb_proj_B2 - Projection onto L2-ball
 sopt_mltb_prox_L1sopt_mltb_prox_L1 - Proximal operator with L1 norm
 sopt_mltb_prox_TVsopt_mltb_prox_TV - Total variation proximal operator
 sopt_mltb_prox_TVoAsopt_mltb_prox_TVoA - Agumented total variation proximal operator

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/sopt_mltb_fast_proj_B2.html.svn-base000066400000000000000000000337071277570055300326360ustar00rootroot00000000000000 Description of sopt_mltb_fast_proj_B2
Home > matlab > prox_operators > sopt_mltb_fast_proj_B2.m

sopt_mltb_fast_proj_B2

PURPOSE ^

sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball

SYNOPSIS ^

function [sol, u] = sopt_mltb_fast_proj_B2(x, param)

DESCRIPTION ^

 sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball

 Compute the projection onto the L2 ball, i.e. solve

   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon

 where x is the input vector and the solution z* is returned as sol.
 The structure param should contain the following fields:

   - y: Measurements (default = 0).

   - A: Forward operator (default = Identity).

   - At: Adjoint operator (default = Identity).

   - epsilon: Radius of the L2 ball (default = 1e-3).

   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter: Maximum number of iterations (default: 200).

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - u: Initial vector for the dual problem, same dimension as y
       (default = 0).
   
   - pos: Positivity flag (1 = positive solution,
       0 general complex case; default = 0).

   - real: Reality flag (1 = real solution,
       0 = general complex case; default = 0).

 Outputs:

   - sol: Final solution.

   - u: Final dual vector.

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
 optimization problems in sparse recovery" , IEEE ICIP, Cairo,
 Egypt, 2009.
 [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
 Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
 2 (2009), no. 1, 183--202.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [sol, u] = sopt_mltb_fast_proj_B2(x, param)
0002 % sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball
0003 %
0004 % Compute the projection onto the L2 ball, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - y: Measurements (default = 0).
0012 %
0013 %   - A: Forward operator (default = Identity).
0014 %
0015 %   - At: Adjoint operator (default = Identity).
0016 %
0017 %   - epsilon: Radius of the L2 ball (default = 1e-3).
0018 %
0019 %   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).
0020 %
0021 %   - nu: Bound on the norm^2 of the operator A, i.e.
0022 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0023 %
0024 %   - tol: Tolerance for the projection onto the L2 ball. The algorithms
0025 %       stops if
0026 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0027 %       (default = 1e-3).
0028 %
0029 %   - max_iter: Maximum number of iterations (default: 200).
0030 %
0031 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0032 %       2 = print main steps; default = 1).
0033 %
0034 %   - u: Initial vector for the dual problem, same dimension as y
0035 %       (default = 0).
0036 %
0037 %   - pos: Positivity flag (1 = positive solution,
0038 %       0 general complex case; default = 0).
0039 %
0040 %   - real: Reality flag (1 = real solution,
0041 %       0 = general complex case; default = 0).
0042 %
0043 % Outputs:
0044 %
0045 %   - sol: Final solution.
0046 %
0047 %   - u: Final dual vector.
0048 %
0049 % References:
0050 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0051 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0052 % Egypt, 2009.
0053 % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
0054 % Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
0055 % 2 (2009), no. 1, 183--202.
0056 
0057 % Optional input arguments
0058 if ~isfield(param, 'y'), param.y = 0; end
0059 if ~isfield(param, 'A'), param.A = @(x) x; end
0060 if ~isfield(param, 'At'), param.At = @(x) x; end
0061 if ~isfield(param, 'epsilon'), param.epsilon = 1e-3; end
0062 if ~isfield(param, 'tight'), param.tight = 1; end
0063 if ~isfield(param, 'tol'), param.tol = 1e-3; end
0064 if ~isfield(param, 'verbose'), param.verbose = 1; end
0065 if ~isfield(param, 'nu'), param.nu = 1; end
0066 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0067 if ~isfield(param, 'u'), param.u = zeros(size(param.y)); end
0068 if ~isfield(param, 'pos'), param.pos = 0; end
0069 if ~isfield(param, 'real'), param.real = 0; end
0070 
0071 % Useful functions for the projection
0072 sc = @(z) z*min(param.epsilon/norm(z(:)), 1); % scaling
0073 
0074 % Projection
0075 if (param.tight && ~(param.pos||param.real)) % TIGHT FRAME CASE
0076     
0077     temp = param.A(x) - param.y;
0078     sol = x + 1/param.nu * param.At(sc(temp)-temp);
0079     crit_B2 = 'TOL_EPS'; iter = 0;
0080     u = 0;
0081     
0082 else % NON TIGHT FRAME CASE
0083     
0084     % Initializations
0085     sol = x; u = param.u; v = u;
0086     iter = 1; true = 1; told = 1;
0087     
0088     % Tolerance onto the L2 ball
0089     epsilon_low = param.epsilon/(1+param.tol);
0090     epsilon_up = param.epsilon/(1-param.tol);
0091     
0092     % Check if we are in the L2 ball
0093     dummy = param.A(sol);
0094     norm_res = norm(param.y(:)-dummy(:), 2);
0095     if norm_res <= epsilon_up
0096         crit_B2 = 'TOL_EPS'; true = 0;
0097     end
0098     
0099     % Projection onto the L2-ball
0100     % Init
0101     if param.verbose > 1
0102         fprintf('  Proj. B2:\n');
0103     end
0104     while true
0105         
0106         % Residual
0107         res = param.A(sol) - param.y; norm_res = norm(res(:), 2);
0108         
0109         % Scaling for the projection
0110         res = u*param.nu + res; norm_proj = norm(res(:), 2);
0111         
0112         % Log
0113         if param.verbose>1
0114             fprintf('   Iter %i, epsilon = %e, ||y - Ax||_2 = %e\n', ...
0115                 iter, param.epsilon, norm_res);
0116         end
0117         
0118         % Stopping criterion
0119         if (norm_res>=epsilon_low && norm_res<=epsilon_up)
0120             crit_B2 = 'TOL_EPS'; break;
0121         elseif iter >= param.max_iter
0122             crit_B2 = 'MAX_IT'; break;
0123         end
0124         
0125         % Projection onto the L2 ball
0126         t = (1+sqrt(1+4*told^2))/2;
0127         ratio = min(1, param.epsilon/norm_proj);
0128         u = v;
0129         v = 1/param.nu * (res - res*ratio);
0130         u = v + (told-1)/t * (v - u);
0131         
0132         % Current estimate
0133         sol = x - param.At(u);
0134         
0135         % Projection onto the non-negative orthant (positivity constraint)
0136         if (param.pos)
0137             sol = real(sol);
0138             sol(sol<0) = 0;
0139             
0140         end
0141         
0142         % Projection onto the real orthant (reality constraint)
0143         if (param.real)
0144             sol = real(sol);            
0145         end        
0146         
0147         % Update number of iteration
0148         told = t;
0149         
0150         % Update number of iterations
0151         iter = iter + 1;
0152         
0153     end
0154 end
0155 
0156 % Log after the projection onto the L2-ball
0157 if param.verbose >= 1
0158     temp = param.A(sol);
0159     fprintf(['  Proj. B2: epsilon = %e, ||y-Ax||_2 = %e,', ...
0160         ' %s, iter = %i\n'], param.epsilon, norm(param.y(:)-temp(:)), ...
0161         crit_B2, iter);
0162 end
0163 
0164 
0165 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/sopt_mltb_proj_B2.html.svn-base000066400000000000000000000273051277570055300316160ustar00rootroot00000000000000 Description of sopt_mltb_proj_B2
Home > matlab > prox_operators > sopt_mltb_proj_B2.m

sopt_mltb_proj_B2

PURPOSE ^

sopt_mltb_proj_B2 - Projection onto L2-ball

SYNOPSIS ^

function [sol, u] = sopt_mltb_proj_B2(x, param)

DESCRIPTION ^

 sopt_mltb_proj_B2 - Projection onto L2-ball

 Compute the projection onto the L2 ball, i.e. solve

   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon

 where x is the input vector and the solution z* is returned as sol.
 The structure param should contain the following fields:

   - y: Measurements (default = 0).

   - A: Forward operator (default = Identity).

   - At: Adjoint operator (default = Identity).

   - epsilon: Radius of the L2 ball (default = 1e-3).

   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter: Maximum number of iterations (default: 200).

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - u: Initial vector for the dual problem, same dimension as y
       (default = 0).

 Outputs:

   - sol: Final solution.

   - u: Final dual vector.

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for 
 optimization problems in sparse recovery" , IEEE ICIP, Cairo, 
 Egypt, 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [sol, u] = sopt_mltb_proj_B2(x, param)
0002 % sopt_mltb_proj_B2 - Projection onto L2-ball
0003 %
0004 % Compute the projection onto the L2 ball, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - y: Measurements (default = 0).
0012 %
0013 %   - A: Forward operator (default = Identity).
0014 %
0015 %   - At: Adjoint operator (default = Identity).
0016 %
0017 %   - epsilon: Radius of the L2 ball (default = 1e-3).
0018 %
0019 %   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).
0020 %
0021 %   - nu: Bound on the norm^2 of the operator A, i.e.
0022 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0023 %
0024 %   - tol: Tolerance for the projection onto the L2 ball. The algorithms
0025 %       stops if
0026 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0027 %       (default = 1e-3).
0028 %
0029 %   - max_iter: Maximum number of iterations (default: 200).
0030 %
0031 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0032 %       2 = print main steps; default = 1).
0033 %
0034 %   - u: Initial vector for the dual problem, same dimension as y
0035 %       (default = 0).
0036 %
0037 % Outputs:
0038 %
0039 %   - sol: Final solution.
0040 %
0041 %   - u: Final dual vector.
0042 %
0043 % References:
0044 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0045 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0046 % Egypt, 2009.
0047 
0048 % Optional input arguments
0049 if ~isfield(param, 'y'), param.y = 0; end
0050 if ~isfield(param, 'A'), param.A = @(x) x; end
0051 if ~isfield(param, 'At'), param.At = @(x) x; end
0052 if ~isfield(param, 'epsilon'), param.epsilon = 1e-3; end
0053 if ~isfield(param, 'tight'), param.tight = 1; end
0054 if ~isfield(param, 'tol'), param.tol = 1e-3; end
0055 if ~isfield(param, 'verbose'), param.verbose = 1; end
0056 if ~isfield(param, 'nu'), param.nu = 1; end
0057 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0058 if ~isfield(param, 'u'), param.u = zeros(size(param.y)); end
0059 
0060 % Useful functions for the projection
0061 sc = @(z) z*min(param.epsilon/norm(z(:)), 1); % scaling
0062 
0063 % Projection
0064 if param.tight % TIGHT FRAME CASE
0065     
0066     temp = param.A(x) - param.y;
0067     sol = x + 1/param.nu * param.At(sc(temp)-temp);
0068     crit_B2 = 'TOL_EPS'; iter = 0; u = NaN;
0069     
0070 else % NON TIGHT FRAME CASE
0071     
0072     % Initializations
0073     sol = x; u = param.u;
0074     iter = 1; true = 1;
0075     
0076     % Tolerance onto the L2 ball
0077     epsilon_low = param.epsilon/(1+param.tol);
0078     epsilon_up = param.epsilon/(1-param.tol);
0079     
0080     % Check if we are in the L2 ball
0081     norm_res = norm(param.y(:)-param.A(sol), 2);
0082     if norm_res <= epsilon_up
0083         crit_B2 = 'TOL_EPS'; true = 0;
0084     end
0085     
0086     % Projection onto the L2-ball
0087     % Init
0088     if param.verbose > 1
0089         fprintf('  Proj. B2:\n');
0090     end
0091     while true
0092         
0093         % Residual
0094         res = param.A(sol) - param.y; norm_res = norm(res(:), 2);
0095         
0096         % Scaling for the projection
0097         res = u*param.nu + res; norm_proj = norm(res(:), 2);
0098         
0099         % Log
0100         if param.verbose>1
0101             fprintf('   Iter %i, epsilon = %e, ||y - Ax||_2 = %e\n', ...
0102                 iter, param.epsilon, norm_res);
0103         end
0104         
0105         % Stopping criterion
0106         if (norm_res>=epsilon_low && norm_res<=epsilon_up)
0107             crit_B2 = 'TOL_EPS'; break;
0108         elseif iter >= param.max_iter
0109             crit_B2 = 'MAX_IT'; break;
0110         end
0111         
0112         % Projection onto the L2 ball
0113         ratio = min(1, param.epsilon/norm_proj);
0114         u = 1/param.nu * (res - res*ratio);
0115         
0116         % Current estimate
0117         sol = x - param.At(u);
0118         
0119         % Update number of iteration
0120         iter = iter + 1;
0121         
0122     end
0123 end
0124 
0125 % Log after the projection onto the L2-ball
0126 if param.verbose >= 1
0127     temp = param.A(sol);
0128     fprintf(['  Proj. B2: epsilon = %e, ||y-Ax||_2 = %e,', ...
0129         ' %s, iter = %i\n'], param.epsilon, norm(param.y(:)-temp(:)), ...
0130         crit_B2, iter);
0131 end
0132 
0133 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/sopt_mltb_prox_L1.html.svn-base000066400000000000000000000272541277570055300316500ustar00rootroot00000000000000 Description of sopt_mltb_prox_L1
Home > matlab > prox_operators > sopt_mltb_prox_L1.m

sopt_mltb_prox_L1

PURPOSE ^

sopt_mltb_prox_L1 - Proximal operator with L1 norm

SYNOPSIS ^

function sol = sopt_mltb_prox_L1(x, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_L1 - Proximal operator with L1 norm

 Compute the L1 proximal operator, i.e. solve

   min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 ,

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - Psit: Sparsifying transform (default = Identity).

   - Psi: Adjoint of Psit (default = Identity).

   - tight: 1 if Psit is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator Psi, i.e.
       ||Psi x||^2 <= nu * ||x||^2 (default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - weights: Weights for a weighted L1-norm (default = 1).

   - pos: Positivity flag (1 = positive solution,
       0 = general complex case; default = 0).

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
 optimization problems in sparse recovery" , IEEE ICIP, Cairo,
 Egypt, 2009.
 [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
 Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
 2 (2009), no. 1, 183--202.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_L1(x, lambda, param)
0002 % sopt_mltb_prox_L1 - Proximal operator with L1 norm
0003 %
0004 % Compute the L1 proximal operator, i.e. solve
0005 %
0006 %   min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 ,
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - Psit: Sparsifying transform (default = Identity).
0012 %
0013 %   - Psi: Adjoint of Psit (default = Identity).
0014 %
0015 %   - tight: 1 if Psit is a tight frame or 0 otherwise (default = 1).
0016 %
0017 %   - nu: Bound on the norm^2 of the operator Psi, i.e.
0018 %       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
0019 %
0020 %   - max_iter: Maximum number of iterations (default = 200).
0021 %
0022 %   - rel_obj: Minimum relative change of the objective value
0023 %       (default = 1e-4).  The algorithm stops if
0024 %           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
0025 %       where x(t) is the estimate of the solution at iteration t.
0026 %
0027 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0028 %       2 = print main steps; default = 1).
0029 %
0030 %   - weights: Weights for a weighted L1-norm (default = 1).
0031 %
0032 %   - pos: Positivity flag (1 = positive solution,
0033 %       0 = general complex case; default = 0).
0034 %
0035 % References:
0036 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0037 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0038 % Egypt, 2009.
0039 % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
0040 % Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
0041 % 2 (2009), no. 1, 183--202.
0042 
0043 % Optional input arguments
0044 if ~isfield(param, 'verbose'), param.verbose = 1; end
0045 if ~isfield(param, 'Psit'), param.Psi = @(x) x; param.Psit = @(x) x; end
0046 if ~isfield(param, 'tight'), param.tight = 1; end
0047 if ~isfield(param, 'nu'), param.nu = 1; end
0048 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0049 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0050 if ~isfield(param, 'Psit'), param.Psit = @(x) x; end
0051 if ~isfield(param, 'Psi'), param.Psi = @(x) x; end
0052 if ~isfield(param, 'weights'), param.weights = 1; end
0053 if ~isfield(param, 'pos'), param.pos = 0; end
0054 
0055 % Useful functions
0056 soft = @(z, T) sign(z).*max(abs(z)-T, 0);
0057 
0058 % Projection
0059 if param.tight && ~param.pos % TIGHT FRAME CASE
0060     
0061     temp = param.Psit(x);
0062     sol = x + 1/param.nu * param.Psi(soft(temp, ...
0063         lambda*param.nu*param.weights)-temp);
0064     crit_L1 = 'REL_OBJ'; iter_L1 = 1;
0065     dummy = param.Psit(sol);
0066     norm_l1 = sum(param.weights(:).*abs(dummy(:)));
0067     
0068 else % NON TIGHT FRAME CASE OR CONSTRAINT INVOLVED
0069     
0070     % Initializations
0071     u_l1 = zeros(size(param.Psit(x)));
0072     sol = x - param.Psi(u_l1);
0073     prev_l1 = 0; iter_L1 = 0;
0074     
0075     % Soft-thresholding
0076     % Init
0077     if param.verbose > 1
0078         fprintf('  Proximal l1 operator:\n');
0079     end
0080     while 1
0081         
0082         % L1 norm of the estimate
0083         dummy = param.Psit(sol);
0084         
0085         norm_l1 = .5*norm(x(:) - sol(:), 2)^2 + lambda * ...
0086             sum(param.weights(:).*abs(dummy(:)));
0087         rel_l1 = abs(norm_l1-prev_l1)/norm_l1;
0088         
0089         % Log
0090         if param.verbose>1
0091             fprintf('   Iter %i, ||Psit x||_1 = %e, rel_l1 = %e\n', ...
0092                 iter_L1, norm_l1, rel_l1);
0093         end
0094         
0095         % Stopping criterion
0096         if (rel_l1 < param.rel_obj)
0097             crit_L1 = 'REL_OB'; break;
0098         elseif iter_L1 >= param.max_iter
0099             crit_L1 = 'MAX_IT'; break;
0100         end
0101         
0102         % Soft-thresholding
0103         res = u_l1*param.nu + param.Psit(sol);
0104         dummy = soft(res, lambda*param.nu*param.weights);
0105         if param.pos
0106             dummy = real(dummy); dummy(dummy<0) = 0;
0107         end
0108         u_l1 = 1/param.nu * (res - dummy);
0109         sol = x - param.Psi(u_l1);
0110         
0111         % Update
0112         prev_l1 = norm_l1;
0113         iter_L1 = iter_L1 + 1;
0114         
0115     end
0116 end
0117 
0118 % Log after the projection onto the L2-ball
0119 if param.verbose >= 1
0120     fprintf(['  prox_L1: ||Psi x||_1 = %e,', ...
0121         ' %s, iter = %i\n'], norm_l1, crit_L1, iter_L1);
0122 end
0123 
0124 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/sopt_mltb_prox_TV.html.svn-base000066400000000000000000000200761277570055300317200ustar00rootroot00000000000000 Description of sopt_mltb_prox_TV
Home > matlab > prox_operators > sopt_mltb_prox_TV.m

sopt_mltb_prox_TV

PURPOSE ^

sopt_mltb_prox_TV - Total variation proximal operator

SYNOPSIS ^

function sol = sopt_mltb_prox_TV(x, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_TV - Total variation proximal operator

 Compute the TV proximal operator, i.e. solve

   min_{z} ||x - z||_2^2 + lambda * ||z||_{TV}

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

 Reference:
 [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
 constrained Total Variation Image Denoising and Deblurring Problems", 
 IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434, 
 November 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_TV(x, lambda, param)
0002 % sopt_mltb_prox_TV - Total variation proximal operator
0003 %
0004 % Compute the TV proximal operator, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2 + lambda * ||z||_{TV}
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - max_iter: Maximum number of iterations (default = 200).
0012 %
0013 %   - rel_obj: Minimum relative change of the objective value
0014 %       (default = 1e-4).  The algorithm stops if
0015 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0016 %       where x(t) is the estimate of the solution at iteration t.
0017 %
0018 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0019 %       2 = print main steps; default = 1).
0020 %
0021 % Reference:
0022 % [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
0023 % constrained Total Variation Image Denoising and Deblurring Problems",
0024 % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
0025 % November 2009.
0026 
0027 % Optional input arguments
0028 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0029 if ~isfield(param, 'verbose'), param.verbose = 1; end
0030 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0031 
0032 % Initializations
0033 [r, s] = sopt_mltb_gradient_op(x*0);
0034 pold = r; qold = s;
0035 told = 1; prev_obj = 0;
0036 
0037 % Main iterations
0038 if param.verbose > 1
0039     fprintf('  Proximal TV operator:\n');
0040 end
0041 for iter = 1:param.max_iter
0042     
0043     % Current solution
0044     sol = x - lambda*sopt_mltb_div_op(r, s);
0045     
0046     % Objective function value
0047     obj = .5*norm(x(:)-sol(:), 2)^2 + lambda * sopt_mltb_TV_norm(sol, 0);
0048     rel_obj = abs(obj-prev_obj)/obj;
0049     prev_obj = obj;
0050     
0051     % Stopping criterion
0052     if param.verbose>1
0053         fprintf('   Iter %i, obj = %e, rel_obj = %e\n', ...
0054             iter, obj, rel_obj);
0055     end
0056     if rel_obj < param.rel_obj
0057         crit_TV = 'TOL_EPS'; break;
0058     end
0059     
0060     % Udpate divergence vectors and project
0061     [dx, dy] = sopt_mltb_gradient_op(sol);
0062     r = r - 1/(8*lambda) * dx; s = s - 1/(8*lambda) * dy;
0063     weights = max(1, sqrt(abs(r).^2+abs(s).^2));
0064     p = r./weights; q = s./weights;
0065     
0066     % FISTA update
0067     t = (1+sqrt(4*told^2))/2;
0068     r = p + (told-1)/t * (p - pold); pold = p;
0069     s = q + (told-1)/t * (q - qold); qold = q;
0070     told = t;
0071     
0072 end
0073 
0074 % Log after the minimization
0075 if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end
0076 if param.verbose >= 1
0077     fprintf(['  Prox_TV: obj = %e, rel_obj = %e,' ...
0078         ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter);
0079 end
0080 
0081 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/.svn/text-base/sopt_mltb_prox_TVoA.html.svn-base000066400000000000000000000306471277570055300322050ustar00rootroot00000000000000 Description of sopt_mltb_prox_TVoA
Home > matlab > prox_operators > sopt_mltb_prox_TVoA.m

sopt_mltb_prox_TVoA

PURPOSE ^

sopt_mltb_prox_TVoA - Agumented total variation proximal operator

SYNOPSIS ^

function sol = sopt_mltb_prox_TVoA(b, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_TVoA - Agumented total variation proximal operator

 Compute the TV proximal operator when an additional linear operator A is
 incorporated in the TV norm, i.e. solve

   min_{x} ||y - x||_2^2 + lambda * ||A x||_{TV}

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - A: Forward transform (default = Identity).

   - At: Adjoint of At (default = Identity).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1)

 Reference:
 [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
 constrained Total Variation Image Denoising and Deblurring Problems",
 IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
 November 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_TVoA(b, lambda, param)
0002 % sopt_mltb_prox_TVoA - Agumented total variation proximal operator
0003 %
0004 % Compute the TV proximal operator when an additional linear operator A is
0005 % incorporated in the TV norm, i.e. solve
0006 %
0007 %   min_{x} ||y - x||_2^2 + lambda * ||A x||_{TV}
0008 %
0009 % where x is the input vector and the solution z* is returned as sol.
0010 % The structure param should contain the following fields:
0011 %
0012 %   - max_iter: Maximum number of iterations (default = 200).
0013 %
0014 %   - rel_obj: Minimum relative change of the objective value
0015 %       (default = 1e-4).  The algorithm stops if
0016 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_1 < rel_obj,
0017 %       where x(t) is the estimate of the solution at iteration t.
0018 %
0019 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0020 %       2 = print main steps; default = 1).
0021 %
0022 %   - A: Forward transform (default = Identity).
0023 %
0024 %   - At: Adjoint of At (default = Identity).
0025 %
0026 %   - nu: Bound on the norm^2 of the operator A, i.e.
0027 %       ||A x||^2 <= nu * ||x||^2 (default = 1)
0028 %
0029 % Reference:
0030 % [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
0031 % constrained Total Variation Image Denoising and Deblurring Problems",
0032 % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
0033 % November 2009.
0034 
0035 % Optional input arguments
0036 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0037 if ~isfield(param, 'verbose'), param.verbose = 1; end
0038 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0039 if ~isfield(param, 'At'), param.At = @(x) x; end
0040 if ~isfield(param, 'A'), param.A = @(x) x; end
0041 if ~isfield(param, 'nu'), param.nu = 1; end
0042 
0043 % Advanced input arguments (not exposed in documentation)
0044 if ~isfield(param, 'weights_dx'), param.weights_dx = 1; end
0045 if ~isfield(param, 'weights_dy'), param.weights_dy = 1; end
0046 if ~isfield(param, 'zero_weights_flag'), param.zero_weights_flag = 1; end
0047 if ~isfield(param, 'identical_weights_flag')
0048     param.identical_weights_flag = 0; 
0049 end
0050 if ~isfield(param, 'sphere_flag'), param.sphere_flag = 0; end
0051 if ~isfield(param, 'incNP'), param.incNP = 0; end
0052 
0053 % Set grad and div operators to planar or spherical case and also
0054 % include weights or not (depending on parameter flags).
0055 if (param.sphere_flag)
0056    G = @sopt_mltb_gradient_op_sphere;
0057    D = @sopt_mltb_div_op_sphere;
0058 else
0059    G = @sopt_mltb_gradient_op;
0060    D = @sopt_mltb_div_op;
0061 end
0062 
0063 if (~param.identical_weights_flag && param.zero_weights_flag)
0064     grad = @(x) G(x, param.weights_dx, param.weights_dy);
0065     div = @(r, s) D(r, s, param.weights_dx, param.weights_dy);
0066     max_weights = max([abs(param.weights_dx(:)); ...
0067         abs(param.weights_dy(:))])^2;
0068 else
0069     grad = @(x) G(x);
0070     div = @(r, s) D(r, s);
0071 end
0072 
0073 % Initializations
0074 [r, s] = grad(param.A(b*0));
0075 pold = r; qold = s;
0076 told = 1; prev_obj = 0;
0077 
0078 % Main iterations
0079 if param.verbose > 1
0080     fprintf('  Proximal TV operator:\n');
0081 end
0082 for iter = 1:param.max_iter
0083     
0084     % Current solution
0085     sol = b - lambda*param.At(div(r, s));
0086     
0087     % Objective function value
0088     obj = .5*norm(b(:)-sol(:), 2) + lambda * ...
0089         sopt_mltb_TV_norm(param.A(sol), param.weights_dx, param.weights_dy);
0090     rel_obj = abs(obj-prev_obj)/obj;
0091     prev_obj = obj;
0092     
0093     % Stopping criterion
0094     if param.verbose>1
0095         fprintf('   Iter %i, obj = %e, rel_obj = %e\n', ...
0096             iter, obj, rel_obj);
0097     end
0098     if rel_obj < param.rel_obj
0099         crit_TV = 'TOL_EPS'; break;
0100     end
0101     
0102     % Udpate divergence vectors and project
0103     [dx, dy] = grad(param.A(sol));
0104     if (param.identical_weights_flag)
0105         r = r - 1/(8*lambda*param.nu) * dx;
0106         s = s - 1/(8*lambda*param.nu) * dy;
0107         weights = max(param.weights_dx, sqrt(abs(r).^2+abs(s).^2));
0108         p = r./weights.*param.weights_dx; q = s./weights.*param.weights_dx;
0109     else
0110         if (~param.zero_weights_flag)
0111             r = r - 1/(8*lambda*param.nu) * dx;
0112             s = s - 1/(8*lambda*param.nu) * dy;
0113             weights = max(1, sqrt(abs(r./param.weights_dx).^2+...
0114                 abs(s./param.weights_dy).^2));
0115             p = r./weights; q = s./weights;
0116         else
0117             % Weights go into grad and div operators so usual update
0118             r = r - 1/(8*lambda*param.nu*max_weights) * dx;
0119             s = s - 1/(8*lambda*param.nu*max_weights) * dy;
0120             weights = max(1, sqrt(abs(r).^2+abs(s).^2));
0121             p = r./weights; q = s./weights;
0122         end
0123     end
0124     
0125     % FISTA update
0126     t = (1+sqrt(4*told^2))/2;
0127     r = p + (told-1)/t * (p - pold); pold = p;
0128     s = q + (told-1)/t * (q - qold); qold = q;
0129     told = t;
0130     
0131 end
0132 
0133 % Log after the minimization
0134 if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end
0135 if param.verbose >= 1
0136     fprintf(['  Prox_TV: obj = %e, rel_obj = %e,' ...
0137         ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter);
0138 end
0139 
0140 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/index.html000066400000000000000000000042371277570055300230470ustar00rootroot00000000000000 Index for Directory matlab/prox_operators
< Master index Index for matlab/prox_operators >

Index for matlab/prox_operators

Matlab files in this directory:

 sopt_mltb_fast_proj_B2sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball
 sopt_mltb_proj_B2sopt_mltb_proj_B2 - Projection onto L2-ball
 sopt_mltb_prox_L1sopt_mltb_prox_L1 - Proximal operator with L1 norm
 sopt_mltb_prox_TVsopt_mltb_prox_TV - Total variation proximal operator
 sopt_mltb_prox_TVoAsopt_mltb_prox_TVoA - Agumented total variation proximal operator

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/sopt_mltb_fast_proj_B2.html000066400000000000000000000337071277570055300263410ustar00rootroot00000000000000 Description of sopt_mltb_fast_proj_B2
Home > matlab > prox_operators > sopt_mltb_fast_proj_B2.m

sopt_mltb_fast_proj_B2

PURPOSE ^

sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball

SYNOPSIS ^

function [sol, u] = sopt_mltb_fast_proj_B2(x, param)

DESCRIPTION ^

 sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball

 Compute the projection onto the L2 ball, i.e. solve

   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon

 where x is the input vector and the solution z* is returned as sol.
 The structure param should contain the following fields:

   - y: Measurements (default = 0).

   - A: Forward operator (default = Identity).

   - At: Adjoint operator (default = Identity).

   - epsilon: Radius of the L2 ball (default = 1e-3).

   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter: Maximum number of iterations (default: 200).

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - u: Initial vector for the dual problem, same dimension as y
       (default = 0).
   
   - pos: Positivity flag (1 = positive solution,
       0 general complex case; default = 0).

   - real: Reality flag (1 = real solution,
       0 = general complex case; default = 0).

 Outputs:

   - sol: Final solution.

   - u: Final dual vector.

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
 optimization problems in sparse recovery" , IEEE ICIP, Cairo,
 Egypt, 2009.
 [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
 Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
 2 (2009), no. 1, 183--202.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [sol, u] = sopt_mltb_fast_proj_B2(x, param)
0002 % sopt_mltb_fast_proj_B2 - Fast projection onto L2-ball
0003 %
0004 % Compute the projection onto the L2 ball, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - y: Measurements (default = 0).
0012 %
0013 %   - A: Forward operator (default = Identity).
0014 %
0015 %   - At: Adjoint operator (default = Identity).
0016 %
0017 %   - epsilon: Radius of the L2 ball (default = 1e-3).
0018 %
0019 %   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).
0020 %
0021 %   - nu: Bound on the norm^2 of the operator A, i.e.
0022 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0023 %
0024 %   - tol: Tolerance for the projection onto the L2 ball. The algorithms
0025 %       stops if
0026 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0027 %       (default = 1e-3).
0028 %
0029 %   - max_iter: Maximum number of iterations (default: 200).
0030 %
0031 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0032 %       2 = print main steps; default = 1).
0033 %
0034 %   - u: Initial vector for the dual problem, same dimension as y
0035 %       (default = 0).
0036 %
0037 %   - pos: Positivity flag (1 = positive solution,
0038 %       0 general complex case; default = 0).
0039 %
0040 %   - real: Reality flag (1 = real solution,
0041 %       0 = general complex case; default = 0).
0042 %
0043 % Outputs:
0044 %
0045 %   - sol: Final solution.
0046 %
0047 %   - u: Final dual vector.
0048 %
0049 % References:
0050 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0051 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0052 % Egypt, 2009.
0053 % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
0054 % Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
0055 % 2 (2009), no. 1, 183--202.
0056 
0057 % Optional input arguments
0058 if ~isfield(param, 'y'), param.y = 0; end
0059 if ~isfield(param, 'A'), param.A = @(x) x; end
0060 if ~isfield(param, 'At'), param.At = @(x) x; end
0061 if ~isfield(param, 'epsilon'), param.epsilon = 1e-3; end
0062 if ~isfield(param, 'tight'), param.tight = 1; end
0063 if ~isfield(param, 'tol'), param.tol = 1e-3; end
0064 if ~isfield(param, 'verbose'), param.verbose = 1; end
0065 if ~isfield(param, 'nu'), param.nu = 1; end
0066 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0067 if ~isfield(param, 'u'), param.u = zeros(size(param.y)); end
0068 if ~isfield(param, 'pos'), param.pos = 0; end
0069 if ~isfield(param, 'real'), param.real = 0; end
0070 
0071 % Useful functions for the projection
0072 sc = @(z) z*min(param.epsilon/norm(z(:)), 1); % scaling
0073 
0074 % Projection
0075 if (param.tight && ~(param.pos||param.real)) % TIGHT FRAME CASE
0076     
0077     temp = param.A(x) - param.y;
0078     sol = x + 1/param.nu * param.At(sc(temp)-temp);
0079     crit_B2 = 'TOL_EPS'; iter = 0;
0080     u = 0;
0081     
0082 else % NON TIGHT FRAME CASE
0083     
0084     % Initializations
0085     sol = x; u = param.u; v = u;
0086     iter = 1; true = 1; told = 1;
0087     
0088     % Tolerance onto the L2 ball
0089     epsilon_low = param.epsilon/(1+param.tol);
0090     epsilon_up = param.epsilon/(1-param.tol);
0091     
0092     % Check if we are in the L2 ball
0093     dummy = param.A(sol);
0094     norm_res = norm(param.y(:)-dummy(:), 2);
0095     if norm_res <= epsilon_up
0096         crit_B2 = 'TOL_EPS'; true = 0;
0097     end
0098     
0099     % Projection onto the L2-ball
0100     % Init
0101     if param.verbose > 1
0102         fprintf('  Proj. B2:\n');
0103     end
0104     while true
0105         
0106         % Residual
0107         res = param.A(sol) - param.y; norm_res = norm(res(:), 2);
0108         
0109         % Scaling for the projection
0110         res = u*param.nu + res; norm_proj = norm(res(:), 2);
0111         
0112         % Log
0113         if param.verbose>1
0114             fprintf('   Iter %i, epsilon = %e, ||y - Ax||_2 = %e\n', ...
0115                 iter, param.epsilon, norm_res);
0116         end
0117         
0118         % Stopping criterion
0119         if (norm_res>=epsilon_low && norm_res<=epsilon_up)
0120             crit_B2 = 'TOL_EPS'; break;
0121         elseif iter >= param.max_iter
0122             crit_B2 = 'MAX_IT'; break;
0123         end
0124         
0125         % Projection onto the L2 ball
0126         t = (1+sqrt(1+4*told^2))/2;
0127         ratio = min(1, param.epsilon/norm_proj);
0128         u = v;
0129         v = 1/param.nu * (res - res*ratio);
0130         u = v + (told-1)/t * (v - u);
0131         
0132         % Current estimate
0133         sol = x - param.At(u);
0134         
0135         % Projection onto the non-negative orthant (positivity constraint)
0136         if (param.pos)
0137             sol = real(sol);
0138             sol(sol<0) = 0;
0139             
0140         end
0141         
0142         % Projection onto the real orthant (reality constraint)
0143         if (param.real)
0144             sol = real(sol);            
0145         end        
0146         
0147         % Update number of iteration
0148         told = t;
0149         
0150         % Update number of iterations
0151         iter = iter + 1;
0152         
0153     end
0154 end
0155 
0156 % Log after the projection onto the L2-ball
0157 if param.verbose >= 1
0158     temp = param.A(sol);
0159     fprintf(['  Proj. B2: epsilon = %e, ||y-Ax||_2 = %e,', ...
0160         ' %s, iter = %i\n'], param.epsilon, norm(param.y(:)-temp(:)), ...
0161         crit_B2, iter);
0162 end
0163 
0164 
0165 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/sopt_mltb_proj_B2.html000066400000000000000000000273051277570055300253210ustar00rootroot00000000000000 Description of sopt_mltb_proj_B2
Home > matlab > prox_operators > sopt_mltb_proj_B2.m

sopt_mltb_proj_B2

PURPOSE ^

sopt_mltb_proj_B2 - Projection onto L2-ball

SYNOPSIS ^

function [sol, u] = sopt_mltb_proj_B2(x, param)

DESCRIPTION ^

 sopt_mltb_proj_B2 - Projection onto L2-ball

 Compute the projection onto the L2 ball, i.e. solve

   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon

 where x is the input vector and the solution z* is returned as sol.
 The structure param should contain the following fields:

   - y: Measurements (default = 0).

   - A: Forward operator (default = Identity).

   - At: Adjoint operator (default = Identity).

   - epsilon: Radius of the L2 ball (default = 1e-3).

   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter: Maximum number of iterations (default: 200).

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - u: Initial vector for the dual problem, same dimension as y
       (default = 0).

 Outputs:

   - sol: Final solution.

   - u: Final dual vector.

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for 
 optimization problems in sparse recovery" , IEEE ICIP, Cairo, 
 Egypt, 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function [sol, u] = sopt_mltb_proj_B2(x, param)
0002 % sopt_mltb_proj_B2 - Projection onto L2-ball
0003 %
0004 % Compute the projection onto the L2 ball, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2   s.t.  ||y - A z||_2 < epsilon
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - y: Measurements (default = 0).
0012 %
0013 %   - A: Forward operator (default = Identity).
0014 %
0015 %   - At: Adjoint operator (default = Identity).
0016 %
0017 %   - epsilon: Radius of the L2 ball (default = 1e-3).
0018 %
0019 %   - tight: 1 if A is a tight frame or 0 otherwise (default = 1).
0020 %
0021 %   - nu: Bound on the norm^2 of the operator A, i.e.
0022 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0023 %
0024 %   - tol: Tolerance for the projection onto the L2 ball. The algorithms
0025 %       stops if
0026 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0027 %       (default = 1e-3).
0028 %
0029 %   - max_iter: Maximum number of iterations (default: 200).
0030 %
0031 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0032 %       2 = print main steps; default = 1).
0033 %
0034 %   - u: Initial vector for the dual problem, same dimension as y
0035 %       (default = 0).
0036 %
0037 % Outputs:
0038 %
0039 %   - sol: Final solution.
0040 %
0041 %   - u: Final dual vector.
0042 %
0043 % References:
0044 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0045 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0046 % Egypt, 2009.
0047 
0048 % Optional input arguments
0049 if ~isfield(param, 'y'), param.y = 0; end
0050 if ~isfield(param, 'A'), param.A = @(x) x; end
0051 if ~isfield(param, 'At'), param.At = @(x) x; end
0052 if ~isfield(param, 'epsilon'), param.epsilon = 1e-3; end
0053 if ~isfield(param, 'tight'), param.tight = 1; end
0054 if ~isfield(param, 'tol'), param.tol = 1e-3; end
0055 if ~isfield(param, 'verbose'), param.verbose = 1; end
0056 if ~isfield(param, 'nu'), param.nu = 1; end
0057 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0058 if ~isfield(param, 'u'), param.u = zeros(size(param.y)); end
0059 
0060 % Useful functions for the projection
0061 sc = @(z) z*min(param.epsilon/norm(z(:)), 1); % scaling
0062 
0063 % Projection
0064 if param.tight % TIGHT FRAME CASE
0065     
0066     temp = param.A(x) - param.y;
0067     sol = x + 1/param.nu * param.At(sc(temp)-temp);
0068     crit_B2 = 'TOL_EPS'; iter = 0; u = NaN;
0069     
0070 else % NON TIGHT FRAME CASE
0071     
0072     % Initializations
0073     sol = x; u = param.u;
0074     iter = 1; true = 1;
0075     
0076     % Tolerance onto the L2 ball
0077     epsilon_low = param.epsilon/(1+param.tol);
0078     epsilon_up = param.epsilon/(1-param.tol);
0079     
0080     % Check if we are in the L2 ball
0081     norm_res = norm(param.y(:)-param.A(sol), 2);
0082     if norm_res <= epsilon_up
0083         crit_B2 = 'TOL_EPS'; true = 0;
0084     end
0085     
0086     % Projection onto the L2-ball
0087     % Init
0088     if param.verbose > 1
0089         fprintf('  Proj. B2:\n');
0090     end
0091     while true
0092         
0093         % Residual
0094         res = param.A(sol) - param.y; norm_res = norm(res(:), 2);
0095         
0096         % Scaling for the projection
0097         res = u*param.nu + res; norm_proj = norm(res(:), 2);
0098         
0099         % Log
0100         if param.verbose>1
0101             fprintf('   Iter %i, epsilon = %e, ||y - Ax||_2 = %e\n', ...
0102                 iter, param.epsilon, norm_res);
0103         end
0104         
0105         % Stopping criterion
0106         if (norm_res>=epsilon_low && norm_res<=epsilon_up)
0107             crit_B2 = 'TOL_EPS'; break;
0108         elseif iter >= param.max_iter
0109             crit_B2 = 'MAX_IT'; break;
0110         end
0111         
0112         % Projection onto the L2 ball
0113         ratio = min(1, param.epsilon/norm_proj);
0114         u = 1/param.nu * (res - res*ratio);
0115         
0116         % Current estimate
0117         sol = x - param.At(u);
0118         
0119         % Update number of iteration
0120         iter = iter + 1;
0121         
0122     end
0123 end
0124 
0125 % Log after the projection onto the L2-ball
0126 if param.verbose >= 1
0127     temp = param.A(sol);
0128     fprintf(['  Proj. B2: epsilon = %e, ||y-Ax||_2 = %e,', ...
0129         ' %s, iter = %i\n'], param.epsilon, norm(param.y(:)-temp(:)), ...
0130         crit_B2, iter);
0131 end
0132 
0133 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/sopt_mltb_prox_L1.html000066400000000000000000000272541277570055300253530ustar00rootroot00000000000000 Description of sopt_mltb_prox_L1
Home > matlab > prox_operators > sopt_mltb_prox_L1.m

sopt_mltb_prox_L1

PURPOSE ^

sopt_mltb_prox_L1 - Proximal operator with L1 norm

SYNOPSIS ^

function sol = sopt_mltb_prox_L1(x, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_L1 - Proximal operator with L1 norm

 Compute the L1 proximal operator, i.e. solve

   min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 ,

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - Psit: Sparsifying transform (default = Identity).

   - Psi: Adjoint of Psit (default = Identity).

   - tight: 1 if Psit is a tight frame or 0 otherwise (default = 1).

   - nu: Bound on the norm^2 of the operator Psi, i.e.
       ||Psi x||^2 <= nu * ||x||^2 (default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - weights: Weights for a weighted L1-norm (default = 1).

   - pos: Positivity flag (1 = positive solution,
       0 = general complex case; default = 0).

 References:
 [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
 optimization problems in sparse recovery" , IEEE ICIP, Cairo,
 Egypt, 2009.
 [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
 Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
 2 (2009), no. 1, 183--202.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_L1(x, lambda, param)
0002 % sopt_mltb_prox_L1 - Proximal operator with L1 norm
0003 %
0004 % Compute the L1 proximal operator, i.e. solve
0005 %
0006 %   min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 ,
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - Psit: Sparsifying transform (default = Identity).
0012 %
0013 %   - Psi: Adjoint of Psit (default = Identity).
0014 %
0015 %   - tight: 1 if Psit is a tight frame or 0 otherwise (default = 1).
0016 %
0017 %   - nu: Bound on the norm^2 of the operator Psi, i.e.
0018 %       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
0019 %
0020 %   - max_iter: Maximum number of iterations (default = 200).
0021 %
0022 %   - rel_obj: Minimum relative change of the objective value
0023 %       (default = 1e-4).  The algorithm stops if
0024 %           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
0025 %       where x(t) is the estimate of the solution at iteration t.
0026 %
0027 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0028 %       2 = print main steps; default = 1).
0029 %
0030 %   - weights: Weights for a weighted L1-norm (default = 1).
0031 %
0032 %   - pos: Positivity flag (1 = positive solution,
0033 %       0 = general complex case; default = 0).
0034 %
0035 % References:
0036 % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for
0037 % optimization problems in sparse recovery" , IEEE ICIP, Cairo,
0038 % Egypt, 2009.
0039 % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding
0040 % Algorithm for Linear Inverse Problems",  SIAM Journal on Imaging Sciences
0041 % 2 (2009), no. 1, 183--202.
0042 
0043 % Optional input arguments
0044 if ~isfield(param, 'verbose'), param.verbose = 1; end
0045 if ~isfield(param, 'Psit'), param.Psi = @(x) x; param.Psit = @(x) x; end
0046 if ~isfield(param, 'tight'), param.tight = 1; end
0047 if ~isfield(param, 'nu'), param.nu = 1; end
0048 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0049 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0050 if ~isfield(param, 'Psit'), param.Psit = @(x) x; end
0051 if ~isfield(param, 'Psi'), param.Psi = @(x) x; end
0052 if ~isfield(param, 'weights'), param.weights = 1; end
0053 if ~isfield(param, 'pos'), param.pos = 0; end
0054 
0055 % Useful functions
0056 soft = @(z, T) sign(z).*max(abs(z)-T, 0);
0057 
0058 % Projection
0059 if param.tight && ~param.pos % TIGHT FRAME CASE
0060     
0061     temp = param.Psit(x);
0062     sol = x + 1/param.nu * param.Psi(soft(temp, ...
0063         lambda*param.nu*param.weights)-temp);
0064     crit_L1 = 'REL_OBJ'; iter_L1 = 1;
0065     dummy = param.Psit(sol);
0066     norm_l1 = sum(param.weights(:).*abs(dummy(:)));
0067     
0068 else % NON TIGHT FRAME CASE OR CONSTRAINT INVOLVED
0069     
0070     % Initializations
0071     u_l1 = zeros(size(param.Psit(x)));
0072     sol = x - param.Psi(u_l1);
0073     prev_l1 = 0; iter_L1 = 0;
0074     
0075     % Soft-thresholding
0076     % Init
0077     if param.verbose > 1
0078         fprintf('  Proximal l1 operator:\n');
0079     end
0080     while 1
0081         
0082         % L1 norm of the estimate
0083         dummy = param.Psit(sol);
0084         
0085         norm_l1 = .5*norm(x(:) - sol(:), 2)^2 + lambda * ...
0086             sum(param.weights(:).*abs(dummy(:)));
0087         rel_l1 = abs(norm_l1-prev_l1)/norm_l1;
0088         
0089         % Log
0090         if param.verbose>1
0091             fprintf('   Iter %i, ||Psit x||_1 = %e, rel_l1 = %e\n', ...
0092                 iter_L1, norm_l1, rel_l1);
0093         end
0094         
0095         % Stopping criterion
0096         if (rel_l1 < param.rel_obj)
0097             crit_L1 = 'REL_OB'; break;
0098         elseif iter_L1 >= param.max_iter
0099             crit_L1 = 'MAX_IT'; break;
0100         end
0101         
0102         % Soft-thresholding
0103         res = u_l1*param.nu + param.Psit(sol);
0104         dummy = soft(res, lambda*param.nu*param.weights);
0105         if param.pos
0106             dummy = real(dummy); dummy(dummy<0) = 0;
0107         end
0108         u_l1 = 1/param.nu * (res - dummy);
0109         sol = x - param.Psi(u_l1);
0110         
0111         % Update
0112         prev_l1 = norm_l1;
0113         iter_L1 = iter_L1 + 1;
0114         
0115     end
0116 end
0117 
0118 % Log after the projection onto the L2-ball
0119 if param.verbose >= 1
0120     fprintf(['  prox_L1: ||Psi x||_1 = %e,', ...
0121         ' %s, iter = %i\n'], norm_l1, crit_L1, iter_L1);
0122 end
0123 
0124 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/sopt_mltb_prox_TV.html000066400000000000000000000200761277570055300254230ustar00rootroot00000000000000 Description of sopt_mltb_prox_TV
Home > matlab > prox_operators > sopt_mltb_prox_TV.m

sopt_mltb_prox_TV

PURPOSE ^

sopt_mltb_prox_TV - Total variation proximal operator

SYNOPSIS ^

function sol = sopt_mltb_prox_TV(x, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_TV - Total variation proximal operator

 Compute the TV proximal operator, i.e. solve

   min_{z} ||x - z||_2^2 + lambda * ||z||_{TV}

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

 Reference:
 [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
 constrained Total Variation Image Denoising and Deblurring Problems", 
 IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434, 
 November 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_TV(x, lambda, param)
0002 % sopt_mltb_prox_TV - Total variation proximal operator
0003 %
0004 % Compute the TV proximal operator, i.e. solve
0005 %
0006 %   min_{z} ||x - z||_2^2 + lambda * ||z||_{TV}
0007 %
0008 % where x is the input vector and the solution z* is returned as sol.
0009 % The structure param should contain the following fields:
0010 %
0011 %   - max_iter: Maximum number of iterations (default = 200).
0012 %
0013 %   - rel_obj: Minimum relative change of the objective value
0014 %       (default = 1e-4).  The algorithm stops if
0015 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0016 %       where x(t) is the estimate of the solution at iteration t.
0017 %
0018 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0019 %       2 = print main steps; default = 1).
0020 %
0021 % Reference:
0022 % [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
0023 % constrained Total Variation Image Denoising and Deblurring Problems",
0024 % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
0025 % November 2009.
0026 
0027 % Optional input arguments
0028 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0029 if ~isfield(param, 'verbose'), param.verbose = 1; end
0030 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0031 
0032 % Initializations
0033 [r, s] = sopt_mltb_gradient_op(x*0);
0034 pold = r; qold = s;
0035 told = 1; prev_obj = 0;
0036 
0037 % Main iterations
0038 if param.verbose > 1
0039     fprintf('  Proximal TV operator:\n');
0040 end
0041 for iter = 1:param.max_iter
0042     
0043     % Current solution
0044     sol = x - lambda*sopt_mltb_div_op(r, s);
0045     
0046     % Objective function value
0047     obj = .5*norm(x(:)-sol(:), 2)^2 + lambda * sopt_mltb_TV_norm(sol, 0);
0048     rel_obj = abs(obj-prev_obj)/obj;
0049     prev_obj = obj;
0050     
0051     % Stopping criterion
0052     if param.verbose>1
0053         fprintf('   Iter %i, obj = %e, rel_obj = %e\n', ...
0054             iter, obj, rel_obj);
0055     end
0056     if rel_obj < param.rel_obj
0057         crit_TV = 'TOL_EPS'; break;
0058     end
0059     
0060     % Udpate divergence vectors and project
0061     [dx, dy] = sopt_mltb_gradient_op(sol);
0062     r = r - 1/(8*lambda) * dx; s = s - 1/(8*lambda) * dy;
0063     weights = max(1, sqrt(abs(r).^2+abs(s).^2));
0064     p = r./weights; q = s./weights;
0065     
0066     % FISTA update
0067     t = (1+sqrt(4*told^2))/2;
0068     r = p + (told-1)/t * (p - pold); pold = p;
0069     s = q + (told-1)/t * (q - qold); qold = q;
0070     told = t;
0071     
0072 end
0073 
0074 % Log after the minimization
0075 if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end
0076 if param.verbose >= 1
0077     fprintf(['  Prox_TV: obj = %e, rel_obj = %e,' ...
0078         ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter);
0079 end
0080 
0081 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/prox_operators/sopt_mltb_prox_TVoA.html000066400000000000000000000306471277570055300257100ustar00rootroot00000000000000 Description of sopt_mltb_prox_TVoA
Home > matlab > prox_operators > sopt_mltb_prox_TVoA.m

sopt_mltb_prox_TVoA

PURPOSE ^

sopt_mltb_prox_TVoA - Agumented total variation proximal operator

SYNOPSIS ^

function sol = sopt_mltb_prox_TVoA(b, lambda, param)

DESCRIPTION ^

 sopt_mltb_prox_TVoA - Agumented total variation proximal operator

 Compute the TV proximal operator when an additional linear operator A is
 incorporated in the TV norm, i.e. solve

   min_{x} ||y - x||_2^2 + lambda * ||A x||_{TV}

 where x is the input vector and the solution z* is returned as sol.  
 The structure param should contain the following fields:

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - A: Forward transform (default = Identity).

   - At: Adjoint of At (default = Identity).

   - nu: Bound on the norm^2 of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1)

 Reference:
 [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
 constrained Total Variation Image Denoising and Deblurring Problems",
 IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
 November 2009.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_prox_TVoA(b, lambda, param)
0002 % sopt_mltb_prox_TVoA - Agumented total variation proximal operator
0003 %
0004 % Compute the TV proximal operator when an additional linear operator A is
0005 % incorporated in the TV norm, i.e. solve
0006 %
0007 %   min_{x} ||y - x||_2^2 + lambda * ||A x||_{TV}
0008 %
0009 % where x is the input vector and the solution z* is returned as sol.
0010 % The structure param should contain the following fields:
0011 %
0012 %   - max_iter: Maximum number of iterations (default = 200).
0013 %
0014 %   - rel_obj: Minimum relative change of the objective value
0015 %       (default = 1e-4).  The algorithm stops if
0016 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_1 < rel_obj,
0017 %       where x(t) is the estimate of the solution at iteration t.
0018 %
0019 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0020 %       2 = print main steps; default = 1).
0021 %
0022 %   - A: Forward transform (default = Identity).
0023 %
0024 %   - At: Adjoint of At (default = Identity).
0025 %
0026 %   - nu: Bound on the norm^2 of the operator A, i.e.
0027 %       ||A x||^2 <= nu * ||x||^2 (default = 1)
0028 %
0029 % Reference:
0030 % [1] A. Beck and  M. Teboulle, "Fast gradient-based algorithms for
0031 % constrained Total Variation Image Denoising and Deblurring Problems",
0032 % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434,
0033 % November 2009.
0034 
0035 % Optional input arguments
0036 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0037 if ~isfield(param, 'verbose'), param.verbose = 1; end
0038 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0039 if ~isfield(param, 'At'), param.At = @(x) x; end
0040 if ~isfield(param, 'A'), param.A = @(x) x; end
0041 if ~isfield(param, 'nu'), param.nu = 1; end
0042 
0043 % Advanced input arguments (not exposed in documentation)
0044 if ~isfield(param, 'weights_dx'), param.weights_dx = 1; end
0045 if ~isfield(param, 'weights_dy'), param.weights_dy = 1; end
0046 if ~isfield(param, 'zero_weights_flag'), param.zero_weights_flag = 1; end
0047 if ~isfield(param, 'identical_weights_flag')
0048     param.identical_weights_flag = 0; 
0049 end
0050 if ~isfield(param, 'sphere_flag'), param.sphere_flag = 0; end
0051 if ~isfield(param, 'incNP'), param.incNP = 0; end
0052 
0053 % Set grad and div operators to planar or spherical case and also
0054 % include weights or not (depending on parameter flags).
0055 if (param.sphere_flag)
0056    G = @sopt_mltb_gradient_op_sphere;
0057    D = @sopt_mltb_div_op_sphere;
0058 else
0059    G = @sopt_mltb_gradient_op;
0060    D = @sopt_mltb_div_op;
0061 end
0062 
0063 if (~param.identical_weights_flag && param.zero_weights_flag)
0064     grad = @(x) G(x, param.weights_dx, param.weights_dy);
0065     div = @(r, s) D(r, s, param.weights_dx, param.weights_dy);
0066     max_weights = max([abs(param.weights_dx(:)); ...
0067         abs(param.weights_dy(:))])^2;
0068 else
0069     grad = @(x) G(x);
0070     div = @(r, s) D(r, s);
0071 end
0072 
0073 % Initializations
0074 [r, s] = grad(param.A(b*0));
0075 pold = r; qold = s;
0076 told = 1; prev_obj = 0;
0077 
0078 % Main iterations
0079 if param.verbose > 1
0080     fprintf('  Proximal TV operator:\n');
0081 end
0082 for iter = 1:param.max_iter
0083     
0084     % Current solution
0085     sol = b - lambda*param.At(div(r, s));
0086     
0087     % Objective function value
0088     obj = .5*norm(b(:)-sol(:), 2) + lambda * ...
0089         sopt_mltb_TV_norm(param.A(sol), param.weights_dx, param.weights_dy);
0090     rel_obj = abs(obj-prev_obj)/obj;
0091     prev_obj = obj;
0092     
0093     % Stopping criterion
0094     if param.verbose>1
0095         fprintf('   Iter %i, obj = %e, rel_obj = %e\n', ...
0096             iter, obj, rel_obj);
0097     end
0098     if rel_obj < param.rel_obj
0099         crit_TV = 'TOL_EPS'; break;
0100     end
0101     
0102     % Udpate divergence vectors and project
0103     [dx, dy] = grad(param.A(sol));
0104     if (param.identical_weights_flag)
0105         r = r - 1/(8*lambda*param.nu) * dx;
0106         s = s - 1/(8*lambda*param.nu) * dy;
0107         weights = max(param.weights_dx, sqrt(abs(r).^2+abs(s).^2));
0108         p = r./weights.*param.weights_dx; q = s./weights.*param.weights_dx;
0109     else
0110         if (~param.zero_weights_flag)
0111             r = r - 1/(8*lambda*param.nu) * dx;
0112             s = s - 1/(8*lambda*param.nu) * dy;
0113             weights = max(1, sqrt(abs(r./param.weights_dx).^2+...
0114                 abs(s./param.weights_dy).^2));
0115             p = r./weights; q = s./weights;
0116         else
0117             % Weights go into grad and div operators so usual update
0118             r = r - 1/(8*lambda*param.nu*max_weights) * dx;
0119             s = s - 1/(8*lambda*param.nu*max_weights) * dy;
0120             weights = max(1, sqrt(abs(r).^2+abs(s).^2));
0121             p = r./weights; q = s./weights;
0122         end
0123     end
0124     
0125     % FISTA update
0126     t = (1+sqrt(4*told^2))/2;
0127     r = p + (told-1)/t * (p - pold); pold = p;
0128     s = q + (told-1)/t * (q - qold); qold = q;
0129     told = t;
0130     
0131 end
0132 
0133 % Log after the minimization
0134 if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end
0135 if param.verbose >= 1
0136     fprintf(['  Prox_TV: obj = %e, rel_obj = %e,' ...
0137         ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter);
0138 end
0139 
0140 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_BPDN.html000066400000000000000000000411461277570055300226700ustar00rootroot00000000000000 Description of sopt_mltb_solve_BPDN
Home > matlab > sopt_mltb_solve_BPDN.m

sopt_mltb_solve_BPDN

PURPOSE ^

sopt_mltb_solve_BPDN - Solve BPDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param)

DESCRIPTION ^

 sopt_mltb_solve_BPDN - Solve BPDN problem

 Solve the Basis Pursuit Denoising (BPDN) problem

   min ||Psit x||_1   s.t.  ||y-A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator, Psit is a sparfying transform and
 Psi its adjoint. The structure param should contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of L1 norm when solving for
       L1 proximal operator) (default = 1e-1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - rel_obj_L1: Used as stopping criterion for the proximal L1
       operator. Minimum relative change of the objective value between
       two successive estimates.

   - max_iter_L1: Used as stopping criterion for the proximal L1
       operator. Maximun number of iterations.
 
   - param.nu_L1: Bound on the norm^2 of the operator Psi, i.e.
       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
 
   - param.tight_L1: 1 if Psit is a tight frame, 0 otherwise 
       (default = 1).
 
   - param.weights: Weights for a weighted L1-norm defined
       by sum_i{weights_i.*abs(x_i)} (default = 1). 

   - pos_l1: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

 References:
 [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting 
 Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
 of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param)
0002 % sopt_mltb_solve_BPDN - Solve BPDN problem
0003 %
0004 % Solve the Basis Pursuit Denoising (BPDN) problem
0005 %
0006 %   min ||Psit x||_1   s.t.  ||y-A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator, Psit is a sparfying transform and
0010 % Psi its adjoint. The structure param should contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of L1 norm when solving for
0025 %       L1 proximal operator) (default = 1e-1).
0026 %
0027 %   - initsol: Initial solution for a warmstart.
0028 %
0029 %   Projection onto the L2-ball:
0030 %
0031 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0032 %
0033 %   - nu_B2: Bound on the norm of the operator A, i.e.
0034 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0035 %
0036 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0037 %       stops if
0038 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0039 %       (default = 1e-3).
0040 %
0041 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0042 %       L2 ball (default = 200).
0043 %
0044 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0045 %       default = 0).
0046 %
0047 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   Proximal L1 operator:
0051 %
0052 %   - rel_obj_L1: Used as stopping criterion for the proximal L1
0053 %       operator. Minimum relative change of the objective value between
0054 %       two successive estimates.
0055 %
0056 %   - max_iter_L1: Used as stopping criterion for the proximal L1
0057 %       operator. Maximun number of iterations.
0058 %
0059 %   - param.nu_L1: Bound on the norm^2 of the operator Psi, i.e.
0060 %       ||Psi x||^2 <= nu * ||x||^2 (default = 1).
0061 %
0062 %   - param.tight_L1: 1 if Psit is a tight frame, 0 otherwise
0063 %       (default = 1).
0064 %
0065 %   - param.weights: Weights for a weighted L1-norm defined
0066 %       by sum_i{weights_i.*abs(x_i)} (default = 1).
0067 %
0068 %   - pos_l1: Positivity flag (1 to impose positivity, 0 otherwise;
0069 %       default = 0).
0070 %
0071 % References:
0072 % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting
0073 % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
0074 % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0075 
0076 % Optional input arguments
0077 if ~isfield(param, 'verbose'), param.verbose = 1; end
0078 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0079 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0080 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0081 if ~isfield(param, 'pos_l1'), param.pos_l1 = 0; end
0082 
0083 % Input arguments for projection onto the L2 ball
0084 param_B2.A = A; param_B2.At = At;
0085 param_B2.y = y; param_B2.epsilon = epsilon;
0086 param_B2.verbose = param.verbose;
0087 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0088 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0089 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0090 if isfield(param, 'max_iter_B2')
0091     param_B2.max_iter = param.max_iter_B2;
0092 end
0093 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0094 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0095 
0096 % Input arguments for prox L1
0097 param_L1.Psi = Psi; param_L1.Psit = Psit; param_L1.pos = param.pos_l1;
0098 param_L1.verbose = param.verbose; 
0099 %param_L1.verbose = 2;
0100 param_L1.rel_obj = param.rel_obj;
0101 if isfield(param, 'nu_L1')
0102     param_L1.nu = param.nu_L1;
0103 end
0104 if isfield(param, 'tight_L1')
0105     param_L1.tight = param.tight_L1;
0106 end
0107 if isfield(param, 'max_iter_L1')
0108     param_L1.max_iter = param.max_iter_L1;
0109 end
0110 if isfield(param, 'rel_obj_L1')
0111     param_L1.rel_obj = param.rel_obj_L1;
0112 end
0113 if isfield(param, 'weights')
0114     param_L1.weights = param.weights;
0115 else
0116     param_L1.weights = 1;
0117 end
0118 
0119 % Initialization
0120 if isfield(param,'initsol')
0121     xhat = param.initsol;
0122 else
0123     xhat = At(y); 
0124 end
0125 
0126 iter = 1; prev_norm = 0;
0127 
0128 % Main loop
0129 while 1
0130     
0131     if param.verbose >= 1
0132         fprintf('Iteration %i:\n', iter);
0133     end
0134     
0135     % Projection onto the L2-ball
0136     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0137     
0138     % Global stopping criterion
0139     dummy = Psit(sol);
0140     curr_norm = sum(param_L1.weights(:).*abs(dummy(:)));    
0141     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0142     if param.verbose >= 1
0143         fprintf('  ||x||_1 = %e, rel_norm = %e\n', ...
0144             curr_norm, rel_norm);
0145     end
0146     if (rel_norm < param.rel_obj)
0147         crit_BPDN = 'REL_NORM';
0148         break;
0149     elseif iter >= param.max_iter
0150         crit_BPDN = 'MAX_IT';
0151         break;
0152     end
0153     
0154     % Proximal L1 operator
0155     xhat = 2*sol - xhat;
0156     temp = sopt_mltb_prox_L1(xhat, param.gamma, param_L1);
0157     xhat = temp + sol - xhat;
0158     
0159     % Update variables
0160     iter = iter + 1;
0161     prev_norm = curr_norm;
0162     
0163 end
0164 
0165 % Log
0166 if param.verbose >= 1
0167   
0168     % L1 norm
0169     fprintf('\n Solution found:\n');
0170     fprintf(' Final L1 norm: %e\n', curr_norm);
0171     
0172     % Residual
0173     dummy = A(sol); res = norm(y(:)-dummy(:), 2);
0174     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res);
0175     
0176     % Stopping criterion
0177     fprintf(' %i iterations\n', iter);
0178     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0179     
0180 end
0181 
0182 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_L2DN.html000066400000000000000000000314111277570055300226360ustar00rootroot00000000000000 Description of sopt_mltb_solve_L2DN
Home > matlab > sopt_mltb_solve_L2DN.m

sopt_mltb_solve_L2DN

PURPOSE ^

sopt_mltb_solve_L2DN - Solve L2DN problem.

SYNOPSIS ^

function sol = sopt_mltb_solve_L2DN(y, epsilon, A, At, param)

DESCRIPTION ^

 sopt_mltb_solve_L2DN - Solve L2DN problem.

 Solve the L2 denoising problem

   min ||x||_2   s.t.  ||y-A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator. The structure param should 
 contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_2 - ||x(t-1)||_2 | / ||x(t)||_2 < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of L1 norm when solving for
       L1 proximal operator) (default = 1e-1).

   - param.weights: weightsfor a weighted L2-norm defined
       by norm(weights_i.*x_i,2) (default = 1).

   - initsol: Initial solution for a warmstart.

   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).

 References:
 [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting 
 Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
 of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_L2DN(y, epsilon, A, At, param)
0002 % sopt_mltb_solve_L2DN - Solve L2DN problem.
0003 %
0004 % Solve the L2 denoising problem
0005 %
0006 %   min ||x||_2   s.t.  ||y-A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator. The structure param should
0010 % contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_2 - ||x(t-1)||_2 | / ||x(t)||_2 < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of L1 norm when solving for
0025 %       L1 proximal operator) (default = 1e-1).
0026 %
0027 %   - param.weights: weightsfor a weighted L2-norm defined
0028 %       by norm(weights_i.*x_i,2) (default = 1).
0029 %
0030 %   - initsol: Initial solution for a warmstart.
0031 %
0032 %   Projection onto the L2-ball:
0033 %
0034 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0035 %
0036 %   - nu_B2: Bound on the norm of the operator A, i.e.
0037 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0038 %
0039 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0040 %       stops if
0041 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0042 %       (default = 1e-3).
0043 %
0044 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0045 %       L2 ball (default = 200).
0046 %
0047 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0051 %       default = 0).
0052 %
0053 % References:
0054 % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting
0055 % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal
0056 % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0057 
0058 % Optional input arguments
0059 if ~isfield(param, 'verbose'), param.verbose = 1; end
0060 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0061 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0062 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0063 if ~isfield(param, 'weights'), param.weights = 1; end
0064 
0065 % Input arguments for projection onto the L2 ball
0066 param_B2.A = A; param_B2.At = At;
0067 param_B2.y = y; param_B2.epsilon = epsilon;
0068 param_B2.verbose = param.verbose;
0069 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0070 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0071 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0072 if isfield(param, 'max_iter_B2')
0073     param_B2.max_iter = param.max_iter_B2;
0074 end
0075 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0076 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0077 
0078 % Initialization
0079 if isfield(param,'initsol')
0080     xhat = param.initsol;
0081 else
0082     xhat = At(y); 
0083 end
0084 
0085 iter = 1; prev_norm = 0;
0086 
0087 % Main loop
0088 while 1
0089     
0090     %
0091     if param.verbose >= 1
0092         fprintf('Iteration %i:\n', iter);
0093     end
0094     
0095     % Projection onto the L2-ball
0096     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0097     
0098     % Global stopping criterion
0099     dummy = sol;
0100     curr_norm = norm(param.weights(:).*dummy(:));    
0101     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0102     if param.verbose >= 1
0103         fprintf('  ||x||_1 = %e, rel_norm = %e\n', ...
0104             curr_norm, rel_norm);
0105     end
0106     if (rel_norm < param.rel_obj)
0107         crit_BPDN = 'REL_NORM';
0108         break;
0109     elseif iter >= param.max_iter
0110         crit_BPDN = 'MAX_IT';
0111         break;
0112     end
0113     
0114     % Proximal L2 operator
0115     xhat = 2*sol - xhat;   
0116     temp = xhat ./ (1 + 2*param.weights);    
0117     xhat = temp + sol - xhat;
0118     
0119     % Update variables
0120     iter = iter + 1;
0121     prev_norm = curr_norm;
0122     
0123 end
0124 
0125 % Log
0126 if param.verbose >= 1
0127   
0128     % L1 norm
0129     fprintf('\n Solution found:\n');
0130     fprintf(' Final L1 norm: %e\n', curr_norm);
0131     
0132     % Residual
0133     dummy = A(sol); res = norm(y(:)-dummy(:), 2);
0134     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res);
0135     
0136     % Stopping criterion
0137     fprintf(' %i iterations\n', iter);
0138     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0139     
0140 end
0141 
0142 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_TVDN.html000066400000000000000000000330451277570055300227170ustar00rootroot00000000000000 Description of sopt_mltb_solve_TVDN
Home > matlab > sopt_mltb_solve_TVDN.m

sopt_mltb_solve_TVDN

PURPOSE ^

sopt_mltb_solve_TVDN - Solve TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param)

DESCRIPTION ^

 sopt_mltb_solve_TVDN - Solve TVDN problem

 Solve the total variation denoising (TVDN) problem

   min ||x||_TV   s.t.  ||y - A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator. The structure param should
 contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of TV norm when solving for
       TV proximal operator) (default = 1e-1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - max_iter_TV: Used as stopping criterion for the proximal TV
       operator. Maximun number of iterations (default = 200).

 References:
 P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
 to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
 Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param)
0002 % sopt_mltb_solve_TVDN - Solve TVDN problem
0003 %
0004 % Solve the total variation denoising (TVDN) problem
0005 %
0006 %   min ||x||_TV   s.t.  ||y - A x||_2 < epsilon
0007 %
0008 % where y contains the measurements, A is the forward measurement operator
0009 % and At the associated adjoint operator. The structure param should
0010 % contain the following fields:
0011 %
0012 %   General parameters:
0013 %
0014 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0015 %       2 = print main steps; default = 1).
0016 %
0017 %   - max_iter: Maximum number of iterations (default = 200).
0018 %
0019 %   - rel_obj: Minimum relative change of the objective value
0020 %       (default = 1e-4).  The algorithm stops if
0021 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0022 %       where x(t) is the estimate of the solution at iteration t.
0023 %
0024 %   - gamma: Convergence speed (weighting of TV norm when solving for
0025 %       TV proximal operator) (default = 1e-1).
0026 %
0027 %   - initsol: Initial solution for a warmstart.
0028 %
0029 %   Projection onto the L2-ball:
0030 %
0031 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0032 %
0033 %   - nu_B2: Bound on the norm of the operator A, i.e.
0034 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0035 %
0036 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0037 %       stops if
0038 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0039 %       (default = 1e-3).
0040 %
0041 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0042 %       L2 ball (default = 200).
0043 %
0044 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0045 %       default = 0).
0046 %
0047 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0048 %       default = 0).
0049 %
0050 %   Proximal L1 operator:
0051 %
0052 %   - max_iter_TV: Used as stopping criterion for the proximal TV
0053 %       operator. Maximun number of iterations (default = 200).
0054 %
0055 % References:
0056 % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
0057 % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
0058 % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0059 
0060 % Optional input arguments
0061 if ~isfield(param, 'verbose'), param.verbose = 1; end
0062 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0063 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0064 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0065 
0066 % Input arguments for projection onto the L2 ball
0067 param_B2.A = A; param_B2.At = At;
0068 param_B2.y = y; param_B2.epsilon = epsilon;
0069 param_B2.verbose = param.verbose;
0070 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0071 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0072 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0073 if isfield(param, 'max_iter_B2')
0074     param_B2.max_iter = param.max_iter_B2;
0075 end
0076 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0077 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0078 
0079 % Input arguments for prox TV
0080 param_TV.verbose = param.verbose; param_TV.rel_obj = param.rel_obj;
0081 if isfield(param, 'max_iter_TV')
0082     param_TV.max_iter= param.max_iter_TV;
0083 end
0084 
0085 % Initialization
0086 if isfield(param,'initsol')
0087     xhat = param.initsol;
0088 else
0089     xhat = At(y); 
0090 end 
0091 
0092 iter = 1; prev_norm = 0;
0093 
0094 % Main loop
0095 while 1
0096     
0097     if param.verbose>=1
0098         fprintf('Iteration %i:\n', iter);
0099     end
0100     
0101     % Projection onto the L2-ball
0102     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);
0103     
0104     % Global stopping criterion
0105     curr_norm = sopt_mltb_TV_norm(sol, 0);
0106     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0107     if param.verbose >= 1
0108         fprintf('  ||x||_TV = %e, rel_norm = %e\n', ...
0109             curr_norm, rel_norm);
0110     end
0111     if (rel_norm < param.rel_obj)
0112         crit_BPDN = 'REL_NORM';
0113         break;
0114     elseif iter >= param.max_iter
0115         crit_BPDN = 'MAX_IT';
0116         break;
0117     end
0118     
0119     % Proximal L1 operator
0120     xhat = 2*sol - xhat;
0121     temp = sopt_mltb_prox_TV(xhat, param.gamma, param_TV);
0122     xhat = temp + sol - xhat;
0123     
0124     % Update variables
0125     iter = iter + 1;
0126     prev_norm = curr_norm;
0127     
0128 end
0129 
0130 % Log
0131 if param.verbose >= 1
0132   
0133     % L1 norm
0134     fprintf('\n Solution found:\n');
0135     fprintf(' Final TV norm: %e\n', curr_norm);
0136     
0137     % Residual
0138     temp = A(sol);
0139     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ...
0140         norm(y(:)-temp(:)));
0141     
0142     % Stopping criterion
0143     fprintf(' %i iterations\n', iter);
0144     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0145     
0146 end
0147 
0148 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_TVDNoA.html000066400000000000000000000411271277570055300231770ustar00rootroot00000000000000 Description of sopt_mltb_solve_TVDNoA
Home > matlab > sopt_mltb_solve_TVDNoA.m

sopt_mltb_solve_TVDNoA

PURPOSE ^

sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, S, St, param)

DESCRIPTION ^

 sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem

 Solve the total variation denoising (TVDN) problem when an additional 
 linear operator S is incorporated in the TV norm, i.e. solve

   min ||S x||_TV   s.t.  ||y - A x||_2 < epsilon

 where y contains the measurements, A is the forward measurement operator 
 and At the associated adjoint operator, S is the operator appearing in
 the TV norm and St the associated adjoint operator.  The structure param 
 should contain the following fields:

   General parameters:
 
   - verbose: Verbosity level (0 = no log, 1 = summary at convergence, 
       2 = print main steps; default = 1).

   - max_iter: Maximum number of iterations (default = 200).

   - rel_obj: Minimum relative change of the objective value 
       (default = 1e-4).  The algorithm stops if
           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
       where x(t) is the estimate of the solution at iteration t.

   - gamma: Convergence speed (weighting of TV norm when solving for
       TV proximal operator) (default = 1e-1).
 
   - nu_TV: Bound on the norm of the operator S, i.e.
       ||S x||^2 <= nu * ||x||^2 (default = 1).

   - initsol: Initial solution for a warmstart.
 
   Projection onto the L2-ball:

   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
 
   - nu_B2: Bound on the norm of the operator A, i.e.
       ||A x||^2 <= nu * ||x||^2 (default = 1).

   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
       stops if
         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
       (default = 1e-3).

   - max_iter_B2: Maximum number of iterations for the projection onto the
       L2 ball (default = 200).

   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
       default = 0).

   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
       default = 0).
 
   Proximal L1 operator:

   - max_iter_TV: Used as stopping criterion for the proximal TV
       operator. Maximun number of iterations (default = 200).

   - param.weights_dx_TV: Weights for a weighted TV-norm in the x
       direction (default = 1).

   - param.weights_dy_TV: Weights for a weighted TV-norm in the y
       direction (default = 1).

 References:
 P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach 
 to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of 
 Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.

CROSS-REFERENCE INFORMATION ^

This function calls:
This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, S, St, param)
0002 % sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem
0003 %
0004 % Solve the total variation denoising (TVDN) problem when an additional
0005 % linear operator S is incorporated in the TV norm, i.e. solve
0006 %
0007 %   min ||S x||_TV   s.t.  ||y - A x||_2 < epsilon
0008 %
0009 % where y contains the measurements, A is the forward measurement operator
0010 % and At the associated adjoint operator, S is the operator appearing in
0011 % the TV norm and St the associated adjoint operator.  The structure param
0012 % should contain the following fields:
0013 %
0014 %   General parameters:
0015 %
0016 %   - verbose: Verbosity level (0 = no log, 1 = summary at convergence,
0017 %       2 = print main steps; default = 1).
0018 %
0019 %   - max_iter: Maximum number of iterations (default = 200).
0020 %
0021 %   - rel_obj: Minimum relative change of the objective value
0022 %       (default = 1e-4).  The algorithm stops if
0023 %           | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj,
0024 %       where x(t) is the estimate of the solution at iteration t.
0025 %
0026 %   - gamma: Convergence speed (weighting of TV norm when solving for
0027 %       TV proximal operator) (default = 1e-1).
0028 %
0029 %   - nu_TV: Bound on the norm of the operator S, i.e.
0030 %       ||S x||^2 <= nu * ||x||^2 (default = 1).
0031 %
0032 %   - initsol: Initial solution for a warmstart.
0033 %
0034 %   Projection onto the L2-ball:
0035 %
0036 %   - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1).
0037 %
0038 %   - nu_B2: Bound on the norm of the operator A, i.e.
0039 %       ||A x||^2 <= nu * ||x||^2 (default = 1).
0040 %
0041 %   - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms
0042 %       stops if
0043 %         epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol)
0044 %       (default = 1e-3).
0045 %
0046 %   - max_iter_B2: Maximum number of iterations for the projection onto the
0047 %       L2 ball (default = 200).
0048 %
0049 %   - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise;
0050 %       default = 0).
0051 %
0052 %   - real_B2: Reality flag (1 to impose reality, 0 otherwise;
0053 %       default = 0).
0054 %
0055 %   Proximal L1 operator:
0056 %
0057 %   - max_iter_TV: Used as stopping criterion for the proximal TV
0058 %       operator. Maximun number of iterations (default = 200).
0059 %
0060 %   - param.weights_dx_TV: Weights for a weighted TV-norm in the x
0061 %       direction (default = 1).
0062 %
0063 %   - param.weights_dy_TV: Weights for a weighted TV-norm in the y
0064 %       direction (default = 1).
0065 %
0066 % References:
0067 % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach
0068 % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of
0069 % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007.
0070 
0071 % Optional input arguments
0072 if ~isfield(param, 'verbose'), param.verbose = 1; end
0073 if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end
0074 if ~isfield(param, 'max_iter'), param.max_iter = 200; end
0075 if ~isfield(param, 'gamma'), param.gamma = 1e-2; end
0076 if ~isfield(param, 'weights_dx_TV'), param.weights_dx_TV = 1.0; end
0077 if ~isfield(param, 'weights_dy_TV'), param.weights_dy_TV = 1.0; end
0078 if ~isfield(param, 'incNP'), param.incNP = false; end
0079 if ~isfield(param, 'sphere_flag'), param.sphere_flag = false; end
0080 
0081 % Input arguments for projection onto the L2 ball
0082 param_B2.A = A; param_B2.At = At;
0083 param_B2.y = y; param_B2.epsilon = epsilon;
0084 param_B2.verbose = param.verbose;
0085 if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end
0086 if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end
0087 if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end
0088 if isfield(param, 'max_iter_B2')
0089     param_B2.max_iter = param.max_iter_B2;
0090 end
0091 if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end
0092 if isfield(param,'real_B2'), param_B2.real=param.real_B2; end
0093 
0094 % Input arguments for prox TVoA
0095 param_TV.A = S; param_TV.At = St;
0096 param_TV.verbose = param.verbose; 
0097 param_TV.rel_obj = param.rel_obj;
0098 param_TV.weights_dx = param.weights_dx_TV;
0099 param_TV.weights_dy = param.weights_dy_TV;
0100 if isfield(param, 'nu_TV')
0101    param_TV.nu = param.nu_TV; 
0102 end
0103 if isfield(param, 'max_iter_TV')
0104     param_TV.max_iter= param.max_iter_TV;
0105 end
0106 if isfield(param, 'zero_weights_flag_TV')
0107    param_TV.zero_weights_flag = param.zero_weights_flag_TV; 
0108 end
0109 if isfield(param, 'identical_weights_flag_TV'), 
0110    param_TV.identical_weights_flag = param.identical_weights_flag_TV;
0111 end
0112 if isfield(param, 'sphere_flag'), 
0113    param_TV.sphere_flag = param.sphere_flag;
0114    param_TV.incNP = param.incNP;
0115 end
0116 
0117 
0118 % Initialization
0119 if isfield(param,'initsol')
0120     xhat = param.initsol;
0121 else
0122     xhat = At(y); 
0123 end
0124 
0125 iter = 1; prev_norm = 0;
0126 
0127 % Main loop
0128 while 1
0129     
0130     %
0131     if param.verbose>=1
0132         fprintf('Iteration %i:\n', iter);
0133     end
0134     
0135     % Projection onto the L2-ball
0136     [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2);    
0137     
0138     % Global stopping criterion
0139     curr_norm = sopt_mltb_TV_norm(S(sol), param_TV.sphere_flag, param_TV.incNP, param_TV.weights_dx, param_TV.weights_dy);
0140     rel_norm = abs(curr_norm - prev_norm)/curr_norm;
0141     if param.verbose >= 1
0142         fprintf('  ||x||_TV = %e, rel_norm = %e\n', ...
0143             curr_norm, rel_norm);
0144     end
0145     if (rel_norm < param.rel_obj)
0146         crit_BPDN = 'REL_NORM';
0147         break;
0148     elseif iter >= param.max_iter
0149         crit_BPDN = 'MAX_IT';
0150         break;
0151     end
0152     
0153     % Proximal L1 operator
0154     xhat = 2*sol - xhat;
0155     temp = sopt_mltb_prox_TVoA(xhat, param.gamma, param_TV);
0156     xhat = temp + sol - xhat;
0157     
0158     % Update variables
0159     iter = iter + 1;
0160     prev_norm = curr_norm;
0161     
0162 end
0163 
0164 % Log
0165 if param.verbose>=1
0166     % L1 norm
0167     fprintf('\n Solution found:\n');
0168     fprintf(' Final TV norm: %e\n', curr_norm);
0169     
0170     % Residual
0171     temp = A(sol);
0172     fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ...
0173         norm(y(:)-temp(:)));
0174     
0175     % Stopping criterion
0176     fprintf(' %i iterations\n', iter);
0177     fprintf(' Stopping criterion: %s \n\n', crit_BPDN);
0178     
0179 end
0180 
0181 end

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_rwBPDN.html000066400000000000000000000224301277570055300232340ustar00rootroot00000000000000 Description of sopt_mltb_solve_rwBPDN
Home > matlab > sopt_mltb_solve_rwBPDN.m

sopt_mltb_solve_rwBPDN

PURPOSE ^

sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit,paramT, sigma, tol, maxiter, initsol)

DESCRIPTION ^

 sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem

 Solve the reweighted L1 minimization function using an homotopy
 continuation method to approximate the L0 norm.  At each iteration the 
 following problem is solved:

   min_x ||W Psit x||_1   s.t.  ||y-A x||_2 < epsilon

 where W is a diagonal matrix with diagonal elements given by

   [W]_ii = delta(t)/(delta(t)+|[Psit x(t)]_i|).

 The input parameters are defined as follows.

   - y: Input data (measurements).

   - epsilon: Noise bound.

   - A: Forward measurement operator.

   - At: Adjoint measurement operator.

   - Psi: Synthesis sparsity transform.

   - Psit: Analysis sparsity transform.

   - paramT: Structure containing parameters for the L1 solver (see 
       documentation for sopt_mltb_solve_BPDN).  

   - sigma: Noise standard deviation in the analysis domain.

   - tol: Minimum relative change in the solution.
       The algorithm stops if 
           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
       where x(t) is the estimate of the solution at iteration t.

   - maxiter: Maximum number of iterations of the reweighted algorithm.

   - initsol: Initial solution for a warmstart.

 References:
 [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and 
 Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc. 
 Let., in press, 2013.
 [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging 
 Reweighted Analysis (SARA): a novel algorithm for radio-interferometric 
 imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, ...
0002   paramT, sigma, tol, maxiter, initsol)
0003 % sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem
0004 %
0005 % Solve the reweighted L1 minimization function using an homotopy
0006 % continuation method to approximate the L0 norm.  At each iteration the
0007 % following problem is solved:
0008 %
0009 %   min_x ||W Psit x||_1   s.t.  ||y-A x||_2 < epsilon
0010 %
0011 % where W is a diagonal matrix with diagonal elements given by
0012 %
0013 %   [W]_ii = delta(t)/(delta(t)+|[Psit x(t)]_i|).
0014 %
0015 % The input parameters are defined as follows.
0016 %
0017 %   - y: Input data (measurements).
0018 %
0019 %   - epsilon: Noise bound.
0020 %
0021 %   - A: Forward measurement operator.
0022 %
0023 %   - At: Adjoint measurement operator.
0024 %
0025 %   - Psi: Synthesis sparsity transform.
0026 %
0027 %   - Psit: Analysis sparsity transform.
0028 %
0029 %   - paramT: Structure containing parameters for the L1 solver (see
0030 %       documentation for sopt_mltb_solve_BPDN).
0031 %
0032 %   - sigma: Noise standard deviation in the analysis domain.
0033 %
0034 %   - tol: Minimum relative change in the solution.
0035 %       The algorithm stops if
0036 %           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
0037 %       where x(t) is the estimate of the solution at iteration t.
0038 %
0039 %   - maxiter: Maximum number of iterations of the reweighted algorithm.
0040 %
0041 %   - initsol: Initial solution for a warmstart.
0042 %
0043 % References:
0044 % [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and
0045 % Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc.
0046 % Let., in press, 2013.
0047 % [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging
0048 % Reweighted Analysis (SARA): a novel algorithm for radio-interferometric
0049 % imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.
0050 
0051 param=paramT;
0052 iter=0;
0053 rel_dist=1;
0054 
0055 if nargin<11
0056     fprintf('RW iteration: %i\n', iter);
0057     sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0058 else
0059     sol = initsol;
0060 end
0061 
0062 temp=Psit(sol);
0063 delta=std(temp(:));
0064 
0065 while (rel_dist>tol && iter<maxiter)
0066   
0067     iter=iter+1;
0068     delta=max(sigma/10,delta);
0069     fprintf('RW iteration: %i\n', iter);
0070     fprintf('delta = %e\n', delta);
0071     
0072     % Weights
0073     weights=abs(Psit(sol));
0074     param.weights=delta./(delta+weights);
0075     
0076     % Warm start
0077     param.initsol=sol;
0078     param.gamma=1e-1*max(weights(:));
0079     sol1=sol;
0080     
0081     % Weighted L1 problem
0082     sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param);
0083     
0084     % Relative distance
0085     rel_dist=norm(sol(:)-sol1(:))/norm(sol1(:));
0086     fprintf('Relative distance = %e\n\n', rel_dist);
0087     delta = delta/10;
0088     
0089 end
0090

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlab/sopt_mltb_solve_rwTVDN.html000066400000000000000000000217451277570055300232740ustar00rootroot00000000000000 Description of sopt_mltb_solve_rwTVDN
Home > matlab > sopt_mltb_solve_rwTVDN.m

sopt_mltb_solve_rwTVDN

PURPOSE ^

sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

SYNOPSIS ^

function sol = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, paramT,sigma, tol, maxiter, initsol)

DESCRIPTION ^

 sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem

 Solve the reweighted TV minimization function using an homotopy
 continuation method to approximate the L0 norm of the magnitude of the 
 gradient.  At each iteration the following problem is solved:

   min_x ||W x||_TV   s.t.  ||y-A x||_2 < epsilon

 where W is a diagonal matrix with diagonal elements given by esentially
 the inverse of the graident.
   
 The input parameters are defined as follows.

   - y: Input data (measurements).

   - epsilon: Noise bound.

   - A: Forward measurement operator.

   - At: Adjoint measurement operator.

   - paramT: Structure containing parameters for the TV solver (see 
       documentation for sopt_mltb_solve_TVDN).  

   - sigma: Noise standard deviation in the analysis domain.

   - tol: Minimum relative change in the solution.
       The algorithm stops if 
           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
       where x(t) is the estimate of the solution at iteration t.

   - maxiter: Maximum number of iterations of the reweighted algorithm.

   - initsol: Initial solution for a warmstart.

 References:
 [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and 
 Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc. 
 Let., in press, 2013.
 [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging 
 Reweighted Analysis (SARA): a novel algorithm for radio-interferometric 
 imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function sol = sopt_mltb_solve_rwTVDN(y, epsilon, A, At, paramT, ...
0002   sigma, tol, maxiter, initsol)
0003 % sopt_mltb_solve_rwTVDN - Solve reweighted TVDN problem
0004 %
0005 % Solve the reweighted TV minimization function using an homotopy
0006 % continuation method to approximate the L0 norm of the magnitude of the
0007 % gradient.  At each iteration the following problem is solved:
0008 %
0009 %   min_x ||W x||_TV   s.t.  ||y-A x||_2 < epsilon
0010 %
0011 % where W is a diagonal matrix with diagonal elements given by esentially
0012 % the inverse of the graident.
0013 %
0014 % The input parameters are defined as follows.
0015 %
0016 %   - y: Input data (measurements).
0017 %
0018 %   - epsilon: Noise bound.
0019 %
0020 %   - A: Forward measurement operator.
0021 %
0022 %   - At: Adjoint measurement operator.
0023 %
0024 %   - paramT: Structure containing parameters for the TV solver (see
0025 %       documentation for sopt_mltb_solve_TVDN).
0026 %
0027 %   - sigma: Noise standard deviation in the analysis domain.
0028 %
0029 %   - tol: Minimum relative change in the solution.
0030 %       The algorithm stops if
0031 %           ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol.
0032 %       where x(t) is the estimate of the solution at iteration t.
0033 %
0034 %   - maxiter: Maximum number of iterations of the reweighted algorithm.
0035 %
0036 %   - initsol: Initial solution for a warmstart.
0037 %
0038 % References:
0039 % [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and
0040 % Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc.
0041 % Let., in press, 2013.
0042 % [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging
0043 % Reweighted Analysis (SARA): a novel algorithm for radio-interferometric
0044 % imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012.
0045 
0046 Psit = @(x) x; Psi=@(x) x;
0047 
0048 param=paramT;
0049 iter=0;
0050 rel_dist=1;
0051 
0052 if nargin<9
0053     fprintf('RW iteration: %i\n', iter);
0054     sol = sopt_mltb_solve_TVoA_B2(y, epsilon, A, At, Psi, Psit, param);
0055 else
0056     sol = initsol;
0057 end
0058 
0059 
0060 delta=std(sol(:));
0061 
0062 while (rel_dist>tol && iter<maxiter)
0063   
0064     iter=iter+1;
0065     delta=max(sigma/10,delta);
0066     fprintf('RW iteration: %i\n', iter);
0067     fprintf('delta = %e\n', delta);
0068     
0069     %Warm start
0070     param.initsol=sol;
0071     sol1=sol;
0072     
0073     % Weights
0074     [param.weights_dx_TV param.weights_dy_TV] = sopt_mltb_gradient_op(real(sol));
0075     param.weights_dx_TV = delta./(abs(param.weights_dx_TV)+delta);
0076     param.weights_dy_TV = delta./(abs(param.weights_dy_TV)+delta);
0077     param.identical_weights_flag_TV = 0;
0078     param.gamma=1e-1*max(abs(sol1(:)));
0079     
0080     %Weighted TV problem
0081     sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, Psi, Psit, param);
0082 
0083     %Relative distance
0084     rel_dist=norm(sol(:)-sol1(:))/norm(sol1(:)); 
0085     fprintf('relative distance = %e\n\n', rel_dist);
0086     delta = delta/10;
0087     
0088 end
0089

Generated on Fri 22-Feb-2013 15:54:47 by m2html © 2005
sopt-2.0.0/matlab/doc/matlabicon.gif000066400000000000000000000010761277570055300173220ustar00rootroot00000000000000GIF89aG3 !SOQ.,-4/2B>O5]b&ch 68:EFh/pqGtudGE.TS.RQ;a` ,{*,3! #Fxy  T ? V N m t U'&D 333!f,fee Ae(;e b&3-=KYe^SGC:*eddNfQCƦrȐQ#2!D8df@;sopt-2.0.0/matlab/doc/mex.png000066400000000000000000000003621277570055300160160ustar00rootroot00000000000000PNG  IHDR gAMA aPLTEpmStRNS@fbKGDH pHYs  ~tIME WCLIDATx]04F)*#n"6tdism#X{Ko(\ ْ}fsIENDB`sopt-2.0.0/matlab/doc/pcode.png000066400000000000000000000003241277570055300163150ustar00rootroot00000000000000PNG  IHDR VmtIME !vcP pHYs  d_gAMA a PLTED`tRNS@fAIDATxc`+ Kb0d f.FHR *b0C x/Ԛ[IENDB`sopt-2.0.0/matlab/doc/right.png000066400000000000000000000002101277570055300163320ustar00rootroot00000000000000PNG  IHDR PLTEfs pHYsHHFk>(IDATxc```Bu5 u6 2 < , !  g^jIENDB`sopt-2.0.0/matlab/doc/sgi.png000066400000000000000000000004071277570055300160070ustar00rootroot00000000000000PNG  IHDRPIDATxm *L*܏l"1X7y!eL"xHt}Lxyn13a΄r ƴ'FŤLC.nB`qcK&u{cjYW0Ùg5q1ա ,*|w&&Υ:bX:kauV۰7FaZp籥ǏבϷ_t%sIIENDB`sopt-2.0.0/matlab/doc/simulinkicon.gif000066400000000000000000000017211277570055300177120ustar00rootroot00000000000000GIF89af3̙f3f3ffffff3f3333f333f3f3̙f3̙̙̙̙f̙3̙ffffff3f3333f333f3̙f3̙̙f3̙f3ff̙ffff3f33̙33f333̙f3ffffff3ffff̙fff3fffffff3ffffffffffff3fff3f3f3f3ff33f3ffffff3f3333f333333̙3f3333333f3333f3f3f3ff3f33f33333333f333333333f333f3̙f3f3ffffff3f3333f333f3wUD"wUD"wUD"ݻwwwUUUDDD"""!8Copyright 1998 The MathWorks, Inc. All rights reserved.!,r$p~d 2dE2j…2$ KR!?0cSL4~o?3a͠-jtМK5TҥQz5kƈX;sopt-2.0.0/matlab/doc/solaris.png000066400000000000000000000004361277570055300167030ustar00rootroot00000000000000PNG  IHDRPIDATxWm - GgWѻuڱ2^B_޳|h@D j'2㺮yiv1̨ۙQ.gFzԏf Pf 47NE.n򦔖e1#GO J݊Py/2kn{kX; 4AshMEV'$| +\jԹ'IO$QO醿ys?~/#tr^J,IENDB`sopt-2.0.0/matlab/doc/up.png000066400000000000000000000002421277570055300156460ustar00rootroot00000000000000PNG  IHDR PLTEfstRNS0JbKGD- pHYsHHFk>'IDATxc```P†@!!EF@5  QIENDB`sopt-2.0.0/matlab/doc/windows.png000066400000000000000000000004361277570055300167210ustar00rootroot00000000000000PNG  IHDRPIDATxWQ0Gӫ*x7F `ӥ[cOV "HE IBk?θm[?χ03ܾ^QJò,юs*O87ERaZ SoJ鐈8O:D"zcb^BIȖpTr0 0) fprintf('Iter = %i, norm = %e \n',k,val); end if (rel_var < tol) break; end init_val=val; x=x/val; end end sopt-2.0.0/matlab/misc/sopt_mltb_SNR.m000066400000000000000000000010751277570055300176120ustar00rootroot00000000000000function snr = sopt_mltb_SNR(map_init, map_recon) % SNR - Compute the SNR between two images % % C omputes the SNR between the maps map_init and map_recon. The SNR is % computed by % 10 * log10( var(MAP_INIT) / var(MAP_INIT-MAP_NOISY) ) % where var stands for the matlab built-in function that computes the % variance. % % Inputs: % % - map_init: Initial image. % % - map_recon: Reconstructed image. % % Outputs: % % - snr: SNR. noise = map_init(:)-map_recon(:); var_init = var(map_init(:)); var_den = var(noise(:)); snr = 10 * log10(var_init/var_den); end sopt-2.0.0/matlab/misc/sopt_mltb_TV_norm.m000066400000000000000000000020651277570055300205340ustar00rootroot00000000000000function y = sopt_mltb_TV_norm(u, sphere_flag, ... incNP, weights_dx, weights_dy) % sopt_mltb_TV_norm - Compute TV norm % % Compute the TV of an image on the plane or sphere. % % Inputs: % % - u: Image to compute TV norm of. % % - sphere_flag: Flag indicating whether to compute the TV norm on the % sphere (1 = on sphere, 2 = on plane). % % - includeNP: Flag indicating whether the North pole is included % in the sampling grid (1 = North pole included, 0 = North pole not % included). % % - weights_dx: Weights in the x (phi) direction. % % - weights_dy: Weights in the y (theta) direction. % % Outputs: % % - y: TV norm of image. if sphere_flag if nargin>3 [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP, weights_dx, weights_dy); else [dx, dy] = sopt_mltb_gradient_op_sphere(u, incNP); end else if nargin>3 [dx, dy] = sopt_mltb_gradient_op(u, weights_dx, weights_dy); else [dx, dy] = sopt_mltb_gradient_op(u); end end temp = sqrt(abs(dx).^2 + abs(dy).^2); y = sum(temp(:)); end sopt-2.0.0/matlab/misc/sopt_mltb_adjcurvelet.m000066400000000000000000000015341277570055300214600ustar00rootroot00000000000000function restim = sopt_mltb_adjcurvelet(coef, Mod, real) % sopt_mltb_adjcurvelet - Adjoint curvelet transform % % Compute the adjoint curvelet transform from the curvelet % coefficient vector. % % Inputs: % % - coef: Input curvelet coefficient vector. % % - Mod: Data structure that stores sizes of the curvelet transform % generated from the CurveLab toolbox. % % - real: Flag indicating if the transform is real or complex (1 = real, % 0 = complex). % % Outputs: % % - restim: Estimated image from the Curvelet coefficients. CR=cell(size(Mod)); marker=0; for s=1:length(Mod) CR{s} = cell(size(Mod{s})); for w=1:length(Mod{s}) m=Mod{s}{w}(1); n=Mod{s}{w}(2); CR{s}{w}=reshape(coef(marker+1:marker+(m*n)),m,n); marker=marker+m*n; end end % Apply adjoint curvelet transform restim = ifdct_usfft(CR,real); sopt-2.0.0/matlab/misc/sopt_mltb_div_op.m000066400000000000000000000012121277570055300204210ustar00rootroot00000000000000function I = sopt_mltb_div_op(dx, dy, weights_dx, weights_dy) % sopt_mltb_div_op - Compute divergence % % Compute the divergence (adjoint of the gradient) of a two dimensional % signal from the horizontal and vertical gradients. % % Inputs: % % - dx: Gradient in x. % % - dy: Gradient in y. % % - weights_dx: Weights in the x direction. % % - weights_dy: Weights in the y direction. % % Outputs: % % - I: Divergence. if nargin > 2 dx = dx .* conj(weights_dx); dy = dy .* conj(weights_dy); end I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)]; I = I + [dy(:, 1) , dy(:, 2:end-1)-dy(:, 1:end-2) , -dy(:, end-1)]; end sopt-2.0.0/matlab/misc/sopt_mltb_div_op_sphere.m000066400000000000000000000021321277570055300217710ustar00rootroot00000000000000function I = sopt_mltb_div_op_sphere(dx, dy, includeNorthpole, ... weights_dx, weights_dy) % sopt_mltb_div_op_sphere - Compute divergence on sphere % % Compute the divergence (adjoint of the gradient) of a two dimensional % signal on the sphere. The phi direction (x) is periodic, while the theta % direction (y) is not. % % Inputs: % % - dx: Gradient in x. % % - dy: Gradient in y. % % - includeNorthPole: Flag indicating whether the North pole is included % in the sampling grid (1 = North pole included, 0 = North pole not % included). % % - weights_dx: Weights in the x (phi) direction. % % - weights_dy: Weights in the y (theta) direction. % % Outputs: % % - I: Divergence. if nargin > 3 dx = dx .* conj(weights_dx); dy = dy .* conj(weights_dy); end if(includeNorthpole) I = [zeros(1, size(dx,2)) ; dx(2, :); dx(3:end-1, :)-dx(2:end-2, :); -dx(end-1, :)]; I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)]; else I = [dx(1, :) ; dx(2:end-1, :)-dx(1:end-2, :) ; -dx(end-1, :)]; I = I + [dy(:, 1) - dy(:,end) , dy(:, 2:end)-dy(:, 1:end-1)]; end end sopt-2.0.0/matlab/misc/sopt_mltb_fwdcurvelet.m000066400000000000000000000010551277570055300215000ustar00rootroot00000000000000function coef = sopt_mltb_fwdcurvelet(im,real) % sopt_mltb_fwdcurvelet - Forward curvelet transform % % Compute the forward curvelet transform of an image and stores it in % vector coef. % % Inputs: % % - im: Input image. % % - real: Flag indicating if the transform is real or complex (1 = real, % 0 = complex). % % Outputs: % % - coef: Curvelet coefficients. C = fdct_usfft(im,real); % Compute vector version of curvelets coeffcients coef = []; for s=1:length(C) for w=1:length(C{s}) A = C{s}{w}; coef= [coef; A(:)]; end end sopt-2.0.0/matlab/misc/sopt_mltb_genmask.m000066400000000000000000000007421277570055300205750ustar00rootroot00000000000000function mask = sopt_mltb_genmask(pdf, seed) % sopt_mltb_genmask - Generate mask % % Generate a binary mask with variable density sampling. It is used % in sopt_mltb_vdsmask in the generation of variable density sampling % profiles. % % Inputs: % % - pdf: Sampling profile function. % % - seed: Seed for the random number generator. Optional. % % Outputs: % % - mask: Binary mask. if nargin==2 rand('seed', seed); end mask = rand(size(pdf))1 dx = dx .* weights_dx; dy = dy .* weights_dy; end end sopt-2.0.0/matlab/misc/sopt_mltb_gradient_op_sphere.m000066400000000000000000000023701277570055300230100ustar00rootroot00000000000000function [dx, dy] = sopt_mltb_gradient_op_sphere(I, includeNorthpole, ... weights_dx, weights_dy) % sopt_mltb_gradient_op_sphere - Compute gradient on sphere % % Compute the gradientof a signal on the sphere. The phi direction (x) is % periodic, while the theta direction (y) is not. % % Inputs: % % - I: Input two dimesional signal on the sphere. % % - includeNorthPole: Flag indicating whether the North pole is included % in the sampling grid (1 = North pole included, 0 = North pole not % included). % % - weights_dx: Weights in the x (phi) direction. % % - weights_dy: Weights in the y (theta) direction. % % Outputs: % % - dx: Gradient in x (phi) direction. % % - dy: Gradient in y (theta) direction. dx = zeros(size(I, 1),size(I, 2)); I_big = zeros(size(I, 1)+2,size(I, 2)); I_big(2:end-1, 1:end) = I; % Theta direction if(includeNorthpole) dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))]; dx(1,:) = zeros(); else dx = [I(2:end, :)-I(1:end-1, :) ; zeros(1, size(I, 2))]; end % Phi direction if(includeNorthpole) dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)]; else dy = [I(:, 2:end)-I(:, 1:end-1) , I(:, 1)-I(:, end)]; end if nargin>2 dx = dx .* weights_dx; dy = dy .* weights_dy; end end sopt-2.0.0/matlab/misc/sopt_mltb_modifypdf.m000066400000000000000000000016651277570055300211360ustar00rootroot00000000000000function [new_pdf, alpha] = sopt_mltb_modifypdf(pdf, nb_meas) % sopt_mltb_modifypdf - Modify PDF of sampling profile % % Checks PDF of the sampling profile and normalizes it. It is used % in sopt_mltb_vdsmask in the generation of variable density sampling % profiles. % % Inputs: % % - pdf: Sampling profile function. % % - nb_meas: Number of measurements. % % Outputs: % % - new_pdf: New sampling profile function. % % - alpha: DC level for the required number of samples. if sum(pdf(:)<0)>0 error('PDF contains negative values'); end pdf = pdf/max(pdf(:)); % Find alpha alpha_min = -1; alpha_max = 1; while 1 alpha = (alpha_min + alpha_max)/2; new_pdf = pdf + alpha; new_pdf(new_pdf>1) = 1; new_pdf(new_pdf<0) = 0; M = round(sum(new_pdf(:))); if M > nb_meas alpha_max = alpha; elseif M < nb_meas alpha_min = alpha; else break; end end sopt-2.0.0/matlab/misc/sopt_mltb_struct2size.m000066400000000000000000000007751277570055300214570ustar00rootroot00000000000000function Mod = sopt_mltb_struct2size(C) %sopt_mltb_struct2size - Compute curvelet data structure % % Compute data structure to store the sizes of the curvelet transform % generated from the CurveLab toolbox. % % Inputs: % % - C: Curvelet coefficients arranged in the original format. % % Outputs: % % - Mod: Data structure with the appropiate sizes. Mod=cell(size(C)); for s=1:length(C) Mod{s} = cell(size(C{s})); for w=1:length(C{s}) [m,n]=size(C{s}{w}); Mod{s}{w}=[m,n]; end end sopt-2.0.0/matlab/misc/sopt_mltb_vdsmask.m000066400000000000000000000026621277570055300206230ustar00rootroot00000000000000function mask = sopt_mltb_vdsmask(N,M,p) % sopt_mltb_vdsmask - Create variable density sampling profile % % Creates a binary mask generated from a variable density sampling % profile for two dimensional images in the frequency domain. The mask % contains on average p*N*M ones's. % % Inputs: % % - N and M: Size of mask. % % - p: Coverage percentage. % % Note: The undersampling ratio is passed as 2*p and then the function % only takes samples in half plane to account for signal reality. The range % of p is 0 < p <= 0.5. % % Outputs: % % - mask: Binary mask with the sampling profile in the frequency domain. p = 2*p; if p==1 mask=ones(N,M); else nb_meas=round(p*N*M); tol=ceil(p*N*M)-floor(p*N*M); d=1; [x,y] = meshgrid(linspace(-1, 1, M), linspace(-1, 1, N)); % Cartesian grid r = sqrt(x.^2+y.^2); r = r/max(r(:)); % Polar grid alpha=-1; it=0; maxit=20; while (alpha<-0.01 || alpha>0.01) && itnb_meas+tol || sum(mask(:)) 1 fprintf(' Proj. B2:\n'); end while true % Residual res = param.A(sol) - param.y; norm_res = norm(res(:), 2); % Scaling for the projection res = u*param.nu + res; norm_proj = norm(res(:), 2); % Log if param.verbose>1 fprintf(' Iter %i, epsilon = %e, ||y - Ax||_2 = %e\n', ... iter, param.epsilon, norm_res); end % Stopping criterion if (norm_res>=epsilon_low && norm_res<=epsilon_up) crit_B2 = 'TOL_EPS'; break; elseif iter >= param.max_iter crit_B2 = 'MAX_IT'; break; end % Projection onto the L2 ball t = (1+sqrt(1+4*told^2))/2; ratio = min(1, param.epsilon/norm_proj); u = v; v = 1/param.nu * (res - res*ratio); u = v + (told-1)/t * (v - u); % Current estimate sol = x - param.At(u); % Projection onto the non-negative orthant (positivity constraint) if (param.pos) sol = real(sol); sol(sol<0) = 0; end % Projection onto the real orthant (reality constraint) if (param.real) sol = real(sol); end % Update number of iteration told = t; % Update number of iterations iter = iter + 1; end end % Log after the projection onto the L2-ball if param.verbose >= 1 temp = param.A(sol); fprintf([' Proj. B2: epsilon = %e, ||y-Ax||_2 = %e,', ... ' %s, iter = %i\n'], param.epsilon, norm(param.y(:)-temp(:)), ... crit_B2, iter); end end sopt-2.0.0/matlab/prox_operators/sopt_mltb_prox_L1.m000066400000000000000000000103141277570055300226230ustar00rootroot00000000000000function [sol, norm_l1] = sopt_mltb_prox_L1(x, lambda, param) % sopt_mltb_prox_L1 - Proximal operator with L1 norm % % Compute the L1 proximal operator, i.e. solve % % min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 , % % where x is the input vector and the solution z* is returned as sol. % The structure param should contain the following fields: % % - Psit: Sparsifying transform (default = Identity). % % - Psi: Adjoint of Psit (default = Identity). % % - tight: 1 if Psit is a tight frame or 0 otherwise (default = 1). % % - nu: Bound on the norm^2 of the operator Psi, i.e. % ||Psi x||^2 <= nu * ||x||^2 (default = 1). % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - weights: Weights for a weighted L1-norm (default = 1). % % - pos: Positivity flag (1 = positive solution, % 0 = general complex case; default = 0). % % References: % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for % optimization problems in sparse recovery" , IEEE ICIP, Cairo, % Egypt, 2009. % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding % Algorithm for Linear Inverse Problems", SIAM Journal on Imaging Sciences % 2 (2009), no. 1, 183--202. % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'Psit'), param.Psi = @(x) x; param.Psit = @(x) x; end if ~isfield(param, 'tight'), param.tight = 1; end if ~isfield(param, 'nu'), param.nu = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'Psit'), param.Psit = @(x) x; end if ~isfield(param, 'Psi'), param.Psi = @(x) x; end if ~isfield(param, 'weights'), param.weights = 1; end if ~isfield(param, 'pos'), param.pos = 0; end if ~isfield(param, 'real'), param.real = 0; end % Useful functions soft = @(z, T) sign(z).*max(abs(z)-T, 0); % Projection if param.tight && ~param.pos && ~param.real % TIGHT FRAME CASE temp = param.Psit(x); sol = x + 1/param.nu * param.Psi(soft(temp, ... lambda*param.nu*param.weights)-temp); crit_L1 = 'REL_OBJ'; iter_L1 = 1; dummy = param.Psit(sol); %coef=soft(temp,lambda*param.nu*param.weights); norm_l1 = sum(param.weights(:).*abs(dummy(:))); else % NON TIGHT FRAME CASE OR CONSTRAINT INVOLVED % Initializations sol = x; if param.pos || param.real sol = real(sol); end dummy = param.Psit(sol); u_l1 = zeros(size(dummy)); prev_obj = 0; iter_L1 = 0; % Soft-thresholding % Init if param.verbose > 1 fprintf(' Proximal L1 operator:\n'); end while 1 % L1 norm of the estimate norm_l1 = sum(param.weights(:).*abs(dummy(:))); obj = .5*norm(x(:) - sol(:), 2)^2 + lambda * norm_l1; rel_obj = abs(obj-prev_obj)/obj; % Log if param.verbose>1 fprintf(' Iter %i, prox_fval = %e, rel_fval = %e\n', ... iter_L1, obj, rel_obj); end % Stopping criterion if (rel_obj < param.rel_obj) crit_L1 = 'REL_OB'; break; elseif iter_L1 >= param.max_iter crit_L1 = 'MAX_IT'; break; end % Soft-thresholding res = u_l1*param.nu + dummy; dummy = soft(res, lambda*param.nu*param.weights); u_l1 = 1/param.nu * (res - dummy); sol = x - param.Psi(u_l1); if param.pos sol = real(sol); sol(sol<0) = 0; end if param.real sol = real(sol); end % Update prev_obj = obj; iter_L1 = iter_L1 + 1; dummy = param.Psit(sol); end end % Log after the projection onto the L2-ball if param.verbose >= 1 fprintf([' prox_L1: prox_fval = %e,', ... ' %s, iter = %i\n'], norm_l1, crit_L1, iter_L1); end endsopt-2.0.0/matlab/prox_operators/sopt_mltb_prox_L1v2.m000066400000000000000000000102471277570055300231000ustar00rootroot00000000000000function [sol, norm_l1] = prox_L1(x, lambda, param) % PROJ_L1 - Proximal operator with L1 norm % % sol = prox_L1(x, lambda, param) solves: % % min_{z} 0.5*||x - z||_2^2 + lambda * ||Psit x||_1 % % The input argument param contains the following fields: % % - Psit: Sparsifying transform (default: Id). % % - Psi: Adjoint of Psit (default: Id). % % - tight: 1 if Psit is a tight frame or 0 if not (default = 1) % % - nu: bound on the norm of the operator A, i.e. % ||Psi x||^2 <= nu * ||x||^2 (default: 1) % % - max_iter: max. nb. of iterations (default: 200). % % - rel_obj: minimum relative change of the objective value (default: % 1e-4) % The algorithm stops if % | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - verbose: 0 no log, 1 a summary at convergence, 2 print main % steps (default: 1) % % - weights: weights for a weighted L1-norm (default = 1) % % % % References: % [1] M.J. Fadili and J-L. Starck, "Monotone operator splitting for % optimization problems in sparse recovery" , IEEE ICIP, Cairo, % Egypt, 2009. % [2] Amir Beck and Marc Teboulle, "A Fast Iterative Shrinkage-Thresholding % Algorithm for Linear Inverse Problems", SIAM Journal on Imaging Sciences % 2 (2009), no. 1, 183--202. % % % % Author: Gilles Puy % E-mail: gilles.puy@epfl.ch % Date: Dec. 1, 2010 % % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'Psit'), param.Psi = @(x) x; param.Psit = @(x) x; end if ~isfield(param, 'tight'), param.tight = 1; end if ~isfield(param, 'nu'), param.nu = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'Psit'), param.Psit = @(x) x; end if ~isfield(param, 'Psi'), param.Psi = @(x) x; end if ~isfield(param, 'weights'), param.weights = 1; end if ~isfield(param, 'pos'), param.pos = 0; end if ~isfield(param, 'real'), param.real = 0; end % Useful functions soft = @(z, T) sign(z).*max(abs(z)-T, 0); % Projection if param.tight && ~param.pos && ~param.real % TIGHT FRAME CASE temp = param.Psit(x); sol = x + 1/param.nu * param.Psi(soft(temp, ... lambda*param.nu*param.weights)-temp); crit_L1 = 'REL_OBJ'; iter_L1 = 1; dummy = param.Psit(sol); %coef=soft(temp,lambda*param.nu*param.weights); norm_l1 = sum(param.weights(:).*abs(dummy(:))); else % NON TIGHT FRAME CASE OR CONSTRAINT INVOLVED % Initializations sol = x; if param.pos || param.real sol = real(sol); end dummy = param.Psit(sol); u_l1 = zeros(size(dummy)); prev_obj = 0; iter_L1 = 0; % Soft-thresholding % Init if param.verbose > 1 fprintf(' Proximal L1 operator:\n'); end while 1 % L1 norm of the estimate norm_l1 = sum(param.weights(:).*abs(dummy(:))); obj = .5*norm(x(:) - sol(:), 2)^2 + lambda * norm_l1; rel_obj = abs(obj-prev_obj)/obj; % Log if param.verbose>1 fprintf(' Iter %i, prox_fval = %e, rel_fval = %e\n', ... iter_L1, obj, rel_obj); end % Stopping criterion if (rel_obj < param.rel_obj) crit_L1 = 'REL_OB'; break; elseif iter_L1 >= param.max_iter crit_L1 = 'MAX_IT'; break; end % Soft-thresholding res = u_l1*param.nu + dummy; dummy = soft(res, lambda*param.nu*param.weights); u_l1 = 1/param.nu * (res - dummy); sol = x - param.Psi(u_l1); if param.pos sol = real(sol); sol(sol<0) = 0; end if param.real sol = real(sol); end % Update prev_obj = obj; iter_L1 = iter_L1 + 1; dummy = param.Psit(sol); end end % Log after the projection onto the L2-ball if param.verbose >= 1 fprintf([' prox_L1: prox_fval = %e,', ... ' %s, iter = %i\n'], norm_l1, crit_L1, iter_L1); end endsopt-2.0.0/matlab/prox_operators/sopt_mltb_prox_TV.m000066400000000000000000000047411277570055300227070ustar00rootroot00000000000000function sol = sopt_mltb_prox_TV(x, lambda, param) % sopt_mltb_prox_TV - Total variation proximal operator % % Compute the TV proximal operator, i.e. solve % % min_{z} ||x - z||_2^2 + lambda * ||z||_{TV} % % where x is the input vector and the solution z* is returned as sol. % The structure param should contain the following fields: % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % Reference: % [1] A. Beck and M. Teboulle, "Fast gradient-based algorithms for % constrained Total Variation Image Denoising and Deblurring Problems", % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434, % November 2009. % Optional input arguments if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end % Initializations [r, s] = sopt_mltb_gradient_op(x*0); pold = r; qold = s; told = 1; prev_obj = 0; % Main iterations if param.verbose > 1 fprintf(' Proximal TV operator:\n'); end for iter = 1:param.max_iter % Current solution sol = x - lambda*sopt_mltb_div_op(r, s); % Objective function value obj = .5*norm(x(:)-sol(:), 2)^2 + lambda * sopt_mltb_TV_norm(sol, 0); rel_obj = abs(obj-prev_obj)/obj; prev_obj = obj; % Stopping criterion if param.verbose>1 fprintf(' Iter %i, obj = %e, rel_obj = %e\n', ... iter, obj, rel_obj); end if rel_obj < param.rel_obj crit_TV = 'TOL_EPS'; break; end % Udpate divergence vectors and project [dx, dy] = sopt_mltb_gradient_op(sol); r = r - 1/(8*lambda) * dx; s = s - 1/(8*lambda) * dy; weights = max(1, sqrt(abs(r).^2+abs(s).^2)); p = r./weights; q = s./weights; % FISTA update t = (1+sqrt(4*told^2))/2; r = p + (told-1)/t * (p - pold); pold = p; s = q + (told-1)/t * (q - qold); qold = q; told = t; end % Log after the minimization if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end if param.verbose >= 1 fprintf([' Prox_TV: obj = %e, rel_obj = %e,' ... ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter); end end sopt-2.0.0/matlab/prox_operators/sopt_mltb_prox_TVoA.m000066400000000000000000000113111277570055300231560ustar00rootroot00000000000000function sol = sopt_mltb_prox_TVoA(b, lambda, param) % sopt_mltb_prox_TVoA - Agumented total variation proximal operator % % Compute the TV proximal operator when an additional linear operator A is % incorporated in the TV norm, i.e. solve % % min_{x} ||y - x||_2^2 + lambda * ||A x||_{TV} % % where x is the input vector and the solution z* is returned as sol. % The structure param should contain the following fields: % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - A: Forward transform (default = Identity). % % - At: Adjoint of At (default = Identity). % % - nu: Bound on the norm^2 of the operator A, i.e. % ||A x||^2 <= nu * ||x||^2 (default = 1) % % Reference: % [1] A. Beck and M. Teboulle, "Fast gradient-based algorithms for % constrained Total Variation Image Denoising and Deblurring Problems", % IEEE Transactions on Image Processing, VOL. 18, NO. 11, 2419-2434, % November 2009. % Optional input arguments if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'At'), param.At = @(x) x; end if ~isfield(param, 'A'), param.A = @(x) x; end if ~isfield(param, 'nu'), param.nu = 1; end % Advanced input arguments (not exposed in documentation) if ~isfield(param, 'weights_dx'), param.weights_dx = 1; end if ~isfield(param, 'weights_dy'), param.weights_dy = 1; end if ~isfield(param, 'zero_weights_flag'), param.zero_weights_flag = 1; end if ~isfield(param, 'identical_weights_flag') param.identical_weights_flag = 0; end if ~isfield(param, 'sphere_flag'), param.sphere_flag = 0; end if ~isfield(param, 'incNP'), param.incNP = 0; end % Set grad and div operators to planar or spherical case and also % include weights or not (depending on parameter flags). if (param.sphere_flag) G = @sopt_mltb_gradient_op_sphere; D = @sopt_mltb_div_op_sphere; else G = @sopt_mltb_gradient_op; D = @sopt_mltb_div_op; end if (~param.identical_weights_flag && param.zero_weights_flag) grad = @(x) G(x, param.weights_dx, param.weights_dy); div = @(r, s) D(r, s, param.weights_dx, param.weights_dy); max_weights = max([abs(param.weights_dx(:)); ... abs(param.weights_dy(:))])^2; else grad = @(x) G(x); div = @(r, s) D(r, s); end % Initializations [r, s] = grad(param.A(b*0)); pold = r; qold = s; told = 1; prev_obj = 0; % Main iterations if param.verbose > 1 fprintf(' Proximal TV operator:\n'); end for iter = 1:param.max_iter % Current solution sol = b - lambda*param.At(div(r, s)); % Objective function value obj = .5*norm(b(:)-sol(:), 2) + lambda * ... sopt_mltb_TV_norm(param.A(sol), param.weights_dx, param.weights_dy); rel_obj = abs(obj-prev_obj)/obj; prev_obj = obj; % Stopping criterion if param.verbose>1 fprintf(' Iter %i, obj = %e, rel_obj = %e\n', ... iter, obj, rel_obj); end if rel_obj < param.rel_obj crit_TV = 'TOL_EPS'; break; end % Udpate divergence vectors and project [dx, dy] = grad(param.A(sol)); if (param.identical_weights_flag) r = r - 1/(8*lambda*param.nu) * dx; s = s - 1/(8*lambda*param.nu) * dy; weights = max(param.weights_dx, sqrt(abs(r).^2+abs(s).^2)); p = r./weights.*param.weights_dx; q = s./weights.*param.weights_dx; else if (~param.zero_weights_flag) r = r - 1/(8*lambda*param.nu) * dx; s = s - 1/(8*lambda*param.nu) * dy; weights = max(1, sqrt(abs(r./param.weights_dx).^2+... abs(s./param.weights_dy).^2)); p = r./weights; q = s./weights; else % Weights go into grad and div operators so usual update r = r - 1/(8*lambda*param.nu*max_weights) * dx; s = s - 1/(8*lambda*param.nu*max_weights) * dy; weights = max(1, sqrt(abs(r).^2+abs(s).^2)); p = r./weights; q = s./weights; end end % FISTA update t = (1+sqrt(4*told^2))/2; r = p + (told-1)/t * (p - pold); pold = p; s = q + (told-1)/t * (q - qold); qold = q; told = t; end % Log after the minimization if ~exist('crit_TV', 'var'), crit_TV = 'MAX_IT'; end if param.verbose >= 1 fprintf([' Prox_TV: obj = %e, rel_obj = %e,' ... ' %s, iter = %i\n'], obj, rel_obj, crit_TV, iter); end end sopt-2.0.0/matlab/sopt_mltb_admm_bpcon.m000066400000000000000000000113651277570055300203170ustar00rootroot00000000000000function [xsol, z] = sopt_mltb_admm_bpcon(y, epsilon, A, At, Psi, Psit, param) % % sol = admm_bpcon(y, epsilon, A, At, Psi, Psit, param) solves: % % min ||Psit x||_1 s.t. ||y-A x||_2 <= epsilon % % % y contains the measurements. A is the forward measurement operator and % At the associated adjoint operator. Psit is a sparfying transform and Psi % its adjoint. PARAM a Matlab structure containing the following fields: % % General parameters: % % - verbose: 0 no log, 1 print main steps, 2 print all steps. % % - max_iter: max. nb. of iterations (default: 200). % % - rel_obj: minimum relative change of the objective value (default: % 1e-4) % The algorithm stops if % | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: control the converge speed (default: 1e-2). % % % Proximal L1 operator: % % - rel_obj_L1: Used as stopping criterion for the proximal L1 % operator. Min. relative change of the objective value between two % successive estimates. % % - max_iter_L1: Used as stopping criterion for the proximal L1 % operator. Maximun number of iterations. % % - param.nu_L1: bound on the norm^2 of the operator Psi, i.e. % ||Psi x||^2 <= nu * ||x||^2 (default: 1) % % - param.tight_L1: 1 if Psit is a tight frame or 0 if not (default = 1) % % - param.weights: weights (default = 1) for a weighted L1-norm defined % as sum_i{weights_i.*abs(x_i)} % % % Author: Rafael Carrillo % E-mail: rafael.carrillo@epfl.ch % Date: Nov. 22, 2014 % % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end if ~isfield(param, 'nu'), param.nu = 1; end % Input arguments for prox L1 function param_L1.Psi = Psi; param_L1.Psit = Psit; if isfield(param, 'nu_L1') param_L1.nu = param.nu_L1; end if isfield(param, 'tight_L1') param_L1.tight = param.tight_L1; end if isfield(param, 'max_iter_L1') param_L1.max_iter = param.max_iter_L1; end if isfield(param, 'rel_obj_L1') param_L1.rel_obj = param.rel_obj_L1; else param_L1.rel_obj = param.rel_obj; end if isfield(param, 'weights') param_L1.weights = param.weights; else param_L1.weights = 1; end if isfield(param, 'pos_L1') param_L1.pos = param.pos_L1; else param_L1.pos = 0; end if isfield(param, 'verbose_L1') param_L1.verbose = param.verbose_L1; else param_L1.verbose = param.verbose; end % Useful functions for the projection sc = @(z) z*min(epsilon/norm(z(:)), 1); % scaling %Initializations. %Initial solution if isfield(param,'initsol') xsol = param.initsol; else xsol = 1/param.nu*At(y); end %Initial dual variables if isfield(param, 'initz') z = param.initz; else z = zeros(size(y)); end %Initial residual res = A(xsol) - y; %Flags initialization dummy = Psit(xsol); fval = sum(param_L1.weights(:).*abs(dummy(:))); flag = 0; %Step sizes computation %Step size primal mu = 1.0/param.nu; %Step size for the dual variables beta = 0.9; %Main loop. Sequential. for t = 1:param.max_iter %Slack variable update s = sc(- z - res); %Gradient formation r = At(z + res + s); %Gradient decend r = xsol - mu*r; %Prox L1 norm (global solution) prev_fval = fval; [xsol, fval] = sopt_mltb_prox_L1(r, param.gamma*mu, param_L1); %Residual res = A(xsol) - y; %Lagrange multipliers update z = z + beta*(res + s); %Check feasibility res1 = norm(res(:)); %Check relative change of objective function rel_fval = abs(fval - prev_fval)/fval; %Log if (param.verbose >= 1) fprintf('Iter %i\n',t); fprintf(' L1 norm = %e, rel_fval = %e\n', ... fval, rel_fval); fprintf(' epsilon = %e, residual = %e\n\n', epsilon, res1); end %Global stopping criteria if (rel_fval < param.rel_obj && res1 <= epsilon*1.001) flag = 1; break; end end %Final log if (param.verbose > 0) if (flag == 1) fprintf('Solution found\n'); fprintf(' Objective function = %e\n', fval); fprintf(' Final residual = %e\n', res1); else fprintf('Maximum number of iterations reached\n'); fprintf(' Objective function = %e\n', fval); fprintf(' Relative variation = %e\n', rel_fval); fprintf(' Final residual = %e\n', res1); fprintf(' epsilon = %e\n', epsilon); end end end sopt-2.0.0/matlab/sopt_mltb_admm_bpconw.m000066400000000000000000000115521277570055300205040ustar00rootroot00000000000000function [xsol, z] = sopt_mltb_admm_bpconw(y, epsilon, A, At, Psi, Psit, w, param) % % sol = admm_bpconw(y, epsilon, A, At, Psi, Psit, w, param) solves: % % min ||Psit x||_1 s.t. ||W*(y-A x)||_2 <= epsilon % % % y contains the measurements. A is the forward measurement operator and % At the associated adjoint operator. Psit is a sparfying transform and Psi % its adjoint. w is a vector containing the weights for the L2 norm. % PARAM a Matlab structure containing the following fields: % % General parameters: % % - verbose: 0 no log, 1 print main steps, 2 print all steps. % % - max_iter: max. nb. of iterations (default: 200). % % - rel_obj: minimum relative change of the objective value (default: % 1e-4) % The algorithm stops if % | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: control the converge speed (default: 1e-1). % % % Proximal L1 operator: % % - rel_obj_L1: Used as stopping criterion for the proximal L1 % operator. Min. relative change of the objective value between two % successive estimates. % % - max_iter_L1: Used as stopping criterion for the proximal L1 % operator. Maximun number of iterations. % % - param.nu_L1: bound on the norm^2 of the operator Psi, i.e. % ||Psi x||^2 <= nu * ||x||^2 (default: 1) % % - param.tight_L1: 1 if Psit is a tight frame or 0 if not (default = 1) % % - param.weights: weights (default = 1) for a weighted L1-norm defined % as sum_i{weights_i.*abs(x_i)} % % % Author: Rafael Carrillo % E-mail: rafael.carrillo@epfl.ch % Date: Nov. 22, 2014 % % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end if ~isfield(param, 'nu'), param.nu = 1; end % Input arguments for prox L1 param_L1.Psi = Psi; param_L1.Psit = Psit; if isfield(param, 'nu_L1') param_L1.nu = param.nu_L1; end if isfield(param, 'tight_L1') param_L1.tight = param.tight_L1; end if isfield(param, 'max_iter_L1') param_L1.max_iter = param.max_iter_L1; end if isfield(param, 'rel_obj_L1') param_L1.rel_obj = param.rel_obj_L1; else param_L1.rel_obj = param.rel_obj; end if isfield(param, 'weights') param_L1.weights = param.weights; else param_L1.weights = 1; end if isfield(param, 'pos_L1') param_L1.pos = param.pos_L1; else param_L1.pos = 0; end if isfield(param, 'verbose_L1') param_L1.verbose = param.verbose_L1; else param_L1.verbose = param.verbose; end % Useful functions for the projection sc = @(z) z*min(epsilon/norm(z(:)), 1); % scaling %Initializations. %Initial solution if isfield(param,'initsol') xsol = param.initsol; else xsol = 1/param.nu*At(y); end %Initial dual variables if isfield(param, 'initz') z = param.initz; else z = zeros(size(y)); end %Initial residual res = A(xsol) - y; %Flags initialization dummy = Psit(xsol); fval = sum(param_L1.weights(:).*abs(dummy(:))); flag = 0; %Step sizes computation %Step size primal mu = 1.0/param.nu; %Step size for the dual variables beta = 0.9; %Main loop. Sequential. for t = 1:param.max_iter if (param.verbose >= 1) fprintf('Iter %i\n',t); end %Slack variable update s = sc(-w.*(z + res))./w; %Gradient formation r = At(z + res + s); %Gradient decend r = xsol - mu*r; %Prox L1 norm (global solution) prev_fval = fval; [xsol, fval] = sopt_mltb_prox_L1(r, param.gamma*mu, param_L1); %Residual res = A(xsol) - y; %Lagrange multipliers update z = z + beta*(res + s); %Check feasibility res1 = norm(res(:).*w); %Check relative change of objective function rel_fval = abs(fval - prev_fval)/fval; %Log if (param.verbose >= 1) fprintf(' L1 norm = %e, rel_fval = %e\n', ... fval, rel_fval); fprintf(' epsilon = %e, residual = %e\n\n', epsilon, res1); end %Global stopping criteria if (rel_fval < param.rel_obj && res1 <= epsilon*1.001) flag = 1; break; end end %Final log if (param.verbose > 0) if (flag == 1) fprintf('Solution found\n'); fprintf(' Objective function = %e\n', fval); fprintf(' Final residual = %e\n', res1); else fprintf('Maximum number of iterations reached\n'); fprintf(' Objective function = %e\n', fval); fprintf(' Relative variation = %e\n', rel_fval); fprintf(' Final residual = %e\n', res1); fprintf(' epsilon = %e\n', epsilon); end end end sopt-2.0.0/matlab/sopt_mltb_solve_BPDN.m000066400000000000000000000127701277570055300201540ustar00rootroot00000000000000function sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param) % sopt_mltb_solve_BPDN - Solve BPDN problem % % Solve the Basis Pursuit Denoising (BPDN) problem % % min ||Psit x||_1 s.t. ||y-A x||_2 < epsilon % % where y contains the measurements, A is the forward measurement operator % and At the associated adjoint operator, Psit is a sparfying transform and % Psi its adjoint. The structure param should contain the following fields: % % General parameters: % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_1 - ||x(t-1)||_1 | / ||x(t)||_1 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: Convergence speed (weighting of L1 norm when solving for % L1 proximal operator) (default = 1e-1). % % - initsol: Initial solution for a warmstart. % % Projection onto the L2-ball: % % - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1). % % - nu_B2: Bound on the norm of the operator A, i.e. % ||A x||^2 <= nu * ||x||^2 (default = 1). % % - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms % stops if % epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol) % (default = 1e-3). % % - max_iter_B2: Maximum number of iterations for the projection onto the % L2 ball (default = 200). % % - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise; % default = 0). % % - real_B2: Reality flag (1 to impose reality, 0 otherwise; % default = 0). % % Proximal L1 operator: % % - rel_obj_L1: Used as stopping criterion for the proximal L1 % operator. Minimum relative change of the objective value between % two successive estimates. % % - max_iter_L1: Used as stopping criterion for the proximal L1 % operator. Maximun number of iterations. % % - param.nu_L1: Bound on the norm^2 of the operator Psi, i.e. % ||Psi x||^2 <= nu * ||x||^2 (default = 1). % % - param.tight_L1: 1 if Psit is a tight frame, 0 otherwise % (default = 1). % % - param.weights: Weights for a weighted L1-norm defined % by sum_i{weights_i.*abs(x_i)} (default = 1). % % - pos_l1: Positivity flag (1 to impose positivity, 0 otherwise; % default = 0). % % References: % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007. % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end if ~isfield(param, 'pos_l1'), param.pos_l1 = 0; end % Input arguments for projection onto the L2 ball param_B2.A = A; param_B2.At = At; param_B2.y = y; param_B2.epsilon = epsilon; param_B2.verbose = param.verbose; if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end if isfield(param, 'max_iter_B2') param_B2.max_iter = param.max_iter_B2; end if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end if isfield(param,'real_B2'), param_B2.real=param.real_B2; end % Input arguments for prox L1 param_L1.Psi = Psi; param_L1.Psit = Psit; param_L1.pos = param.pos_l1; param_L1.verbose = param.verbose; %param_L1.verbose = 2; param_L1.rel_obj = param.rel_obj; if isfield(param, 'nu_L1') param_L1.nu = param.nu_L1; end if isfield(param, 'tight_L1') param_L1.tight = param.tight_L1; end if isfield(param, 'max_iter_L1') param_L1.max_iter = param.max_iter_L1; end if isfield(param, 'rel_obj_L1') param_L1.rel_obj = param.rel_obj_L1; end if isfield(param, 'weights') param_L1.weights = param.weights; else param_L1.weights = 1; end % Initialization if isfield(param,'initsol') xhat = param.initsol; else xhat = At(y); end iter = 1; prev_norm = 0; % Main loop while 1 if param.verbose >= 1 fprintf('Iteration %i:\n', iter); end % Projection onto the L2-ball [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2); % Global stopping criterion dummy = Psit(sol); curr_norm = sum(param_L1.weights(:).*abs(dummy(:))); rel_norm = abs(curr_norm - prev_norm)/curr_norm; if param.verbose >= 1 fprintf(' ||x||_1 = %e, rel_norm = %e\n', ... curr_norm, rel_norm); end if (rel_norm < param.rel_obj) crit_BPDN = 'REL_NORM'; break; elseif iter >= param.max_iter crit_BPDN = 'MAX_IT'; break; end % Proximal L1 operator xhat = 2*sol - xhat; [temp,~] = sopt_mltb_prox_L1(xhat, param.gamma, param_L1); xhat = temp + sol - xhat; % Update variables iter = iter + 1; prev_norm = curr_norm; end % Log if param.verbose >= 1 % L1 norm fprintf('\n Solution found:\n'); fprintf(' Final L1 norm: %e\n', curr_norm); % Residual dummy = A(sol); res = norm(y(:)-dummy(:), 2); fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res); % Stopping criterion fprintf(' %i iterations\n', iter); fprintf(' Stopping criterion: %s \n\n', crit_BPDN); end end sopt-2.0.0/matlab/sopt_mltb_solve_L2DN.m000066400000000000000000000103241277570055300201210ustar00rootroot00000000000000function sol = sopt_mltb_solve_L2DN(y, epsilon, A, At, param) % sopt_mltb_solve_L2DN - Solve L2DN problem. % % Solve the L2 denoising problem % % min ||x||_2 s.t. ||y-A x||_2 < epsilon % % where y contains the measurements, A is the forward measurement operator % and At the associated adjoint operator. The structure param should % contain the following fields: % % General parameters: % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_2 - ||x(t-1)||_2 | / ||x(t)||_2 < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: Convergence speed (weighting of L1 norm when solving for % L1 proximal operator) (default = 1e-1). % % - param.weights: weightsfor a weighted L2-norm defined % by norm(weights_i.*x_i,2) (default = 1). % % - initsol: Initial solution for a warmstart. % % Projection onto the L2-ball: % % - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1). % % - nu_B2: Bound on the norm of the operator A, i.e. % ||A x||^2 <= nu * ||x||^2 (default = 1). % % - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms % stops if % epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol) % (default = 1e-3). % % - max_iter_B2: Maximum number of iterations for the projection onto the % L2 ball (default = 200). % % - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise; % default = 0). % % - real_B2: Reality flag (1 to impose reality, 0 otherwise; % default = 0). % % References: % [1] P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting % Approach to Nonsmooth Convex Variational Signal Recovery", IEEE Journal % of Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007. % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end if ~isfield(param, 'weights'), param.weights = 1; end % Input arguments for projection onto the L2 ball param_B2.A = A; param_B2.At = At; param_B2.y = y; param_B2.epsilon = epsilon; param_B2.verbose = param.verbose; if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end if isfield(param, 'max_iter_B2') param_B2.max_iter = param.max_iter_B2; end if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end if isfield(param,'real_B2'), param_B2.real=param.real_B2; end % Initialization if isfield(param,'initsol') xhat = param.initsol; else xhat = At(y); end iter = 1; prev_norm = 0; % Main loop while 1 % if param.verbose >= 1 fprintf('Iteration %i:\n', iter); end % Projection onto the L2-ball [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2); % Global stopping criterion dummy = sol; curr_norm = norm(param.weights(:).*dummy(:)); rel_norm = abs(curr_norm - prev_norm)/curr_norm; if param.verbose >= 1 fprintf(' ||x||_1 = %e, rel_norm = %e\n', ... curr_norm, rel_norm); end if (rel_norm < param.rel_obj) crit_BPDN = 'REL_NORM'; break; elseif iter >= param.max_iter crit_BPDN = 'MAX_IT'; break; end % Proximal L2 operator xhat = 2*sol - xhat; temp = xhat ./ (1 + 2*param.weights); xhat = temp + sol - xhat; % Update variables iter = iter + 1; prev_norm = curr_norm; end % Log if param.verbose >= 1 % L1 norm fprintf('\n Solution found:\n'); fprintf(' Final L1 norm: %e\n', curr_norm); % Residual dummy = A(sol); res = norm(y(:)-dummy(:), 2); fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, res); % Stopping criterion fprintf(' %i iterations\n', iter); fprintf(' Stopping criterion: %s \n\n', crit_BPDN); end end sopt-2.0.0/matlab/sopt_mltb_solve_TVDN.m000066400000000000000000000105731277570055300202030ustar00rootroot00000000000000function sol = sopt_mltb_solve_TVDN(y, epsilon, A, At, param) % sopt_mltb_solve_TVDN - Solve TVDN problem % % Solve the total variation denoising (TVDN) problem % % min ||x||_TV s.t. ||y - A x||_2 < epsilon % % where y contains the measurements, A is the forward measurement operator % and At the associated adjoint operator. The structure param should % contain the following fields: % % General parameters: % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: Convergence speed (weighting of TV norm when solving for % TV proximal operator) (default = 1e-1). % % - initsol: Initial solution for a warmstart. % % Projection onto the L2-ball: % % - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1). % % - nu_B2: Bound on the norm of the operator A, i.e. % ||A x||^2 <= nu * ||x||^2 (default = 1). % % - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms % stops if % epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol) % (default = 1e-3). % % - max_iter_B2: Maximum number of iterations for the projection onto the % L2 ball (default = 200). % % - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise; % default = 0). % % - real_B2: Reality flag (1 to impose reality, 0 otherwise; % default = 0). % % Proximal L1 operator: % % - max_iter_TV: Used as stopping criterion for the proximal TV % operator. Maximun number of iterations (default = 200). % % References: % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007. % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end % Input arguments for projection onto the L2 ball param_B2.A = A; param_B2.At = At; param_B2.y = y; param_B2.epsilon = epsilon; param_B2.verbose = param.verbose; if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end if isfield(param, 'max_iter_B2') param_B2.max_iter = param.max_iter_B2; end if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end if isfield(param,'real_B2'), param_B2.real=param.real_B2; end % Input arguments for prox TV param_TV.verbose = param.verbose; param_TV.rel_obj = param.rel_obj; if isfield(param, 'max_iter_TV') param_TV.max_iter= param.max_iter_TV; end % Initialization if isfield(param,'initsol') xhat = param.initsol; else xhat = At(y); end iter = 1; prev_norm = 0; % Main loop while 1 if param.verbose>=1 fprintf('Iteration %i:\n', iter); end % Projection onto the L2-ball [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2); % Global stopping criterion curr_norm = sopt_mltb_TV_norm(sol, 0); rel_norm = abs(curr_norm - prev_norm)/curr_norm; if param.verbose >= 1 fprintf(' ||x||_TV = %e, rel_norm = %e\n', ... curr_norm, rel_norm); end if (rel_norm < param.rel_obj) crit_BPDN = 'REL_NORM'; break; elseif iter >= param.max_iter crit_BPDN = 'MAX_IT'; break; end % Proximal L1 operator xhat = 2*sol - xhat; temp = sopt_mltb_prox_TV(xhat, param.gamma, param_TV); xhat = temp + sol - xhat; % Update variables iter = iter + 1; prev_norm = curr_norm; end % Log if param.verbose >= 1 % L1 norm fprintf('\n Solution found:\n'); fprintf(' Final TV norm: %e\n', curr_norm); % Residual temp = A(sol); fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ... norm(y(:)-temp(:))); % Stopping criterion fprintf(' %i iterations\n', iter); fprintf(' Stopping criterion: %s \n\n', crit_BPDN); end end sopt-2.0.0/matlab/sopt_mltb_solve_TVDNoA.m000066400000000000000000000133401277570055300204560ustar00rootroot00000000000000function sol = sopt_mltb_solve_TVDNoA(y, epsilon, A, At, S, St, param) % sopt_mltb_solve_TVDNoA - Solve augmented TVDN problem % % Solve the total variation denoising (TVDN) problem when an additional % linear operator S is incorporated in the TV norm, i.e. solve % % min ||S x||_TV s.t. ||y - A x||_2 < epsilon % % where y contains the measurements, A is the forward measurement operator % and At the associated adjoint operator, S is the operator appearing in % the TV norm and St the associated adjoint operator. The structure param % should contain the following fields: % % General parameters: % % - verbose: Verbosity level (0 = no log, 1 = summary at convergence, % 2 = print main steps; default = 1). % % - max_iter: Maximum number of iterations (default = 200). % % - rel_obj: Minimum relative change of the objective value % (default = 1e-4). The algorithm stops if % | ||x(t)||_TV - ||x(t-1)||_TV | / ||x(t)||_TV < rel_obj, % where x(t) is the estimate of the solution at iteration t. % % - gamma: Convergence speed (weighting of TV norm when solving for % TV proximal operator) (default = 1e-1). % % - nu_TV: Bound on the norm of the operator S, i.e. % ||S x||^2 <= nu * ||x||^2 (default = 1). % % - initsol: Initial solution for a warmstart. % % Projection onto the L2-ball: % % - param.tight_B2: 1 if A is a tight frame or 0 otherwise (default = 1). % % - nu_B2: Bound on the norm of the operator A, i.e. % ||A x||^2 <= nu * ||x||^2 (default = 1). % % - tol_B2: Tolerance for the projection onto the L2 ball. The algorithms % stops if % epsilon/(1-tol) <= ||y - A z||_2 <= epsilon/(1+tol) % (default = 1e-3). % % - max_iter_B2: Maximum number of iterations for the projection onto the % L2 ball (default = 200). % % - pos_B2: Positivity flag (1 to impose positivity, 0 otherwise; % default = 0). % % - real_B2: Reality flag (1 to impose reality, 0 otherwise; % default = 0). % % Proximal L1 operator: % % - max_iter_TV: Used as stopping criterion for the proximal TV % operator. Maximun number of iterations (default = 200). % % - param.weights_dx_TV: Weights for a weighted TV-norm in the x % direction (default = 1). % % - param.weights_dy_TV: Weights for a weighted TV-norm in the y % direction (default = 1). % % References: % P. L. Combettes and J-C. Pesquet, "A Douglas-Rachford Splitting Approach % to Nonsmooth Convex Variational Signal Recovery", IEEE Journal of % Selected Topics in Signal Processing, vol. 1, no. 4, pp. 564-574, 2007. % Optional input arguments if ~isfield(param, 'verbose'), param.verbose = 1; end if ~isfield(param, 'rel_obj'), param.rel_obj = 1e-4; end if ~isfield(param, 'max_iter'), param.max_iter = 200; end if ~isfield(param, 'gamma'), param.gamma = 1e-2; end if ~isfield(param, 'weights_dx_TV'), param.weights_dx_TV = 1.0; end if ~isfield(param, 'weights_dy_TV'), param.weights_dy_TV = 1.0; end if ~isfield(param, 'incNP'), param.incNP = false; end if ~isfield(param, 'sphere_flag'), param.sphere_flag = false; end % Input arguments for projection onto the L2 ball param_B2.A = A; param_B2.At = At; param_B2.y = y; param_B2.epsilon = epsilon; param_B2.verbose = param.verbose; if isfield(param, 'nu_B2'), param_B2.nu = param.nu_B2; end if isfield(param, 'tol_B2'), param_B2.tol = param.tol_B2; end if isfield(param, 'tight_B2'), param_B2.tight = param.tight_B2; end if isfield(param, 'max_iter_B2') param_B2.max_iter = param.max_iter_B2; end if isfield(param,'pos_B2'), param_B2.pos=param.pos_B2; end if isfield(param,'real_B2'), param_B2.real=param.real_B2; end % Input arguments for prox TVoA param_TV.A = S; param_TV.At = St; param_TV.verbose = param.verbose; param_TV.rel_obj = param.rel_obj; param_TV.weights_dx = param.weights_dx_TV; param_TV.weights_dy = param.weights_dy_TV; if isfield(param, 'nu_TV') param_TV.nu = param.nu_TV; end if isfield(param, 'max_iter_TV') param_TV.max_iter= param.max_iter_TV; end if isfield(param, 'zero_weights_flag_TV') param_TV.zero_weights_flag = param.zero_weights_flag_TV; end if isfield(param, 'identical_weights_flag_TV'), param_TV.identical_weights_flag = param.identical_weights_flag_TV; end if isfield(param, 'sphere_flag'), param_TV.sphere_flag = param.sphere_flag; param_TV.incNP = param.incNP; end % Initialization if isfield(param,'initsol') xhat = param.initsol; else xhat = At(y); end iter = 1; prev_norm = 0; % Main loop while 1 % if param.verbose>=1 fprintf('Iteration %i:\n', iter); end % Projection onto the L2-ball [sol, param_B2.u] = sopt_mltb_fast_proj_B2(xhat, param_B2); % Global stopping criterion curr_norm = sopt_mltb_TV_norm(S(sol), param_TV.sphere_flag, param_TV.incNP, param_TV.weights_dx, param_TV.weights_dy); rel_norm = abs(curr_norm - prev_norm)/curr_norm; if param.verbose >= 1 fprintf(' ||x||_TV = %e, rel_norm = %e\n', ... curr_norm, rel_norm); end if (rel_norm < param.rel_obj) crit_BPDN = 'REL_NORM'; break; elseif iter >= param.max_iter crit_BPDN = 'MAX_IT'; break; end % Proximal L1 operator xhat = 2*sol - xhat; temp = sopt_mltb_prox_TVoA(xhat, param.gamma, param_TV); xhat = temp + sol - xhat; % Update variables iter = iter + 1; prev_norm = curr_norm; end % Log if param.verbose>=1 % L1 norm fprintf('\n Solution found:\n'); fprintf(' Final TV norm: %e\n', curr_norm); % Residual temp = A(sol); fprintf(' epsilon = %e, ||y-Ax||_2=%e\n', epsilon, ... norm(y(:)-temp(:))); % Stopping criterion fprintf(' %i iterations\n', iter); fprintf(' Stopping criterion: %s \n\n', crit_BPDN); end end sopt-2.0.0/matlab/sopt_mltb_solve_rwBPDN.m000066400000000000000000000047701277570055300205260ustar00rootroot00000000000000function sol = sopt_mltb_solve_rwBPDN(y, epsilon, A, At, Psi, Psit, ... paramT, sigma, tol, maxiter, initsol) % sopt_mltb_solve_rwBPDN - Solve reweighted BPDN problem % % Solve the reweighted L1 minimization function using an homotopy % continuation method to approximate the L0 norm. At each iteration the % following problem is solved: % % min_x ||W Psit x||_1 s.t. ||y-A x||_2 < epsilon % % where W is a diagonal matrix with diagonal elements given by % % [W]_ii = delta(t)/(delta(t)+|[Psit x(t)]_i|). % % The input parameters are defined as follows. % % - y: Input data (measurements). % % - epsilon: Noise bound. % % - A: Forward measurement operator. % % - At: Adjoint measurement operator. % % - Psi: Synthesis sparsity transform. % % - Psit: Analysis sparsity transform. % % - paramT: Structure containing parameters for the L1 solver (see % documentation for sopt_mltb_solve_BPDN). % % - sigma: Noise standard deviation in the analysis domain. % % - tol: Minimum relative change in the solution. % The algorithm stops if % ||x(t)-x(t-1)||_2/||x(t-1)||_2 < tol. % where x(t) is the estimate of the solution at iteration t. % % - maxiter: Maximum number of iterations of the reweighted algorithm. % % - initsol: Initial solution for a warmstart. % % References: % [1] R. E. Carrillo, J. D. McEwen, D. Van De Ville, J.-Ph. Thiran, and % Y. Wiaux. Sparsity averaging for compressive imaging. IEEE Sig. Proc. % Let., in press, 2013. % [2] R. E. Carrillo, J. D. McEwen, and Y. Wiaux. Sparsity Averaging % Reweighted Analysis (SARA): a novel algorithm for radio-interferometric % imaging. Mon. Not. Roy. Astron. Soc., 426(2):1223-1234, 2012. param=paramT; iter=0; rel_dist=1; if nargin<11 fprintf('RW iteration: %i\n', iter); sol = sopt_mltb_solve_BPDN(y, epsilon, A, At, Psi, Psit, param); else sol = initsol; end temp=Psit(sol); delta=std(temp(:)); while (rel_dist>tol && itertol && iter-pi)); sf2=find((v1-pi)); sf=intersect(sf1,sf2); v=v1(sf); u=u1(sf); M = length(u); clear v1 u1 %% Measurement operator initialization %Oversampling factors for nufft ox = 2; oy = 2; %Number of neighbours for nufft Kx = 8; Ky = 8; %Initialize nufft parameters fprintf('Initializing the NUFFT operator\n\n'); tstart1=tic; st = nufft_init([v u],[Ny Nx],[Ky Kx],[oy*Ny ox*Nx], [Ny/2 Nx/2]); tend1=toc(tstart1); fprintf('Time for the initialization: %e\n\n', tend1); %Operator functions A = @(x) nufft(x, st); At = @(x) nufft_adj(x, st); %Maximum eigenvalue of operato A^TA eval = pow_method(A, At, [Ny,Nx], 1e-4, 100, 1); y0 = A(im); % Add Gaussian i.i.d. noise %sigma_noise = 10^(-input_snr/20)*norm(im(:))/sqrt(N); sigma_noise = 10^(-input_snr/20)*norm(y0)/sqrt(M); noise = (randn(size(y0)) + 1i*randn(size(y0)))*sigma_noise/sqrt(2); y = y0 + noise; epsilon = sqrt(M + 2*sqrt(M))*sigma_noise; %Dirty image dirty = At(y); dirty1 = 2*real(dirty)/eval; %dirty1(dirty1<0) = 0; %% Sparsity operator definition %Wavelets parameters nlevel=4; dwtmode('per'); % Sparsity operator for SARA [C1,S1]=wavedec2(dirty1,nlevel,'db1'); ncoef1=length(C1); [C2,S2]=wavedec2(dirty1,nlevel,'db2'); ncoef2=length(C2); [C3,S3]=wavedec2(dirty1,nlevel,'db3'); ncoef3=length(C3); [C4,S4]=wavedec2(dirty1,nlevel,'db4'); ncoef4=length(C4); [C5,S5]=wavedec2(dirty1,nlevel,'db5'); ncoef5=length(C5); [C6,S6]=wavedec2(dirty1,nlevel,'db6'); ncoef6=length(C6); [C7,S7]=wavedec2(dirty1,nlevel,'db7'); ncoef7=length(C7); [C8,S8]=wavedec2(dirty1,nlevel,'db8'); ncoef8=length(C8); clear C1 C2 C3 C4 C5 C6 C7 C8 Psit = @(x) [wavedec2(x,nlevel,'db1')'; wavedec2(x,nlevel,'db2')';... wavedec2(x,nlevel,'db3')';wavedec2(x,nlevel,'db4')';... wavedec2(x,nlevel,'db5')'; wavedec2(x,nlevel,'db6')';... wavedec2(x,nlevel,'db7')'; wavedec2(x,nlevel,'db8')'; x(:)]/sqrt(9); Psi = @(x) (waverec2(x(1:ncoef1),S1,'db1')+... waverec2(x(ncoef1+1:ncoef1+ncoef2),S2,'db2')+... waverec2(x(2*ncoef1+1:2*ncoef1+ncoef2),S3,'db3')+... waverec2(x(3*ncoef1+1:3*ncoef1+ncoef2),S4,'db4')+... waverec2(x(4*ncoef1+1:4*ncoef1+ncoef2),S5,'db5')+... waverec2(x(5*ncoef1+1:5*ncoef1+ncoef2),S6,'db6')+... waverec2(x(6*ncoef1+1:6*ncoef1+ncoef2),S7,'db7')+... waverec2(x(7*ncoef1+1:7*ncoef1+ncoef2),S8,'db8')+... reshape(x(8*ncoef1+1:8*ncoef1+ncoef2), [Ny Nx]))/sqrt(9); % Parameters for BPDN param1.verbose = 1; % Print log or not param1.gamma = 1e-2; % Converge parameter param1.rel_obj = 1e-4; % Stopping criterion for the L1 problem param1.max_iter = 500; % Max. number of iterations for the L1 problem param1.nu = eval; % Bound on the norm of the operator A param1.tight_L1 = 0; % Indicate if Psit is a tight frame (1) or not (0) param1.max_iter_L1 = 100; param1.rel_obj_L1 = 1e-2; param1.pos_L1 = 1; param1.nu_L1 = 1; param1.verbose_L1 = 0; param1.initsol = dirty1; %param1.initz = z; %Solve BPDN tstart = tic; [sol, z] = sopt_mltb_admm_bpcon(y, epsilon, A, At, Psi, Psit, param1); tend = toc(tstart) error = im - sol; SNR = 20*log10(norm(im(:))/norm(error(:))) residual = At(y - A(sol)); DR = eval*max(sol(:))/(norm(residual(:))/sqrt(N)) % save('results/par_results_1.mat','sol','residual','tend','DR','param1',... % 'nlevel','SNR','z'); soln = sol/max(sol(:)); dirtyn = dirty1 - min(dirty1(:)); dirtyn = dirtyn/max(dirtyn(:)); figure, imagesc(log10(soln + 1e-4)), colorbar, axis image figure, imagesc(log10(dirtyn + 1e-4)), colorbar, axis image figure, imagesc(real(residual)/eval), colorbar, axis image sopt-2.0.0/matlab/test_images/000077500000000000000000000000001277570055300162555ustar00rootroot00000000000000sopt-2.0.0/matlab/test_images/Brain_low_res.mat000066400000000000000000021514501277570055300215550ustar00rootroot00000000000000MATLAB 5.0 MAT-file, Platform: MACI, Created on: Thu Mar 3 11:18:53 2011 IMx,w4!daWxY {+(ZVTdE^TTF $#|s{׽ܳc]yWmvoM6;&JCivE|̏)yA]xn u+n00_vT;q܅T}u tKk.ut&R 9)5|ɴd#Gq!q.oF[C ?$լ]SҜtEHe p:=0,H.-9. ܍t~Էv_}:DE#QnC$|Sam檭z~P 0WʹKyJaau=SqxG W~;u2r 1R bN^5Rjz)+>x#15fj;./t%hy`&Uϝc܂!)r)wXZGɪdp9 {7E˞e`Į8&5MJx GUU{ʼ1t&m')qukVxYqR qR3tKj">e(S7ٹz xSxoDi/`ekx祶J džbZZEAltuJ`*ڡP8Q>K>ɺ[ׂ($OcJOeC'W xmKha0 \&&8v[LQis?CϨ_60& ڂXSA3ml˓ U´1Wyt1)84"ސCg]~W˺\"]UܳN;#|Ep8^9ces%X#JquHRJnjە}Ҋ`ڮ7T^n 0_G?V{6-xO}f'bbP\=F'N=wV ~ȱOޙO _Y dZKzTm(),]6c@ #=_ð$(C\A6a_B` |;{|:n^䘖Us ܡG~ƀ;j|#a#`Y&_[( \V-.|GyhQV[#M"R8uvȧ$ 7f:J>[g"=o( YsgPHxHA2/Ul9Px~:>"CYwJS!Lp%:Ϝ9 wc|RmS$r{/(gö!kY} /FЪg3]7l^҉ۢް봪I,;ќ 31E `csE0~G..=n# yc׬+`24hϭр?LwyiW(5?/Iu7;w鑜 e'츹<Z:)c۝y*i:Uy8"i- !t_v^TԩLĢ!oGQ~ohv#4lGb^7OESmR!UkBw$)h4 s}Bgg/J!4ϡ}dQe1]`{G'7-[(Q|DQf3rm2 (ڙa 5sŧ1QLY4~EGCm=3`溇Mo@|O|26,"?ɍ8&tiB "=p.I1CWvX~IQ"Sf <֘bNf\β|^6OTբ?4 rlS g׏(i7 4Km.X>-FRR3:' *Bģ'Fo3 ~.!vF2kB.?^%L&+gE4~ն,-QJT8Cg6nN1܏Y @Hl KKS2%X08p342J-_OozFf*ǜâZeL,\0IN/2& ~f)KB |BDfs}t<mEt>{}J:8inx?F"vxbg3X(^dc8ty7˞מA~B=[G]`~Y|prZH,7n/V[$(F7u/1ɒmY] ^X1>R@]js̓ef2{ܻR~0 Þ}$x]|4 Չ~zAeY3gŠ:fppde(L GkJ,ޠٰ*R,3< &u hEf^=7s#"M{ѶN52-n"I0"Z%~Cfw4OS ̭eԤ@5F)4Ӗ((5E3:wkq *X &Y=y8Ց8]Gg8 8of_a\П{4M=O7y2l\eYw RVƵi;"0lc:5$wGwUǐ`T3H33ӈIW\6dSi/xj}()\n&K^zVܼ2׵pw%4 WVUl.{7v%'Y" 90f?`n,׭ TF_a=dHZwY]9vp)Q\mthre1=3gܱNKj  C)z} |8nh A4 !fk)8ӊ෾:yGG_ɡ" y~5%ŶKhF[=Iz}Լ8,5%E*׭-UpS, gU響tP!kv,uQyM|hbq]9;.k@03V6IխTnt=wOwjsV##}-ԓn^?QnVE40iKƑ qKX$NփϺ ΂0j[Rcǘ`T]+|zsV< 1Nn81 0 E׹MSHoL?c\YT7 kmYq;^*PSAAʲU Ĵ|wu~qثJ^ :.DDmyã ( PeGL@>}pҒ`b5Q= YD-tdO<'6F^31- ҾJc}NUr Ta?EZ?[kcBH*SE!R$\z_Ws!́ yC6T55ѝb||$|8 clAPvA#f8H_\K^dc }4 N {mJF(d[HiY z5"y؈a50)d[{5t46Z:S ~*KCT-ީU M>d O);j)-ݥ9љgybAxt|u]Cݖ̝rf1*ᑹ[l)Z80 r?Nu=F)s&!ls l nNYЊ@~ܼt5 YZh 9#}+Nu@ wqGpb1LK:w%bJ< '-eCjU 4r~}ΰ?[ser: MFG,{]!O`Pf@H<)8 )2kbpqg):^dOFF8Mq>L.9>29s&O;v#TŵxsI7 HQ XMUB4=ڜefYZm iVdfcR?&0{Kƪr%笰Y+R٢YWol|~}?iU 7P][{o e MRxvN Mյf^ #~e(Q u=TQ7[v|k 8zYAxƾ (ǐE+OU5AorHs/o3d>G- WN#GK<&gc$%@e)/1RMi6{F a\Dy-c0jwGNj9F>:wRN7W;oo| / Z\++"4i:Ev80eJ˓V\- ?7i^pR".=go ; ;}@7x DJCJ2n]f ̢ydHbƟچmːq?Tщ\tA+[^xa&k*&2[nW=eH|SE6vv2'Ko?pw*}ZBa@AᅂΊ9v*`DčD(xV?5N;Tbe4;eftfyjC>>u؞_ w7 1.88ޜyugP0h#c4et>T.sW`Pe7 Mfi~]Lwk2.[y4|[棢v7 Ѭ\V> N1N|ϸF)~.wmSK񫎈MXwi] ]}QE[(>jXY4K諵O:VV닙3 ռM(|$V~̸Lx zeM"S mW~_ =(V ੡/n'sU稭7ښ$k3I8vgq55 0daˀq&<3);ک B<ΰ*dě_5 t'ύ"ڂJ\tѧ/LXH mԗo^ƀ)k3 Uw{vW% g8 pU$dX!{g^koʸVF2dY(N 2 $D!os>Nrk-ǤͲ^2(qtam4@7 =勬O^=R2_Z:9-%Wv7M*ϕyxuxDlIJ4;CFH Fۦ, ɚmK ZO6+  HΠ=Kvo(PA!,'"yݿ ;-D Tn:䋍6!uaa݈}/K{ǡvxBbDѠ L?)|m/ d}7s;_b vMVo47$Q Cg>x~($/RcbD0"ʭjϬ.XxRS?۳uPjg鳷~@Eg@'ڌI#ޗ%SVT944JЩ4eui=z}׸ y,zLf}J7{4}d~ 0$Be.Foj->L/.?1G}URQ\.FTKb?ow4N(` 'ONNOdJbTo\iqǗ1M/Q79!tob @0gǕB8}U-Q(CjxӌV=zTgj9!,aV1dvOM5n5ЋCKGN%X ;U)> n . `>QMFԔʡJ-qwlg ֠w n2{d+ <wíU1-.I^s,gc̑&zDZ~`~v^/Ns 2H4聑/ vjWz1t!MgQIj{ {ш/D%?ZA*tiDz(kcڃ܆hyaqzZS1g/x9Kfrw >GHGqj]L8BOZ5_}1hީ@ƭ2-3H叔/]a/{le̽"MJ9Q~"Vjɳ{c=YYHmy N 5VuV4zp\0ViBw`WwpfY1l}Ql/] ۿ~bG2ö%%'Mz 4T1h <" 6in# +49`γ=y4RHfHh͕_~3.]D?Tix^ڗsHYlCæ׉I^0<W+qr̍FR ?dv>a`եhc;Ck9e{,]@[VOU􁅨]zQ<0;^IJ(TSdB/+?N:+Wë4߶|P mAiL/~ x4"ת@~ٷzK]d{lٶ=?Tꖸ$G3>[t)of"`H%^Ttƭ1*QjeC1pQ ;Xq5бs>2zDRD9"A@>l̥x]yR\ڛu5ۇyWAb7ニݨ ;"> xnL3?`O#g/x57BJW,YQL%.?Ơj 2LNjyQ)%|MU#b%LΰŊ)Tr\ߢV'UC7Of'3>/F?ufhZVNn@XF爰#lv-Ҧ{%nE?8F鎗o0F=u^pi! oY1Ah{N[ & ;ޮ 2-*XMyN&JxKqT&.QXi#u^=e>.FGUPള&TGBh1߬Xxii >o t!O6s}kQ:yLGxK3 QN7)QAIGğ yJ|qkVAOM J59S]>xE82⯼Cn?V@^!Z-˶Y # i C @#OomL5]Mz&vsApN+9 yͻlr'y&6gt0.נ?^ rya侅4HCC} ۦddf Z_{5SISy[51oi1r|{tuIXUYZiDeUMqG<жj"egCxfk Ud2=9*p9*EY%B<@ K0fMze4u1F(H5koWJgu]u2q^R@rC3F3 B&=7H/KFY8*w||թV]`RgP\aD }UpJ[=]7Ƃ&?11Y»J2?3 ~k ^䱥}Pnsӯ 8W5܅H"d3|}?6-l}[Vu1HkXG΁c&LyLcF([W; +}&8Wgq|npd &"Z8ģby1hmrp֪x0%=˞6 U 5n8i@ piI>\fpeкv7m|r1m (Bܻ yt1{l<:4!̙gzE&)s@p $(7fM} xҔ9Ε蘔bjSGo,,/8-lH"`*T- Lsmxw}P;6wLq{WoZh ]IyDp%;YGS0laq$AgU,׬ʙA #USOقon24ԥlsfQLщ5/;9y cSa *@0=*E&a~N?RT+ ȱT$0V:SULZum;0ksj(sI_Cl܀5OfcpjGo,1ˢdTjقLcOr&pJ<ޛHr;+{1H[V(zWFǛOFR!K i֧#@$pz`x;04qS&h`8~U0)g$Z Jv. WÕy?ՀCWL̪o$ ,Q<_qk&pI 3A'|ȲJxo^qk;7•:emԇg^Az#UD j۔?!tBMD~k]SM3X;+i:U} fT($6l< xp ~/ĬNvN$Pz8CkL e4&8sf)B#Vҵ}4^MS9 w23Zr#;dt29+頳!JWpC7-^6^MsأzO2OaԷ]f* SESgL e^\<3ZUs 9m[a2.zޮ;akٮH/UD _Ajw{UeWU#³”fwj9QkǞXAqpl uHh*B["eY^UXUl$SJRpaV9C Љ3>Z׭@R ZU7r-clN'{ J^8=׏TL?^LS;Q{l,-N&t#/mVdsOCIlBGc:}C@W#j6)U`gձ?Q50Nƴ*K׏H |,Dw`uUkGȩ68ܵ%`,sP6ƩT{7vg`W@< yUs0vެdniOw⚊徛 Ĕ2`567\(5ʄg!c/] =k4#E"SRd/eKwCq_{ĿUۀ+}Q1 7g8(Y( B{@;PC~1=jl}7F@ [kmܯ)M=E]QHLH+w*8`Q[0q$pԛ=-{gnGN+Y4빻F)]@ʐv/'F0\@Iσ|^26j-N@Y4Iڲ M dz#>@gxl鍚߈R|n`Kf=WKgf96`cM "zGi? M_!Di 'h8|3ntß>wh<ޕ7Dg_TGOIPg[`O~zO7-p:";l|o>"㧫_\5<ܳQVU&s6hl*T!UX} (\G]z0 pl~\spVҺqD0V1."Rڍgq3K=ˋ+0T+>f/XT؜;Ո$Ӑ­/ :P> $>3˶JW^B : ϼJ0Q33&R\H"Cl}ӱE8-s]a/|-Ziy5\x1-r~)o b:Mg,9Ұ}j[zj(hC׺9!|ŚC3fnt44Jffs̘5AdQ-̚ 9g}T`djN*0%N! o ZS-`#ǶY"] P } [!▙kMAdIгƺ0Plj|~-s-IaUpFX77u p}/w諎%.u>H+~,జ$oKo "#%KEQu7ʼC:|-bثymتt (AVxK$칮;Xi+D2ϓgdjȞ ]# @ =g4/;csmq\  bP~c̰~;//fc9 ?e6i/%|?G-a)!N"Up8`=;ނξ{> õ|xc= >hQJOn07oNy}Ƴ!(A;3÷8nLy&;dw]C)/mccCHgvwR&s]gOzK L\؋Xkv>g˨עvH"b+2vyx#ws3~ė.' F[ޜfg~.׍>kY;xPC2>XaJ8,YSFy|5L{fs5YrHt\~ ;wP{ B~SR=-/AGB47Yϭ%haC:~&4!GuC{D khi6x4oO> ۞_tOad6Sqѯ*v'%CKEo%EL3?8hcjphNz J6mCU{>jاL\@Y;Qot@cz_N_1`zt?Y_!w G E4jp/N0ظ8EXUC'kQh ^3>M.K?EaᔖF,~ ‚Whf 3VS[yBIyaβ6wk<nXUȉ@P&|#J%?s&crQF&wGr2)E,0" [)p`(^ 5>nW0bG?v%:nx6OX o:o.Cr]?t_~,Sg} 7ŠΣ Y<< jq @@سot{SinAT~~jk$͠3'̔?'8x7Z7o-YFitHX;ǻ!s$)$lra ]'EǴᎠH9Mr6LFd0dZt0v<$?jY1?q}K<|+ޓJBDV#V`R#u=t #nNX+t1jԀ\Y? w8 ƉHٲ3Jd2B6{{mQ!*L&BJןy9凌x[&K!Nm^g?lK.cc3!UF7Z.EjN Fi*Ԑ;.w#/Zm;$5z/ Ζ]+י"Jw@цKz5ʛ'MdG- հ$`_3[7\Hh !㳈;죆d#o ZE7 NaKU @WyKL=r%;IAayRb6z7OTl H+q2.!^qvOmEzсxxC0Ӓq~gg$9\R%D=;6rVip23fZa!jxLxQKZ3 ~Њ~,m;p2+]7ڃ-P{dirLB#ܜ؂>[S`G Z>LS82KjH6a_Z*CAHvPRذ2:;)iZBQkޮ^D <;2#n۲91/&g`J~ JSpvM۝|Wen9Uw]F7~zo$bBq`8"tF&^Nq'W4&MCQ2m(xy-߂! G KGHGnP|-D#mjtvYI`>뇌KR͖3$-T7gg2J )9 DcwqXH%,XYqtu9 Kj=FrN ED,Td&ܲkh'E]RE#{>Ԍ-ǂ4[]q'?I͖sdN Û="{[‰S-7 "y!å5Q4Ux/x-􂌉̿xʜa'A =VUx}DE/i1rQAc;us3j&m-xΐ$uš'VUw`9E@ٮ3YC`mjpꇇs7@U.c(~k [xʡFj =4nsYA_ٱ#UI>PZsIٛ>z J "I/OrvBq3S)P xKm!d3;H:iaj6)?h[,ACHzp cGYEH|?-o%'@VTP) 24}Z%里d"pĮ3v1*}t;"6*mhHtF[NWfFl]E۟M[><޶!LP0`Oǀ+u-mc_G'e^l66sF;-",\K MSؖ~9}2&fH&[҉֘@dA!;(< T 1v"6ؿ} {'c +WxIx㞪'! Ӡe4nsng=iG")Imvq@K)8uVh" if<6C ePXz}SFg|n\ELEpL)m~(a՚?P|*Be30+J zVF4z_TNҺ҆6C̝#sXwB٩ Lftt#؏]ً#4ȩھOv#tͥ'31]Ն:s, zW9nIxVt[?zSjE&p"r7F:bň6>&k!b1΢XV62s띨uܻ!w~rqZwRc>}_-{{LVIHaiBnYu!xh\8,}dƮ#l:<AhD#)|6R+-#-;&x~ 6e 7/P tFRb&,aC]8CYքaT;(eib3xې3qxO˖Xvߦ--/%]WR f ڲ ,0Rs0 3ܷ,0p;#5;mXoቬdQZw2">= h~}py0!SZl6ADSs!"P-1eKW!1sHݜ\)bXerWNwIu 2qA_;E+eNsnz-M$, 2P/|y꨹I7h6GƘ-v%%ӛ0 8R2V ݔeL%χroCho/V7ߩ>WL!7bg)n~j ڻJgN_v  .Q=J@ Z|TspeYw/;I=oFu`7^jt$>GBɪ p>=U3Sܰ!PPJU{N@މC9!6hەHCթB(;+gk⫬9xu!S[l*'U=(4/IQs]1]!9@?Y%I$H #m\BlV_6]ڐ7Sƾvxq `:/r1Fn؉-^P̭Oߒ}:epWraZ2ޑ`}&ГCbdBѰEu؃x Y!޸\[]l.,ŘSw'žY8r%*r8L7vCcE xsuǎ,dn00*Ζ3#&jxPfVG_/ϯQmwzQk{e*i7>!Һ)]yҕ?chJJW~{ tNXo 8)7}ԋϦgh],_6E?{%/"Έ:x+3'\T0/O =^\!VkIM(%*|XT  :prlvf-8hW4B𻕧_g&@y\ e GVмzN&iߚ&&{ǠbgiX7`L9VRi]FaTc}ۧFS5E^;H(e9HkIg*kdX0)Om4\(pmq+;Kz44,Y,!WN /,m: O)Y*<{:ODe}qf,Zi 1'i4$wea)߉ 9Ú.yI`_t/pCQg5!?GK4&-ɱeH鉂G"3y59v?ε~i^^L¥(1ZzDCk!S|$}gx}*6o5Z4{oDtֶ6p\'It/*fD 2FO rmc< P՜TI5U8ޚ×OO*vXx -gy; ċ5U%blDnAz=酎[1#y-c9 2c6{\gz-%pc*}z Q(z}!H>1<2(m=E/w)]A=-F(i8Ȧ}v z JmtW` Nyx35h}PapB+D2^;D9+eh \ V@ uYcht&% D( HU!YWȻda1Co1>>+bK4i ^4cojҼ;f1IE~Za{yGS +35QȉE5*}6,l??<gۙSZ Y+rN曃HlsdѽWQڈ9< {JkL/l*/2w/eF˙X%cdhE"8QxkC6u)dž(Ky6Y?"bxlP,Mͅܧvz%)G71Ff쫜˲, zfqt1DPwz!@2ؚM16\%9oWr T_ 0wGCNe~}"|v8/+ =oBN,Ů"-9V. t] ߶x 8ǯs2z5yX8T&WGvP>q~u(Suv¹9ߍ "o~ D$->}<2ߎ|Z$X|ԂuZ_0I>,5 ޥ2[l`TOV?/xT«=noZZfQ##7omT`? pJ ѽkN +Py kz=G(ݍUNƾ6ySP}] kHJ5]~/lZJȥ/U#pk]WR-jRexolx׿|Bo>P#%BP)%B#8pd~?4ߐstlVq{y6G@?v0]!G{AȎ^ QZÈ d|Xa6 7Iܡ#17j/j☀k=W--q7L>Ύƈ6ea(ɨ9H# 6v@9C3ŜpE=2iߗv%q0~O.S|!Z  'k$ 97O6frL?;ꨟx`%i^I>|E CEdOMj+[W?%/ߣh<Ьk 9b\E4.s~BZr(JcA̚_aL0dLx= ٵ*3P|ӁqJL"S! 3-QI95ǃejȋo%ؒk`1@* N/J͞CS.V8BB=IgNɍ.ȕݯgMVBǻF}VF >?srkiw^CbȠӒs0Ah/#xq} "s/NktӐE9H9kQ ۲3u/n|] `:íW &35&U.4eϯLy*B]sT&G>KEE1xٽ0|_W^9NOJ" [^LzjLg?JabO=:X C/tfOw5.y*[5hF *W;~}6@H: ag0ԞY3Q:(Fڜ!+_ WJ[~P4Jl&p=_&{[nO Q +8"}u ?Jv p2DD7"!JdGa2їUָeҩ v˔rxb/'x y@='E@B?r?=}7 \$~yc7+ng=cC1MV7l  WW  'PvKR$effHV[ddG"+őYd)|=ý&ňlI:27iЗy`keĢp'S; ] {Gm:{SV0A7] tJ(+dLl!@[x{>-IYase=lDn7Y3VL8WQhį ֵ9>XU#1^H4"8F+לI .k(iҪڦwUz 0$5 n#i쨴pϯ9vXnn# г+.2c/kH Ҟo {\L}9Qjq)|`$ /JHGUo,}3m뮩V`,#2^t{d J iϳ*?{-%ͻ0ftP1o^BY#8@g$[ލ83d}~&51V,_sch+plH%n JP1^n˃BGw=C0zO1١3zϴpB|F!4>Gv[/F "d_f<Ɲzlok6z >K勳= {'E2~ɯ-p&l>${ < ZZݞѹ< 4YEVlYXv'ak.ҥo1ʴ|͂}Wnaz𫿣ٸY*]4C@E"83 gh 7ph]CuQz/n? ޤݠxbZ~#KHJ<*2- [Q[D ShvnZ-8^FV*}{'a,;HVṽtW?ĸݗ;h#L*/6x\ƇE*G162g;Fpuo?gYOf qrX|w >"L@WKż@4+K*ke@G~nHa4K.TUpsF@<m3$,6EnиUH8?@Dg(FᶟtKP iy}Hc (x yY&o<'LJ/f u4CgQ\Kk .\тG@P*qoo]$Թ̧Զ ĵwlsE9p@7_zi'-&V[Z̎ {0jbvа_.gQɴYS=(ir2jK҃=mV}Dk:6Pa3A#К/(~$8f8@j%dq_q9)OFwDaդvl@ ۔h$0\j~$ [s v*9N`ыV~ HNݦ҅M[NP]qd : WK Cg_7+ړ=va+,wm@R(Xx=`'dg93])%1#8v<HL7 /TM!BX,{j?=/b,/`WS2}ηeG}dh ks hT0œh\ӇTp&yjUˍ^3"ŀi U"_J5SK{hnZ;Wsx}޷.HIJ*To3oU ]~5\% ,\DJY"yH`:,&+#ƯWئ(vgl@_čcg;Ibwe-3Ѿ2gNы~n663V;`B%#TVl!c/@*ŷ/sm㲂+<ɽ@㉱IɺʠTD釋^SBnD튄NKas 57|2 'f52w X~.@G~K s+9#H$7 S MHt.lGzHzE ~;;iZ_IXW4U Ek};CX@o~jA։%p'pF(sJϰfX\W ~ tAcx?"?|KLcR(՘b߬cy%f|Yok?ˆYo#pӳbrxG&e_sO0r+;¡5m4ɚ!PR_؏ ]B5KrsOb\Xgz1?D$gaEQC)pu{> MI!n9k=[5A܌'vx+Ghs@ߟN!N7f7C77^򀔇.z-#+mm'v7]])Y<.kC%'ee>[T å'ŧE!\˒4X۔fC/ȴ6DCcv"䌕cX B7?AΐD rqyHsW.kڰq̒ =u= {*n. ]|5O@Sl Q'x0&c b۴9$P/lp56y㟝Z \&L-/dÒDS잚P} _hlOjׂb֊q[\e~'bVҋ3>~K#bւcTfŀk;w&\Rђ5R  SuN#8WFQ]Im=P u^2[7@Fnd)S>5[asJ .ϙ84a8ɞ,a-]2-fz"ګ㤏4u"mlҿt?`:c{FGd 9F0vf\_i7CI#C]s ?%.*Nu[B*0i\ WۂxerPiA{HX٭L߂Jb[A ;v CH&6,́-8BzK{ T,_)KW ]b'Iw"ٴM^ z< i8o= U{݁}8QН>5m _lTtjA= *NX ̻5p鐗 w sI\z m?vaXw'>ztlU(Ύǂ OJhK~wt6 љJ=9wez_v$`ҫvhmhHG^Z$,|#L) }+BP׿˷dž 淖Je:tGJ[{5,lxޟOJ2Q|Ʋ-?Z5ElvLY&mze%KmB\w&&> %2 5p_3|UJX/\G? ;+'ǁran$&Awi39vi1-/ W 8|ZþnY*!l{Bۧ&ndtBg az>MlQש Mp8M^ ˾Vwqj{Aز1,m{_|՘JA*r>7x[gjmFfh_o`hgwT6'mI"ŬnSAq<@ eCPW 4b=44!n-MReA1q{rS,恞Pf忦rڗG v8F\,Gc|5Oli[ĚnK;hf>ߤA%w|{>[Uz^?~+~*,{ODr/5h2a(#QG83)>ҿ4!r:[-whCӓR:xSy6B$%tQrmdpwdb[|oK I P@\(_^xm'%- 4$QKDKA$DT%1&#Ix R1$!# C,.2%ԫfpB"27ݴM!HbS3Z!j K_k~ZraR fZZ, 1g(\Y2mNxt#ZEA3"p* h񓚘y\c[ɀ?_1;(t̲WMq" '4F~sgUo:_'?^*'/`{w=;V M2?S]0}tXv)+meyRJ藢9[E젣̮"c#o"s0{?M8Ws!+晍x&\{CXx?n䬅iwRaQlY=.B^b%]h7Qjo^&&d j`clW$M<Cމ̾׽0)PagY_n+1Mr$#iq4Ja( WRyid_) ',2d$PnQuL$?I'ur$D3[~'}H>S$ˬv8`u- gؙwvYr)K;^kktYR0e|Gl%RnIWiM;eqsg{<ct|90vv+-T>zԦ.&w7_LVV 5m)!yzuO5ҁ7mGFa4o$L=!ͯݝq)zʄg ^>aDv)[ol䪑hXl  O:<0aOD; > ;~͇.K e ?m6I\эn1BӋlcfh~+;6'+_9} WĘz ZAӾztϊH^2CU{T2mR>ӖUi0sMD(!xُfE38hwͿ5`r`N"bDz/#U|= ؓ,KBe͑ k]Lև$k}Tom YGttk䈯uK1 Eli 73ֆ?C -3!(`U߯]<}c_޵٪5uRggoLVeݿ?W:] %pZP 2ni!SZ!zHy=鉩;q}XnF~6Z<ٿ{|l|_,B0`1d_g[TS43Nzp?hp|P^0DKkk!8:9A" 5R˼ MǵpI}[ܝ[O%FJaW8p{T:GLhG|/ nk ﱴ3.xd1n~)FZg`3Hrg $}fnffz:܅Dר t;yN ȟ|f>z $EʍD/p;?#$̀ O#`#l>^z_Stbv|:IyUn/X+ãbHEti/E@Z #.UĚ.^}ZY%aE}Q-5 ެ?)$_srY$O~f$liAz`z(޿ѱ'f}"14l[z4.ۀ=hQ/z9Iƞ_At ڡacz 8Ĵ0`_VBIE1#E?.*tOha'YڦP>R{x=t#9*IY0Y%}_ABԏZYueRkU{0Dh\TěiK5kJGRe֭k dNi3Y^~[e7v#>m[U`Gg}-8PM.h0:=6Us `!iDg=*m盰`-.lVDbFGX#_%xʴ)Sqgp^1zY1#ӧHi٢^Cxߙg3I_qqrw<iwz1r=Fc:r Gxͱ ;p|.;#?շv%]'Q$<3G|8U-mԠ,5oИg5֭B&X+sJL If6BMa!Lc,.6@>ފߗkAF+KØM ⼕d=}WGݶXN QWx$bқ8&ӿgAXiz#b m]cͣog5]Zj]}iS!tt5\Z~qD,FG‡#s(Tܹ-xW3W9*B2{?pm m\ C O͸j1j_C!N!(;`q 4a.u04s~ 2C6O?4mDCWѰIW8w cY%vNro}\oX}ؾ=TurS64X05uzo;Lv~$6 "}7E"zgewL$L QwQpT*8;\8h̅s!>sp>!'9DJY>{郗/}QznNk|!~'b`!֝>%ɇ[$ ` .KU 3͋S ͡5dyf6ٗ3}'*IE\ԭ![ dxogTW| ^#8v7,"j.†}_x6 !{Ÿ5MDIxI d4(ZmS7V\3}w׹zѭ^?D~ FM2z_W;߱I42(r+RJ I7\[ьܕ@E%G`駌ݽ)JH!x;)WCFOT"po7DwWl he KۛkcPqF>/F)UHH}HS Y|& |*ܒ@g2X$yJ$Jp!^QIٽa)iPA +^ő0h/f.O k w~¨ݧ`<=VaZ!g&DAf$V WCflcN ԗ$oIcёƶM\:0L {%sHLP7ī.:<<Bv;)^2m{"T#?͚q7E{ }U$uP-e6RqT֤_LH9ѭ~ UID(iSKĞ{wYV FsI%7'&m D/Y2Q_צ< ѽѴx1C38ACVhifT벆T;ᇇj~{9*?P[E%:0C R*_@"XG( Ͽĥ$,pwA'fڧT)?Fz6 ;Hco-U ^%cpnQOdvAhܵ]-@&q v528޼; 7;a%.p7Tħ}²ȭN,IUE^>-êtG̤<{ kU+o;Bb,Aw˽q 9KEIY7AϢ63b:OQpLAo:jP(`wVXa-17KTvYyGYi5?QhZ[vaBcz.I=zplwf܃_\Ms pcGI{^Nq Sۚ#\`$sR4Wݍrttn\L!O:e7GӁ]$H5ˆ<C oH'8yViI{TsJ$@€^62 [Q*hg.(<>&F}cy 4{~qV]<6|?+N4AjbJ{3c6x>l_S(V@EUȲ%.E[퀌͗|5T_1)=m)TZXG qBN/DkړiBՏўK+B_*c{'m3or`8/OQ٬=Kuz@%;kM!ƹ12K6'4e. x6N  ݢDLSס~~(_nZGH>H9 M>S>6őc/auE\ ϳmBA1z$I,V'2Eufa~p+sZ⴮G~5eU3 -QV`KyA:>+vTDr>)x1ũ+ZAj;N[9Έ7n@oG"euiH%H,4'r) Q6A]N9=jt%  R>v 1 ~-<5Pl=tD$Fi:}ftC;,[)W.&[[:ּsI:`2$d֬~9Xo1$0ٜ"Dyl+o7&: g5꙽zl^'жmRA^b]J,=.ZG$xwmWpn* )4BdDgԟ<+@ԕ:0ZC*"p Q?oo cs"ޒ^`wE~Bw^s#uL/ )C20|6QD#UM(`\X0^<I~sS[ͭS*nZG+B2tKS8T޵z,$ ^ـr.ƊygBiFB|p!ۿL .NUpݘV픾ϗy ^_ʱ⥊'w-5|;zդ>8H?{R⟛K)bȼ~&24^66 cXλ`A[I0uؓH7CP-Qz< ivwS63>jg(u_ # w4~)-IBèdwdwd{*If(#ٲ"D׿{w~Nf j`,T֎u#IXYc6;cfʑ*uq^(1 0foWD/}[O̾ uƠNŤnU뽇Gt!C)M~5?T<]UyJfWYP!|,҅h|1=tk51ӅWV.Y.# ES0:E~h ֕԰<*d[u|:U;4t*\͡ڹ<t!*F,h&(\S"*%j(zy8C@BYS&ZdOER:;Ib{uĮz_}<f]،QT 0HPmTL)ٓ9w9_r槀aɏC VدW{ق|dќhӊ 93P *E}s2X\ !˶5mTG17j~HI#cv(NW ~|YJm[$) >X|=J7`2 2áR7" zjZLz4ch' }4oK&1EރW5hoS *z6 3PL)82~*|^}ryzK `R.^tMO@!%hl-54./caEP8  AW?VaVE,K,~iu_'4/v귱H!=OM(Z`|(ZAtf%bC JRaQDAXS#݊Cpmꁭְa)kTy`~bcxg=}ZA}cCV4*h7R3sԺnVQ'XT` `U|%lD޷aCt$yK՞vRut qgQ$`3Ib*1H>g<4m0bhr!d;Tu0ёI}X&\Ԑ=sg_2֛ yѷ"wZS@蹫es0Y  Ֆ`c${uX>Y{lQ}f&{b AXT=}X{v9,`SϓaؘoHk{IF; s@UV50,K*,fӘJFoH|m>ڢɧjx~N{z3uEH~I4୽_26= 3WDs;X8%N2;؍ewncBIF)촋Ƹso.:JDwм]ϗ+|K[A C#)KfM'k nze7EbxL,!>s7tn2ǣxpJ6YTJ! <}d]|0dY/]vvMuz cW"+x-CFD k#|%O|LE5~Bz|aUz| Ʈ̤`X+Bv uu(QFL] WGwHO&+ENO1w'yW8<i d7niM?I|5ocP2g0iw0Sq|v%ڣab O .CPNLX ?S<* )✩x1l>yn 3yf䐠Qυ<3rkP7(qh1>r}˫f42*eE}iK6#SY``Q)dn]UPY`sQ %C~Л-4O&DA)@R2.ڭԓ80hzXx.CT'LA"< <' KO2LgVQa*}}<V,j3]ܣm"&k(?Kɕ}3Yq?1< x_WS]b:PJEqnyzY9+B;Sp&{_NkJ4[5x_\(fXR qy%Xdхg -P>)d  r7wnBs݅zH1hcR ʸcT6G@>IO,;]ԓxMӚIyƽB+0L&TYk"D81 y4:z/B7<[׹rPNK3p9X ۜsSa4X'?E* #0M R8Ln¯C%:`d#XX .# [пi5.*Qb'N.ImK bQ7E4N5R'HHފeX$6^}t=VnOS['/%zYDB k>]7 .:1;,*6&_͛ZF(P1_3=0搒x0gR;^B LF !׵8г=>Agm37P9Nsaߕ!;kކK!\>2EH9t\RxRig$C\'I\$b#ޯb@,h3nF6վCNc[I=QY1֖.(m!ߎ&ؘ$L'(GιG!0>qi&\94q/Am8 wL5+})3QPXic-x׆.иb@cRfl]gxzo-=:VzǡGOjoeyt@#1KlV"6W>*vZjNK MX^Wf /e-sj` A[Y>YyU@lmJyM(ϋm9jʘ`qOWп4~ nDO,T"ɢocJ =1?nd>j;VC u$*0XZ Q/GUc;IV )K,:6B`{F h^ԠQFڱI FŞ"*/8e+ Q^b2VgkGށAw=w߮*~rdGU:lfTޥçeJrcT;[ѿfաZ{N(i@XۋI 'lJ9AIC2'&4VWKwt1GRmQDwA=EM>!i+fhb&= }Q{\`d }~Z o4Vć!n?sC¢[P;SB1u<mK߃ >wBow kňK'>.Fxy.Q қ|>y 2_YH{T!inX9NO-:A:PA)*Eێ( :,3vGQC Fm4燑8S>mkA []s&Id'XT+F8~ޠUI+]FH0e?ǘ)UmѭVFHr3z)NA $pQyKNq#gZSt 9p5ldxcћA,N}6jǐo[Cޗ <-qEs ʥF=5IQdlvkN'P̀8fu S FlKI(SVWdܬKzʲ}t'H^> JKLb^/@_D]oX%\+{sMdf94{ \v*FpЫaQ hX>Eix_Dl/_Tn}L&\Ejzp2zptIN{(mm0Pn@ #|9q;~9#V? U{Amw eWϽ RV~NBF7]sR-!&8G_wG׏G@챎(o8jZvq:1MrIj%86ƷFƔR8YyԝUE4ec7\tDYmaO^q \GS* tts /Љlc/[*sɒPo̓?NCx( q_|g~V]k5K :,أ{CX9N+"n@شBA VIVVMf+'|*p m9 J=**5afV:<}b 2k>Fjs3O}pq/ g jK %:]=lx9ܴ ,' =@1Q>[i~C(/ՙ_8cipw\pՑo5ԧY[=qDuL-E\tH='{LӖS+gyqFLs6jg]%عɦmoy/G40!ד>⯥n8jMـ.M ~JFۅdQXj(7 hWW z?r*-a5Nۖk9$nG?p:{vIx"V(aj]n<}[ yn==KDb3芯ULc4@>VW8R྅D-z> D 7֗:hX<&IF' dw̓COgh+m eL KYR 13 #px'/.s vjaTn>ž{*kڣxH]-Vq=M]G^!18XRE1>g-WiLG%(5c#|h0r0`'b9{f]ڍ1dcOp5j/>},Rt;>[#lS[7$~d ̈́QEY?^ShH!"؆5Nj\i _2,/g=A]FM*BV#P o ؟5<\<rxoUhGC'ҐL^Hrk_T1+ަ ZH( ަg|/y[P 9|}sAKc^L@;!BU}qiire9.WUmI{yf~z)ya u},Mܵ1ꡪ ;kP6=Ef{lw bȎABSʎ"_a XXYT/vߨǦ8nM-ƤO Pr%$|EM}]A)W7[bbazi.7Bm_N@-_qGL{SGeJɁ`J|kNV;F>X"c$KF7i'H{. 1&ϯT:NE ηIX8YQ|CXr1W%|qB#¹k.`s2uL,uV1 vvX޿=ip*)Ѩ\ +8EUD._ fX'Bx0.{~UF \2W-<+_U:SWi㑾Kuh}b>j%?8;8]8ȲVY".ɖT•@JBm0eZ/.+5 ??n  0Ma>鶖W~Cny}-m]ͥKBtQ9 lo5*7cDqoDan0Su{Zi3W̟Mc|QGYmwq:Y@7˹&Q(qi1>0m?M#C:6ԛIhkR|Jp}.wH{՗F^dc $mLMsDoIosި]o 1Aez=5+9`j@BPtMUg=_9< M.Wy@sԣ? ˎ&4W$+1& ߮Qkؾ7'gT%#)`X@+]*)* KA3|$͓)l&}%]93ۏs>ǔ3_I,>rb $'k15+ϽpdȦ.I蘭e}jzoejag7.23sm.M5O,8:1->aUə&,w>?e'FdT/eCKnT\X@sV/ϒ V]kϯj÷pcI? Jt\Np;) FUaw/WVi%wP]ȅP,~'ze ;k 3=Ppos6_Ω. Њ!pdLc q$sNngO?S#5}M],nvjb? Ķ)[Gvrzx?Y/kԫy '5RV!o}=F 9AfHEZ I&/֩va(֯^ss5 ᏅЂ('oq&1) gi3F5c a]Bb4䉳l[v}T$+x &H Kitv)ՀLHFYu }ƁMx"/bCjOsUŽW@)r|?޽_2ň³fP}ӒI uՓ`6jJ@eRrX}R Gi4q[^W.D_*Z@NyF$'e9oCRʏ8X8Sm¾: 1iLVm46E&Cޖn7acD\梐7>UqN:")VH8/}g3>/Jph r_S mfN{7RV'4[ _OۼSA +|e;GR% B^~qy&8eao|@&t>Tn wuyMD2u Bc] Ӡ „C7᭑~ݚ(~ieuIȸ8a4g֞ú5@U'ʕ3G%D] ޫǪaʲQ#yH fLa7h}+Qd -į΍#_b41#ȥZޢ IS P='+VҜgp7٧}DT:aM|'phѰS{l %";k񯚂a $;%64N>a4tFӆNx{?|r({ 85kΡQ8ϧ카&'=J 9-y=a寎IZĦTǠ|G>SRZ/0+|{<.Y&nQzn.Nޣ+ڤ} _y+:5}oFA4TJދR^@Vl :WE׼1Ep'rGx˲4⍗i^ (pt'8HzC: ["6:pb5ѽ^8I#SrJompb@:(Jg|@Aު(,PdV ~`Ӱp5\Y9 c-wJAҽ3eR5ٸ hwXwҤ(]E?R#+US q9P?7' c/E5_GXrILxগ#559X%I2H5FTM<>s*>rpSFr'|o|͝ǿgQ޺s*Ly[vZcG_@3pSSA)r5Pθ*7":/z ]S2[B!C趔?jK#ShfU : Ja|hvWZ),*f+TRh ]{@WAc-&tΆǨ3k’PĴk~wuĠx0756u@iFZAmWJ4$Y6t*fnP c(x.HR(lH{ܡIR3w]qHtg͞I1z5Ehi-ȭ~{\tel S>A˙ݘi {,J߂Dno8ti'졼!qQ }||^( }Mt-҈oLyr]ipXɛx2 vO&a @cxTNRGڣGSܱ% G2L8T8% nF0$P̯ h<*SA[y`>rW"SL"c~}>d_{gM1&6iBD[1!YtpV(C)RfCeT*?K[(D=QD=aq^9{Rɧˮ bfqYNqSXCV쓹7iwt*xpN,l4fſW_7B[Q_~|q;JUEܖ E}\DL8R|ngG_z?dQO?f<۳_@\ӬG) (^Os|y dr, wFOʶ^Dt9}s縲.$?N;2Bdowo "? PwvSfQ1<hM#-n{>Xs{qxڲKwn;Y*nY!XV\Y6|Y#c`(ҥZōz#OA~Qh? ? #(*'0%3wB|QKhbHjACr!jܔ*y,ƻ?ŀ,P tJČ^-;~ 4* i~N! t" jģK$Sj\\ "^?ˑ4=W^g08fV^9 M>pgyfwCa–Ts^tÆ{np~f~Zm _|;>633jjsK-b^ƅwFۡ|ƅyS;7y~?rC+Q&(bA%x]PtGwRd/A|^RE>sFg N>`7+LI"M2ANFհ`4m}.{VLPq_.X@]/Q1<'圲wUůLw%4S:ZJ#y~E1޼k {bȳ‘I,RpW;|Ӎ!ydg8 2By$X!,'/[@W: i\ɖ}k>XI#+Pg7mŹd笭+"KlP->s[bvhwݐWD2(8 Հ] 1jg#gDp%ۉYo5Cz-`+^"6j(cDC FjϦOA&-A:$*r!}# (bܤ-؅KGsy0' hб#╿̡EU]xSzw {'q/ŤD|#pe?|Ѱ  =F6Kь7bzIzk28(y^^ =ګ&w}~1i'c.oGe &Zau>p-Ҕ?ۚq+&=jkF(qlhVG}*C o{ꞻnTi$Ќ@VDGW~)tqD@N,q t^=KQ\wD28.|.%׌3{`Ճv>(wc|~щlk&k@<3FO92Fn:/'].R*0h-/āéٺ,T/~Z})fj` گۑV@h͇"8b I}/aEX@+*ƈW>+Ї0\+c!Tp<ѕw,&<>Vy/H*q,ۄݙԚއ˞S(wC?n9+:gqhDEx#kdJ+[==O awGQ֏+7>2=^tVgI˙ZҰ<7@55)ƑCqu6{<+?ҧS27z`Ϥ b$Ȼ40'!|l ˔1>C, z"zZlQ> ݫ~Q?jCqM(2b!6!T<&+G>A뻽Gq1v92#V (`; `3$qvHSK!wz}..EDfx*NwYV[( |BAOK>=$:| 0 +3ZЈߨkv ʇ ۻcWm}%DK0udмPIJ7FY&ʓ,Foْ;?u!V9pfNʕnw nY S|?j Ә/>Q/"l01E\T{-p\%~|m hG鄍:la7O;Nw^M/ASY.Wk0ʵ-/$}DӭWUe葹P6ҷKA9/"p?4i!zD ISaNFՊnw%]emP'#W`tw7.ׅґC'[OZ&@wX(Os]@"_![Qh!yϒ'ڱP򙗄 >5?키6)΁-]Ӡa8g#: L<÷qN]ΤCs/7ͱ f=w9W%*l ږ 7|t!\("8yp W2x6 C6oFuSr+"ɔU<[)5wVG#YGu #4r4_UBjmҚ%2oiuͰ)B˂}bLQxwkCH|)2EA|r\Z&\h$sja*/UcIF&;M:Pe+-;EmR MC0W辮 gpR/;_ `3:`uْux+|}v :l_cr X'W* %h?S9I6"XH&$JP΃a.ds&Bn5Zx S|~ p W~ae%vl|k o|"0- z\D()M26Co_EtӁol'w"eπ|(>"r|vhLs@7^ye7TV3}Yc2itk!0Ihroz;dv4XLg&XTޢ۳w@9}1НѱH}}8Kq8>iP\7 {j,WL-[tE{z:frtG-&g~0\)Po͐HN"L6DO2 `B!v_gSOL;'=t0R:T=dA8sZ@q}k& =`ր+mPXq~*˫]UA _%PO: {3$8B%`MjWm 2?TTW$EK$ܗ|'ߤI.DZƨWURޫ@ivOޗ%̆4(xPu~ *7F#SoВR -"hזQmcӐd!}g0?jo{@ 2V)xl #`\o{ׇ]}Qe:.^Ӱ}W\ \{w}jgؼzӥx_zyo')H$C+aCG$вh\ -mm֓H%h8L? =E䠓GD'|A?#tv%ٮrjTe-ߜ]'⨴)JǶ{΁&xEC ؆rvwX|P@k_[ j="žnImB9 VP}TA .f0ˋ犆9?ܑ^L? "zW?ifXɮyro Tt]ȿ6 Gsrc@;YZ0l~2?Qb=X$KXM>((h2ɡ7#} mѴzRevA"F@zL죻{fb_$`MxřlK8pRs 0J^K!J⌜ ײ6pjBd{YO5( q( 21Nj:LqQ., 81 ͵N^>s cɐ8 q77a'\´6 K,$ޖ絚GYJz} t~ ~34,ƁC1o*MA+p;u@GO*ԏCru"@,F=޽| Ļ^!  GIݎx9#]_eRKNL"2(A22aϖ$߫~ඛn(k\"]. CoIh_ r1 w${ 429=N_Cd<y2,7+ M8>$gܦz<C@02qva@ޏH30ѾvmCfs*S7T0fd tD&lӵ֦T۶,CGUqJ"aFrft%Di#>^aqN4&'o !?L-@(.QIQ_3|:]<cְ^MK?2w9B?[shfnpC[L>SGOa=Tv◈ c%2? Η(6sh'$bodK=%wE6٣a *#z&S+Hv}[P`(hwtg(Yhϵ^$T,v 9xhV]=2RxbG-v2,+Hw'TS="VD%gA:s+aout0)`bAL\T_7ItTþG(vf;Beu- o xR|x9Y0sޝe, c;a»r _]ttAw=Y8n+ ~hey4Q@\CKqhCڗ18dm931I9W:¹?T1/lǠcm&o;1ב^;ߛ]XNV [Nu@t~| p-琉abCPOس=vVte^@]w\/?iI>rP=}#fY";=5>oP\<܋1!0mx|I }ݞl g]d%h0ZkCI=`JULZ5wxGA?ljo\_nǭ~>Yd$`k{ #~)̏`/QmU ؠV0'c%{%zr iaOq8$w0!1h YsaH%)j>Nc Fs n{8Nlq@݂(ҫ9Ȼ=; 2~@SY. Z;|ٚCEn J75"+sgHT:ļvD?UQPXZz>?TX(e }(tZW(]@'L_Wuo$zOW'ˢ#S/ҙ& .eq"pa߀ڎ:G)w߬sZ𣴒uX2W݂MO_Znm=M>n gz$CTFl1HGh m:w3i5 D! b%U1ήXm 2/'h8Gc&.!R}5hPi}0lwƊ?ūε`"aJ'L/1Imix Fb n{\[d@/ [ dEjULy(5#EGnnf9% Uxg)(\WKm_G'Ghd5r6naU4ܞ.3?}T<'Aa AύE TSa>eCo)0\#}^#:fI\Ү߰:E18ثCI̔NJ*9tU?]|r k{>؎]b"G'i+cڸe+t[FMtmUSaV@NȇzqpJWWo:xCtJ3/n'+V+ƈw ~5de8eg۴D.Y9oda͓+qqHu,^Ee' _-c5zq) |kH9fKMD_ ߻DWo釾s}ݼ}uԟI c?>Y^| g}M A @,jsD.ipûXt|si,Vu}cؽނmuZ#-jZd#@$:01u,H~.*GקQ|:"V~84f5_4"؈ܡИW,q5~z/6 ]VBaU>B2,/EfpNd64*op@^ǟCWt3X($¸;܀xuyW N˙~G=FE[N|ǃǝpUH78hp^"3c%$y d|~i)qW F|щYHjqsI@J>Le 5dG\`/Mz}f(ьJ!zƈ˟kdDF53jk1 hwR  -z"{L8`;^IR& IHTyGÍAž"ϩTp\9N⩢;A/A'G GH_<:Ia偆{#0%^Q6'p5bV)ݧ(PT\`}ܵ ҋഀN|D Vc4< ~7`|Q /2 [ťN`"cˁ(e !~cTx&̼&ę Z!PtQpd#.2<9VnktC.fC/bz)1TeӖdT&S53|hG$u@W }5`RKt+ٖ4&r]j5I݌E<8z5+Rȿe4&oQ-7c;88ұ5< PдT\)eVJƚ75⏭zZt.Tk'Փ<Sab|ljM*VV:LI;[MY0c|rXŭWË}%xshy-yYQ3Ufw{~c˱/?r-Q5 U)V =t#J4u@?a@V.lY}krgخVidsy͇#P;O>Y _L{aO0h2; ykUk /#UdkN:/ZN(soW0 D1r@2/wZ)A%A(`pAO[ ơС9#'\D_"~@Ϳ.Zi2痻.s Iowdž'%Ғ`-Mz~~.ju=^H!B&;4ſx\l'Ⱥ/]#LP]tڕ%TOv\@V 8G%˙5d\IhNeYb^v(ÓW<Іn ]Z+ΪbX\m1%j1XVj, {lFM][Lj-/_9זd;q6|8ƕO8Q ?#/Q[X$?4S]H)~8^>2L7͠gy!7B~ 7lCW>\kxǦfWpLw+k? W./ ANZ`)f4?k'm61Y,$}P3dz(/BqEoYIDT*(G=n? =iG=<0_,M_BFxp]K- F:jy2]og.*ex7H?'*g>ߥ|B/. J{.+R*P{(4p[hG7/<($Iȵ҅ þjD@%P _((\۳ ӋaQOMpxl4v.p,Z >a|`f - .')0|G:~݊}+]S/!# 5s'j_^OF6[ ABSb[LI2\!%D|q 쟻L#'VQ w χalfYp5{؍YCk#0P"z^5)n[_}^ļj2kjhR0Pf_swTskU2!A9'1J[7B&U[Ln+eIK"gsJ_4u5\Į]N_ JlO΁Ex$Xq*=]tMy. 1kցhlxL [3̓G)nrNx|I֬vhʕN߹Mt؞\ M.SllMt-6J{=y0doܻZ~*-wV(R^B~ -@_FLD~~lzQRU@jGig z&R6J$O$P ˗{~& +$nŋ,cҧ:a"'H1Lrz 3z* ( MD˹YytcW9q=,V]fG+[Vƿs(o4%cAwj&.fLj YeeMw[&(Xnn~ Ivro_ҳjѭ,W8<`tsMN,a=p* R _@J KnANZ,0S1?1z?8C!UmJDđH8{ BzHHR <]P{7h'f_z3X NcP\sSHNɁܞœ|u,BXQMnހ#u|v F6]J1 7|gi%5~?KW1Eee1K~jq kʜ=j5öS*n=RRCxG[cBBw\4Ɖ,r*[cH|^l~&R[Ơ)}W5bXbҍ4++&赝'k 'ȫsS?g8`ǥߍ7CuG_Jh]s4ڏp0[AqYKp?xs9f5Dc/Ok|z:9@Y"ic#U]s7 Po `OZe2vuPqw6 E}>SzHS^ dNIEnky ]|-f=nך'<ћ!TvHPxآ 1[2R(^ή 3^"WKygP{dR:W|ω8nQV7 cTlt-A84y<+Beŝe MV*7*#|n偵 3%G(#\ s oŁ$%Xy\KnvY)uL+3,փRX#XQ?l1B%m'LA C.F4Cз[0{j+W謎^!&̡:87z8_BZG Bz*AmkrO&z%Y v{稌#@Kp1Vt3:f%.%!Ut"mZ8ۘ:=1+$8TM[~QSBѢjlFUȽ]Eo=CkQc ^+ -eq/fm%Fw%;AHP0BvS^w)T"Θz88t5l6ԁٟFVb!Dv7ŒC WxyqKm;Zv]v04yYo:F E(v'yd%-SS7':7|wOOB/~Ц`D^aҋ@;>.&Uy5aY 0纭u5}W]R-X͞qx̡L3Pu,v~m8{ 8ll,~{!Ĕ]DAT-GX 0ȇG Rk>X>eٔp7B!a&o##XA`<7=ըQ#$6"K栜:fA, CDs 366MB3/Nlgz}n :N31b;tޘ(ꪋ) Pg3 &Ȓ[a ̖$_))%Wm7Py6#,`z"\5s;7sf<սX.xQcƨ?+[4^7% Uz2TgʨHWlǂ-k, yDfvڢ/W $!`r F(g)@?`Twx|:?Ǩun-#[ *6 r;nP_n0}&?L#jojodzLk^X ~1B.Z &{r/Dǰ/+Ca%ӕ1X9GH7 w]zv6Y{izVH{:*~mvҚ]?BZ=aݦhʛ>#`Z_I7w#@>bX$+6b na#QtBAʍ2v89+t,eLS ~eQ`' 9E["}= AI@8ϳ](nٟ`G%XQwڃ`2@i~UhhMM)IǁF8pj+u7=lm@Ej3 rVxyi˩=7jhhGaoқw=-a`d`:Wngoy{ ,DY'@GOAꙎ?zKkpmO-ǷjN%`I# ⮴@5Cña9u?Gt!սŘ1n(.(mȪ87w ˤD rL~sIGyo~Nċ 31_ih;l4 ;k~jb-䗏_OLa⩈:y΋ʓxO6/a<2=(?(FRw^Je0/̾ O5xi]_f|D'>ɪ y?dAot &-gF8iVƕ(,hmBf>^ǐB>;&*dF Ao'pE N xGפ |8S!kl87FOD(>K-?FR1\M"Ef8Mz#*_r*PpE.bgX:3q/]H'mQg' .# ױ Gy5KT{g.W8X%?9\bkjGҪjYxM&ʖ9ed?C2 jsA~&?lyxD"i37HN\^I1<?pE%sQgը4nW*&~%+)coC<0:@nYu$%ekc&jg[S׈=PBAn>\V[P 0N7BGs f Px=Y ڻ׿W]ϔm0< fWè9Kc&l(G''꯱ɚxb9|u&(oiq{ =_`۪+vYK./U$t[Ьz"?oKC酴w4޴YC뮘D,!(࿓0qvH(&~; \4q#>ozb)nUâH<[ #t1[jhԀNJV3ZE\c ZiHF'dϐwp@frO7_fW)Gy.t`E^lenϷld Lֻ7-fz?2yC Qqu>M?84b$М[&3͆0G>"%,? r|'FѰޤn(UN€l $4ڑOt|u/.>5wߛ#C<59gJ*'fSE-L4ou䦄kȓze/I$H$kJSNʷ& 3Qg@e .OfNBFiȒf3 qw\Djf q eEd\4H ,k*-kxBf㝧 =M' &yRʸn,}Yқ$@[ݓY~tS> ֭SR,<7X{)uEwkIAe)PO^s-J7c%h9 %%^: Ve(2$h4u!jhƏÚo{$d|#aﬕGq);Y{,t^9R]cVB<lu^˱Ps<<﮾{f_:2 ĭ+Yibm57/ڱ>n^C J\)FT'/{FA@$-k0[K5aaávzI0dmvP3!hΟ/4~&g|M.?ݛ.K>?;=m d<o@_ CS$QRRt==xu-Mtj\gP~32JÍb$ck 4q)XdmQ_"8BdvմhTa R#tOC=H>JwjB>h6e3nЦǞ| "U[B y7٧Гjq(0[3ϵfͯF}ޭxe^->ߜ"]PavK#:zv| o~+HtC4 V(jNA4뀚^6FeqWGyr'*^tuK+ź ̃pYVsg;}ԚiYqwƜ=mއMz!alCvqo}8wTЮ6V}5 GI/iwnW֏5 Iϻ`6h>mrodNE bMU!l;Bi^"7L~ϩrG*n\/я;4D!;LK]>;<AOcEh[T#Yej&}W`]T<^H5uTi_8ׂ_ YTFeOk^y1> "`K;Q;)A}b[ksGw7lW m#_C8jz# C[1fpf./iV 1޹ ]< j5,? 7):/ok}ZƳssF4k3G0<q)wi Ή:!u?Yf,]+lFޱT`eUq 'I l Ak9;#2,=uH .Ԏ@/cDD=ms/q:ah~[9 Yپ2yZm6{%{_G+IjUD .Z\.nKUdc#dŽSC,g1dk{x/-rZ]vyڵW*$ٱ` O 9]h4 yUS.}?7hMC8-K<ŁL+'9&#.Ěb>Ĵ;Kd_ >[7W+D<ϐ%r~v-~zLVL٭ʿgT$6%THN?7SՔy%in ~A O->Nx6N˶/G5TIҨ7E1rQ=J_*GT=MU@LgH樟 rHzpld>וl5xlN~oe~]t~_NBōĘj7Fn5D LR[kO:@ݖwKݍ,y>x{w쎼-{腡s[X1:':/{`y@j 85>Fb_mF1|J-"AYChw PM#hiHQ,`47뛬g`7T?*vZ v~"aܻ? D#s>sT<`5^-GL!í[tG>_{(|8;3zo5N@/g-g>y &\RA޽%MY|k}M7hHc0y#Ǻ1܉pFV37*ָnYL"N 6Cܿ rȈ[4<2\@=GhQ]_M A:۵ 'ɟ:eOQagl­×Qz+I {;`SI41vvUʌ`@t~7=?Yr5IM>L`z |5u`_Jlcњe^?Zp;{(R58^C\#];3jcw}\-QIlmVv̖ [a*G?POfÉG.pLG. fPX[-侚,%adloAL.}\I] wC*D,~ݻUEiUC&tny垖}xS5;U\$g~#ϱB_\rUỏC(Jxb }Ġbw)~TqߺlpGko}H[&UpJVKCȳ9ۤZKF ը8p(qgwnNJ Soӏ)K8,!ͱ]AY]~wfhU.ۥl:ymEIs;n3sڙw3-Vr-08Lܙo_'f8y2T=lXQ6J%gqYo6w%A_Y=mx9 vY(-12LjUӟN^!*iK|>Q2Yev8h-nD^G 4WH)t!WR,.3toQF :uWH3Np+YƑXM9åXGIX[p<Qywvv KN"aC1M9 |GT̓qP`R 3e #k>yy{ [vKxx!ݔ(\5m4n2e{ $pjF\zg)HK>\Q9w3\ؙ;W[}\k7nH߯$-f'&dԤya٣q(QT7Q[;i<҉O,=B 7Axl,J]O+zU?Bg{:_F#vyGMl llb;DQ 4r.o ųmz>Eŏm7vEi[S%u؇&8,hyU[0/ͮjg S6noc$c9o^06a aiENJs߱5#8_)߉qCK1S=xm w&x)0/tib*庉9 L&h,2y.v 3dx“r0|Wywp=qr&e͈ұ Ľ:iz*:6ܧ8zj'*_~ 5@Ea]ǡ;ލ< CU]=r_焿c8if}^30.rH={ G9h2q@g ~ `2qfZvgueԵ:O ߭zOǰ@ -l A8鿓i2..Ҍ"n@&`>*)Iwx6֛9qZBVDU{1*3 'w2l X-`\A~:FsLuB`B\2Xc.;=17vQ:]1' ާ"N1>}ZD<Y_' ;N&ƐumBb"Ļl_Ipc5w/vL,dkCz\~n?j Nڢ)EcF LX& ?<У;1JR' fKmR~" Vc(RcހO'$8#6a,e qPj;H gq2Oi"]#+kɔW#;#_c{}]nЌ`|IӤ[]r@wGY_\,cǧmљ{>jd Oϧ]"9Mvn_"U'78v(Ht#nbOy@U"5۪okJZuCUOQl-^:Ix iiK[:DE6שP8?K(T==egjhKT$2aQǵS vDM蹛0L]`tŁ ;i;BNV!/3y? u{]kOەn!3Y, 0H]'Dhb K^g+wG|fGw< wEh"HxSfmWY񣆐Z+NFckr#o\Wj9]humuКz, eNxhͿ>ag6_p}t0$7;\h8jkw~#LGFcVy1g#mOp0pXeX8`>(u #\ g \H)iE>d%33W*DV!4d&QRlٛ]vҐ}yczAp2 5KgLhzZUH3pfo GZfTu/W]?,Egd7 _|]rv ~_:ҋmR 'iʖsC]`Cdh|+j(&GouۅօٲB+Ҿئ?agyw&okBg L-c"nE88#{2\JdOp@@5ok=rݍB`O E& l&7H!WV%.GыI|Y$_2ErYJJ%iL똓LtY+8N*2 6n7+FO5=h-+~3^v]4NGMΐךge(ɂKwEY_/^$VK._lKV+ "i:o+J{fŠ4SSkE[D+&o`]6G\qc[Wq#{ĖxS{AS=|JVȱǟ 0+94yac9V'SL~8Eh%l m$j@-e [ŒFp? 9sǨ nS-H,'t%-Z3&Dڑݥt넭+$˒2 =l:F(Y{s\CtJtm%hޜ^{v6>+gEsNu gnեB7BK~e[I2ku=ateTE4\wHEժVa(tLӍ[v0E>,'Gynӧ &V^9?##/Rc=GOTNP4kɡbA3DZX5Cݍҥ(wyذ>yٹ iƲst&`zsMq+G`631 ӠQN5,.mQ4";yEo+xaPb }RE}7SIǢ̣C4p,<*r,{OOoG$v0'Mi{(Lﮚ~.AQ9jݥ== nS1{thq '2}*aj:>xm?}Ƈ78ñ gnT Wf2 gC(pcIa LrV+QLQpjFY,MDVn_T{Iެ0rqrC4ޤt3n鮵Qx9wMVX_3jڸ::EtKº%-\bԞd*ڒdRZ9/ mAZ,Dzn|3^[gB Ŷ3&~o՝g -v 'b~|ͭB ݘ8: q;g* x#o캵N(eyq<̆+-(3S5Dr*蓼 F='(XTxϘG}o0 DtiWJS'afPp,\,raX| ,ral 5&rA6m|Ȧ#[&TTVQ~- *Tدɕ3w-0B^cx<pI(:֑nG;gOiCΟAKU{ݽp%.h¹34wjb((n|ߖܥw_>8̵"&hpySy%Tt[iU ?a*^nEaش0^Nkb&AKZuTfU2GT  ߭9Pj.َbըo%g-h}/wԪ]@8C(DV:h>Xf|DYO{ҝ14V+I<rasqRNe/˖|wL3jA4JZ.03'z3wWʿ.M%{C|sf_IF+M\}*g˓6I43!M9b)ټ,*]iF;Ct!?99ry3Lj|ӳ +W}H$SX mmG,wE:`ÁޓIw1ag X;r%i??sCڲDW+V"U"~?znoBի\$WثS>v4LZ}kQļ(m;g_RȖ[HSˡ+ށ"T4[:˺m*F♥} kf iO| kZ z@xyZo}"~Y\I_aX!o gn^ qoLTp]/y~4Ʀ{ +y˵ KzbaBcr2I/Moz?{B1 ]N;ǧn:?[`Y cV(Q2~'U vhySB5badzx 2BYTuOb= FgʜTd5ư.\(^6zQ@&4ux(08S9telcYs ܾ=0NGt :v\P2-:emUxUU"t-I>y; %sa禺F+!W7:f~w'BXtvכV`]IÆHS{$+*kWɶ9,/ Uib6DnK8dm|}9Pj^Am>|# Y˯/O}RH(o$n]O0';M4ʃΈT+v&4R}Q223tΜ%VU?#+/O}xiDl˝vAQ VP_C,7ߙȓHd}$Z+m?{[__5~V6$O੬k?Kֳ"-VK!Rm0w,w@M!=휢A$)}މzڊс(ac?Ƕ {Fq qZY AҧHf:Ӹ ye2wjC W#cio1D|ɿؗOi=j`i+5(L.0mbef+5;%nD$taelV)un 'ܔ[>rx.WeG>ؕ^gHrŵwahd:GQ!g"RkmmktL IT/m7Gݺ5_) $UNBڎǾzI9*tHi>NlZA·_e]a\<@LLb CmKQM47@ip(^> ^ 5?YͳˆnQ]Z`a!K DLJ{*v&(1u G~ `rp8cV Mbr%R6co̥%2<"Aw ,Yb[UF >f^kDg]꯽QTX7)ԻG"62s&hEGVeyNe =zGH+g9 gJ0x}3SXzbgW;~M W-eR^<*-VM9>Gͧ8J;C =j#ׯ7YK'30xA|~s~o3 RYʣ<!l7=[/:~wFv)̓䩴n j~o?r S'D&2Əs#(hZ bN?ԃǿ{tƛm\]`- 3,}#ԑ$ׇjL(s6aBIPyrjt/tlUȶȦ!KA!ֆ r}KY֓SFſiKԎcK<:ĵ-vdPp#Kvyy4A5IL|ᶮqMΩ~{e)8|w օc|LE6̽6IGe?t.8 Do]5aە\28~LL3y^>KhAqኝK g} :kC\ )(ܾ!Eb4*t Q O4Gշ%Fz3O~ܻN*q;#6ehpM3K<).~xJ jt)J1v} rI'w[O(l:4x]'k+ ]Xؽ fOQLX>Mңex{v/4@'v䓛Ṏ|,Q@2Xɯ%My/Hў\%V'XG^Kjx wy_툁O< ǣ~㷋FDRk$9TD#eLJ♾{0dyՕzЌ$͘Vy򺉂ļlKx~aK(uK,`/wQ;ٜ%slzy\Q{܄?J1BORZ`YrýG1ZÖH$,?pZ["3c*"n>Z;?BպŠ 2p\bFX5t5dPoCEoœ䫖ͶDHomlO^Vqq]$oV8bמӽ띉LK/׳ )7xi]귮AI$Js:L*?LVN|*4 *4Xy(~z2ͮ+~aafwUT~dlkmoiɆAy8:DyuԿn&Yus|`Q+ݴIlIh &bӮ!IO!3-WLv]GiO֥i>(#7;r4w@Noƥ!#HC$JDCi M%Q*iB.H{=OmI)>9sLngl4oſ!76aË/"|'LgyDxVLWMa5=UXsiw N6iA.5ǖ6-/.ux wwwDa Y=k}? ]JwpzP~)SHtzurRC?{.6ӿXxY \9RW)qBHɳ?@WAzѡAS}?.ߪ GJ+q؀j 9pץ@Տ {&]5.f°)> |Jil]kbq_^{VnM@ڨ~,~*3w @9Y)h's\ژw$k_ | KaFG}2{ lo𭁉}օ&&ߘXQ!|fŁ+[lDmTa؋֋#;'eB}R kwqlEnD\,r{4ɸ^ew;7!`G~/qƯ . @HH|W;Eqt (sSo 2BLyVHd`G^|TyL6,.@DսP hZJCzLؓEc8~StLK( ӅzPRґ{_s>-|mn#]g׋`Am{/cNϦ)rj2dH\+dhQ;V7ǭĝԣ;yw}=/gfiذ`Ըi,#[*Nx+^ΆJмre-63~SdS74ZqI>\ߝ87&y;菈'F? 5ұ#5hAx\FXcQ_ IutI6ۍؾ5vø2w)c_ٷ؉k9nAro=!+yHίѷ%vJ|D:ݫm]ʪGQ("2"H.9Ah=O@m6F :K3!3\MZ7“aGc.̾f[ڼ'ɚm7(Cщ 9HzG?`鈗G-ɮА.x#h8.s>7W#>{ \PH2wSw2r1'"{-TC †^GDٲ׎PM!gX^s!^K9 Dz³00^o!~[<{&~]ϳMMVvI%[!D~x|6~kaOhŏ>ɸӍ__Al1Mvn;f^HHI9^ߵ Y6ms8+~E}*BK B 令7PVH3c')^W%^+F1F,):&M!Srʻ+X3ۯ}~ 8 )ۭ16إ2kDTDjwX*FkխwQ$_sƂC.4nʷn\5$F2 /`r|UU > ԲDt$_nw&F9H+ZK{dI/->۶߷^kwȢXUeBׅ._" g?E00q` nzo6U&J~w[q_XX^>/,ؘN9Ы?pyXq*6Oj_,mPloje#Mۍ1Uѿ=L4Yh1}5 h)O>,ے|s=XF~kxK KxUpjR(4X˯/2 CwÌWQjr[V&;pnפP>RSwڑL|Z߰h? 8'〚`m$4ㄿ 8zuM7^xͻjҹQsq_z~sLME6Wk^l|-l:/+Vl6d[Wb <>X%1pv w~7tDtf`Ɨ*{Vk㹚 ,wÄpT|#9o޹= Xg_+ΙRvPm?v52{l3t[vwBx^X)=Lw9BrI;nB݂ оv-+ &r{qX4:'w;75*S? ~Fp, ݬ.AAAvDIzgśxz}4KRY(=[ oP,Pu=Ntc JZY3,A|%oekk]n 4C#;%㻼n 6oO*fvyrD&o<:PԿx0u6urdIn,M&ਿ'ј[XYuB]-d}݇c`Q?'{Gؙu=C,NG<-Wʕu7Y!u7;ZG_"UHI"qZ/E _OI}bdy$M eUfN鴫dA©;]lVwsv־uȑЂ0+4n19A֧J ^wQ3?OV%_^Dn~/HK݋*9y#؉Uބ+p?iM&~tdyciQoέ@5D;~Pԕ<*x zK%1D{O)FMYOG=LFX?2fhwt:H4vQ`ũHSYh<+y3V/H Llu< vlBY3 3 |,~u,?S a6NP_?run{x2?A! V?#Vt[ƽ,x_{+sq Z*FAeҧ,5>q12Ԕ;!x?'-z`qIpw",XvwX!&֏;4N@Kĉ*986C.OJNH `c_W.%,ש O/ࠛo#Ŋ-5cad[0Avõ\y\ĢM&D}oʀ\>2$so?g 0_ :3W! YCobtTf;<ݹX{:K G4hk6=;-hx<7+^ZևCJF_P_b=O˚tȅWQFCJv^(Mf;QKlF>=t=BKIym܇)_ChEZyWȰJzE+mGeҌGfJNo߰GU&͛K U&&[/xNe;6\Jcяt&0/ݣ6ɢeLp}:78 8Ʉg5ܼPs=MՃc?Zp h2 \w57g{*f$%rC25*|KWGgj7~섆b]%o^qߞ-ͭ{0{]x=d7zߢrp)ͅkqBѩ>eAUOuT)A2…H^PY8nD9K_ׇgrPcjBXxTVtڋU]bZt~˷Jx[wv'Y}ؘ8^n?*g~ьd߁o؟!R nX@~q,GK}\ȴĞHgv݄0&;܉(/Ok ctW#ccDB2k-4j jt :Cyv̻y1.'j.\G[8\'տ {߻J&I .ޒzDZQ^ }!ON)Mx6U@|3,KkS(=ǭ&yɄ20%&m} 9BZL(zM>ӃFǽkX&+WYߎL} I`76LR&ĚDhڌ^DCSVf=q|r5ڞ3/s$)oQU딫]H-nVrNԓ|Qw3+Z"3.iAFz7}>L_nuNU;ܷG4jޝu.\.p7 ˭4cߓM}W1}dX}D-O-7]Km64so3k5Yq_ژ' qV્DMxr׷< >}p2:ڍu-YS9]ńx˨,3(k%?vn@Nǧ`sTlDX /fb\.YHm^t7 $&Xtb&0hnmQqA[t^`fOY;7/,*z{!YΓ\Han4{ffїݽ E?lѥwQn4/mebۅXTONvZK^G`"m=pbsiG7|D tqr9*e$G{1r}/)p E[Q0Q]f.".+H<öWFmˆnޡ˫7t但 mjGAYXs *^ =e,s#p81VLu邴=n݉SK{3`+=;a5( _5݁˛#;x"W)9=xGreJǛc,CqnIy׹*/vtӘ-ؼσՁDž]P럌uK?gx΅[h`0l3GOe`-,$hGcN ay {&}V0LQe? 3`k0 [k|pwܮ<5á/W|{nOp=&чg_u@,OCwݡnDLwx@ YUaM LLneCE>~Ǘt#}CGXrG>|B3[}uņɴnTOEӠyyR/0O.GznLJ|=B2s~ JbY7OvD A0bF^sseըeue|OO}w;֧_)Uc@jUК=%bV6+MM<1_,,*rzQ+_ ,ih Ǻ6%+JUh#E:<&tFٮ^.ڔ8:$ZE]"Dv7kGlǍ1dPqv ِR9H/jS 5E<ۍXTa}RCοtȸ&}qv6T; ,I!CaW+=[7Հ/q\;4_`asf ?6$F+#k#K(rjĖDyvm/,K6E I+b&H8}_X4m&]ͯ$aZFwW`+'>:2=/t"wXEĦs7 dLz0إET6ȵ $۽R {[oK"UQSHd+R~pP] >Iz 7ɤSjtC*n,xȗT)%[Do @H$J*ne@~>΁#l/3=8^jDMhW٥/;|R[]Lv {W;bHY bzfѤ@+PU\zg leQ"#䐽^!;;*{޲2"{ds{/R">?ι '^* 4^B[5P5j]* {t΁3ɝNz8w(@(;,y^B"i ]:X/zB+v8YE#V/Qsn,ts-97@m *Y'_u@?X6B)x=3,zGh,\5ax][nR7āBNghNxR_ ²T}2uc3n / @F%;<6}hb LdV( 2LZH κ-HNutznvBL@A}:Iݔ0wn2sc x,|tl6bX!;Fksyq + q.>C3rG#?J3ߪ#Xѕ?*Vlݰ{WMzp{ nY2Gݿ:eDO|"_{ # i< )~c{A[`݅<Zغ!yFZQp،osg}…\Q %ovyls sꎅ$7kZ>2TtDzc _2oHbAb&(j ׊5Kk5 ۻ<%GO ׀u,j(_RZeH).]Lvpau(^+փX Y[$Z؁EU6JB 5ɖ )ws}/|0sx -ڜ~f`'c <?\w2gAٞW9*G \D7 o'8V>)ݔ: Bu &z} Α@\!ZP/95jϬ!b(g2vCWDV/^_j%r0w.v@hA' N}ͭh/_VZ`='p8mVI~F87 ?T Po2>BUiLF T8-}=^kâEvpʽpBaO}|3hh^qktGG ޭͶaaZfS!1Qx0? T`h>9b~U0QQg1[7}W>z*ҿO„ 4m~p7fn}&2K/JoQyxxdݻh{'^;O`ۼs ~'v̶  0W*c߬Zb_A={QmEdl[CGH(}!/k>B1|.$'0@$U١ ".nkWş|,0|I>Qj܇~sU(?1HId]5QyhC&loЂq 2n@}@Mr5] Q7g.ghgjWTx3WJ,x""y+|CX;$E[su!<1zyixQ.FAs+،@d܂HCp<Ǜudys/lh'3FCjbJB`*+6=icOlKƔ=+5KBq%5`p^4nuRGxg5` R& N>imVƨ6:(W\Z@LTΪ~NP˔ҡu{T^Lz4~K|g<_i߳yYf-A1lN{跑:7kT')I{ '@?̭i2 گ{s9b#" vZ}R/)GF7B!Qp[VoFhձei[)LD]S 苅L9W0`s^tc"=VbZhkx88 ARfut\^lF+0U$f >yCk!Y|J1SP~$`!oj j% Gh|meOXfLsZVUXG[ PΕt d{ 1V9^ 0IvnyAAoمQZ d^Ń@&@2v oudST\Y W3;@kcIcW$7S]|Nl7i?-b^EC3 Mb27 U*G ˥ $|HVl eQdBjFS1|)tB)mP9Y]"ُ/F1q-ӻ.wtc*d=9raN(:]1* Lc_r!\qpVϹE]@=\"jsV"2[x^HFeit@ ~pJ Ķn׺V8b~x*z`ōòMKJ{!K>% ru\2 kCL OvfFag֤ފςWTƀ6tto2MVRIdn%^|aiPv5b0MTAE!$Z-dq_tS\z &aq2}Y! ~Bߗ!aO<fxIۑQc }ƭ,CkL6}I4Yh\A^^q)xqyc|B&^N߀2u0Ts-HBsXza?P68LNS@Myȴm#J*ꬁӟl밓u*9 i$EgF~HNVLUV(T&|)[4xT&<7w*1o>Suwb8*i?>4{P *Ů Jr1le}jjԝ%$ۮcJeu,$YK/A2=`PUk>@>I9RcN]R[:EP R MP F {W5O'$.s$'RۄR OKƿ~`>Ċ"Ȋ 9 H_F=E+9r0btEP502#>˴@" &*|!gtchQ[6EğB5G 7p?+ rU`x;+"udqΜsZ>#m2=$/*R ÞyU~S>hv'^BX<,VD*Qk/C祝)Ȋ'%tثgWC3ѼX:*_O=-E'Sތr:Z-gq\EֹF;5jA-I `O1 9׸EkfblY޷2ӟr*}I [OM]smCp3[\.VomI0 z(Kɏ#@ %ͪ} xvdZ5@B:X ĘWBe݆U=,4ez^!߲.q, x{%z pMprE&}>BZDd+JC?mzb&~ V˯mG|M'P ݈+Z'RctBQ:9# :a'd-#672v!'V.E JCErM#(9ET "AR[}ݨvn@?z}qfܥ׿ڂ-NmTs Ȕ]xU;$]kF%,~EhogmR (*Qaor 㚐ָx@c!i.Q}ᄈ2zSlYӷ DM>&9;"iZz`6#eUt &cޙa蠴mIsֳ=XGPzu>#ײÂ+Oc=}6 Y9'j?ڟg8: 9پv|#" v sYq_G^)I<݃O'Vɣ`$e݄:r|0 +2)cJ~ag>BIN{RJ ٖ6Mf#RotBiB9qԪg*jb<]GZAB9&P,a=J;M@8:+0zb7T6?*FZK%HZ.ң5y^>YK<—7A.l8~&^(z D"sނQb7⢙1Q1䟄ߢ< fPX釜jro(呌|.IsUJ V!֨{ವ%h [2^3P6E{8`Z PHMiINVԑwF / QkлhẢfY__袘~J?uӥB8{|!됍5X'8s],> _{Ā6?.0f OX*_E腷@VeVUE3Lo?C 9MV>U\W;Smj:|^ KB}NPҲX6Sq,4:E^J' sBNv6DΩ[?Kq38v0y G}WvJOV U}eBvoiX m` %sltA@[K@Y~>h q\}A@| o玕H݅3p)Џ`ts|+Oπ`4Կzwd 0bmNa |4|?ߴp ܣKR8ڨf}5"],Q~2e@r.2m[yY d tٔC?y!i$'"TW ؉Ĵ2<|t#XE>ES*=}@Nj%+1utH]>? g<lCohe$*MdTR"UdHvM*#$z#Qt<}}OLFi.jFt.ߗ&Am MZʄdk.XƇ'˃Wp* jBje}p_L\lGQGRfd?7c#-Jq|P~bZOׇ%kV'g7f[>8هzE;7zQӆ##-O AE)ur~ Jpv㊪MqNLɋiáFiO# SP,fU{O?egy{*T+U:2 nm]H28_&J9R|}ѹ]@8}}W+3u#E3@fy5 ѮK7^Mb03 ~ /6GZ{'D7wL?pUӣj- eg !Dz!_X؋u~{QS/BSA^CoKk}\5eWJP2J2nUCNvn/ Pv*ׇ'21a ~Ơ, nu#ONB9ab1sZuz.RͿPz9˜}}m@&t퉟 @+3,?_{4&AQ?HPpaES ;(A{/_,՞iB,Kd<j R2 7f)>f ,-7wÚ0bdh{+;_TZgG ĞEwRm5׍om 'SS.kwc H F|o֐ɟDfɨX7v38¦uQoyǺjN򉯞Pr^Dw{͘JUK rР$9 3ɇݤl} >szslq,nh˕gv7|m`k ^{ #f zYǞJ*Mu߁pVʍ]PMV(SހdD+zK J| -_%m3D; }3O)^bUg|7}DBP-Zr&XjQhUn+/O> F^~ xOOOݢqsNlHŷI~4Ib l]t;k 16W(qC@x:1 w P|SpBv# % Ǝ]D;Sm| n1T) 4K/AiHww8jxlxlYYA?9h긝Vf͏{$@r{cI<``q.K9`QV`gO ;J^ 3^yG.s=IzdPJ+׬ Q.W 㱬j68,kS0߿ \tvMc+7b!h퓰Ƞ>tź.*f뙍ΩAT?҆\t=p; <2Q(A>tKKW%.`*:V~hQ :;m>'!50wT) IdL BG9/Qi \Gʝֿ~ªof7 7KԑD/45<O 3Pwő:6o~qF|j '٬F7=Mwc5d; GIBZE 3ܢnTO ^+xlD_Xv(FZ|Ga%<3d{P(3pwL&U2@xYX>{X8%rltZc_d |Uqw+wmfe>X$#A S~D@~HY<q%﷡A =z =!?[Uoº@3Qv'5sDx$|QOO-#=ֿyxΥi+x$hm,Q9'恃Cp`oЧ=׼z*b\^f te/Tn @׺ /nЌwPkN[yakP. ;ǝ-Ⱦ*pfX2,z IoA9U(mjc%;W)ءsB r 2)=^ \]0=ۢG+JZfuoa X媓zLJ?|4';߇>j1H\C'j|OH c!ƅKڄQ4?ZzlS__M%:^v;6'fr~|AbfQ&bq qU5<74t5yhU% $bq@60h{nOyp7"c~fM7qIy {ӡmDNz&:zPr\ wnY|>].>5*M/V!SϓhV4"4w"nkN Q>}<=Ɛ퓨9O\xf;ޛ >&1yR^LHH mOEfT4 _>qcڊ4&a¶u}/Vdn*T焘KkPY#)kku0}(6gVhՊjhpc,{^(LpUm SՍ^sd3\.X,Ky3 1%C逷*}JˍփsJ@PQ톨s2A4֚  KF={7tWFqQp1?RIyƫ!8D0Ux={vocAP5GNl7aX[ eHw-m; Ӓo*P _;iZ.w`< ϟlQeֈϾQMb=S|)cyE(|Yf5/'7=KWޙU6:UxNq(0Me}ZfECr prТ@]J%Ћ3<bmS!Er}%Hqߌ&pV(8%kؑ ANE2"<սD1mzA0W'cEcaR`faTB 3ũ{`a6~Hw{w%Bi.jsZ)5ca?v{sd{?r#;JtA?=|3}̤zòr@mE=? $Q3⭁uP%z44(&[)[ڋbdkyz![P.,ea7[҃$[TcsV{QSFk R0Faø|#?<7&QrJzpPTe'=(v@"6ʥBUW4wwe=q)";b ՜ϳRsB4RƩ/:߳P1 *_!.OLͨI].JB^kS<^۸J5eKB5}9j,H@z1T$qL`gp]Roc0n0YEE %!Lt6pO!e d󋚰=S:yu_YuB\ ciÿ9c_"VT >xUBΫCl 8c_fכ Р]Ȍ̋Fݹt0{>S1g3gmx!"ן?+)S#,*bs͂x$`2GUZ$XlA @'Q"B^φp/ w4RR$̤A2. IJD2_e){d+ɦPUlЯ99d;Uw4EA4At)g^S*Vt^$sBc_xe _u=T( Cz/fzU];g/~XP<O/sHAtβwL 35c}xC[IT1}|jJi|L@FXI"5 GLLP,Uj+뾉PQ&};ϥ_͆B{K{qVet7aa[_prO|!+*;H/d(IoC#Νg & c'%ڀ[lEK7ne~ c:tO=Ylvg-R e.6x'+Z3L/.ktF.Y{o+^h=6N6IzwDOKpV šF {lshkcSWe44@]&y.YdVE?x.U\16LӾ#4O"u%CoF.(vxk3Jz rj]Cm_E'Kv}o0Rr( ݝJ˿?VP1iOQjT 2$'-e谾ೇs򤢃+ Է? W &~ȞÅxe}cI`B<Ւ9aR 9:5!NKߥ|{))dUf:w/6ByZTX3o&꭬ ?k,-Ƿ^L‹qLZV;r1ߘdwYׯ' 2 uLc?& ݂:jVx\=c~0hh/>L=O j/$pqxjC >dh<xU\zZqjb1&T78a{PʺН=ڿì3n@Y)xV"u/p{ɏu;T I Y ‘OW rکQM!)f 6 ݶձ)@,t,*Ba.:^^sQG@N0t}RʩIlBEqƅQ8_5Gw kעf`0'bEXn7T,»zWYqhJX?~p$.cûİ̅CZSx6#l-o cF"tӹӘTܲOeO Db馠⢹4uVA*JS"9ި9$&Q1t=<7juĘ9)^c;/}qxƱ_02Kִq多ȴ֜| S//6 PP2gKz)΋HSÝщfy)& K X2-^hk;}gq*ŷ i>:c7fA3p_)4R};&d<7<[I)5gb&0he䈧$Ae.cq/ S| y0G@u}Ch(>lD#=.:ZGjD3ZU("<ҐlX)97Jnw&F2X Xg)=Y| 9V_`iĀE$>+U/ՃVW&髼ǹFNzLnx4PjȘr/OH]Gken.FG6Wxn J*JD 3QhЏL2-; 8EQu -(_g0}U0YT=%`pNX 9{5&~s@owE|zPk}9W~څz5zLOeʗN4mH[O0<ͦ)H7f,; ٴZhR ؿܩZLGT{Hα։=*\ j=7\Τ[kw&F$%VYGtk埡k0k㚢0p9lO=k+ 肾ONtq^L4_>Rb\f#(eϦ<bIr`W;{ љX+Wk%,SŇz~<ji~LrCF'yAj )no)t b/Q^K.M9+d{";Y+ Tkq6x2iNӻiNog2&: /n88s?aP5 ӭ͎3{dt J';$.`tҸ4 5[$/u]}IfAej,jU4N~&,>1-O?ƶLU-zJ}?W]UXܶT_BӉݿb-\xz^y\xvWFrã'̆-&4|gp{jz1\f-j Kگ(<ʣaT`lNeSg1ΰ,%MŃYݓØ|0l<1~D53<'HSVHB0 qL+XW,n?4om+q)IA0aE+.Y*mdsXrKEyKەyޥjx[kY =kWL/!/7',`"' \Z+7+p-#(,xǕA)t[ }57GŢ}-TOSl7"ݞpڈ|mzoS'Kf.,L\`ᑢyL2ͽ?,/aOJMKíDgDpw_@+>b^Y p6,9 *+VsX18437*1<72RSGOiW@2Ο8ffA?l'ysfD"7~ϧH8ZOD_*ywАF̀*; Q|uC׆4HhciW?4״aOmX5jԌi*mUlc >yazu_ҜNE%8]'^^L C߁ !Q6j-Ao%̩AW pWF # }W!oL'䝞ߺ Zl*v3C9^vPN-1+ԬeQ Mc`X>ziڏ=$ܐ%Ap9~uiS`?~ʤqhwגy@_ Ͷ[R>@KJqdxazN scƦZӖI6̪d$LS@ N¿ds)qtiKOmt^ N;gWe+F34w{Fu#s68U '= l;m}ȷdФ?TGڕ?~d[USű"=TR45Ɣ?"FpM`ߧ{QӚiWQ]#e%Ur%N;,[-p1vMg0eG/KܳK["+xӝfg7b}O4Iι\лv}L}ĉ㠶?-2n)[&g:8+qX "K,8e?j9F7csʷf+2)dh,IUIz3Zޢ0] K V9gzY:1ݱRO9/rPcˇ`VMd{PlyNVζ/^f]n6 |lkQ==#zAg WI]- ~&݂"}~ ^v|DUZ֢I&ħGnU'?1-X#.8+>s3c[ߓ c~ݸB S&Wʖv5ϞsYtR6kJS]qUT-;Nc(b̃exHƤ.TFbх/-qy ^:e,AHͷy2+X;l#}ܗ6gNn^ؚGn*"Yw[B!EjKhԘrn_ T|},aY=HkkO"DK3:֭ /*>5bSYYs4 8y,ZK玣K|ԶN/qņ#B̢xןwTtwyhKnyhC HunQS'&j3/PG|)ymϋlgu[?%xFqT" I t<.ҷwZj.jO^o1~;@BRC;q5kQ|ŒShh}cpzv*èKޯeԏKye9R i|Gq[:v,shlŚ +ɺ Ka oҺۻyڻ1]5ؑhS)=57jSO=Ko]세b-wk,-wJYyr1r6 qp dQ/6h226zun{AZj ip:l; a^J.ð{-55T(|6Aw"&` ;+fQ:>o em#*!2V7"@GFZuJ*Y,DZh ֧,ϘSzdgY~֟>aVUǠtQ!sd] ԼxZBF8i{j;ws Ǒ?Ɨp'P3G-Ez~z#r;#/w9{Ղ/J@ = տl9Ok=ml )s=R9]WY? hO3g}A8'CV 7oG(?Sh|0cQ!:{xX`0k vnQ|LCK()>-LMqߞpcGԲ/UKJ6H[hE5:z!m}=g{/@g?=r~_ ɭ_"Wx70|WZeYko>wqQqRC(+'K`Gj]@w*Rބoq{̰fT,܌-yvs{ 4Z9Љ|Cv ~ކ&ous!o nx2%{ϐH@zl~ȞSA݌nZ|.8\Ѵ~Nbn.g!sKHv(FXT/}"!f3w@J5pjoPN X "b^cjuFE=/B\ef#᠘8^oT3as)LWI!b)+Axsg}K#/y#ۼ-%l;U9J^B?]72{1;Ml1dE3*[kgH]&{g'bnFB 2rr8xN 5 Тif:[1*:3x_GP;/YzwܙkkOR1v•4C:|$yAUl%ӝ (w߇" w4nBDQ)Eh2QB.;dy^e={s~w:P|؝yO:9.]2X6aIʒSޡ}mSWX6lOGfwV{(>qKsfc+6R[0yן$lwV! nw~jNźw1zC'MgC~COzzcyϱ iv4{S#MSYUDwYq ^XYHp\xJ*^+6fG=#ߠtNz  \J >cdv_ @8D5̽@}7+1\2q5$TLfa[ Nr Q>p7٘@mǵ0K)yJg׍RZ=2c?lk!'"m]T(DEFBҍ^n8:Lqk;ܵ}Yp϶>1:{TB>?Md^d>>awٰͲXm-7{,,l8t w Zq11&y6x5er! P&W%SHHXB JlzG,}ĝyCqr11W70ȸcRj e']г?Z3DЍ:dWVCG0|fl"ꀹKWË;R"ߠ'׮@7pf>}7{eiBvX1iݑ46˖J/fao &8=~y^?gQtǙ {Ku-ID 9_ALg T#G6% Ȁml5ݔ2D׫\DqhW# ~率'yd,fDLFcn_Q>HQF? ikj 6U΋*j.P<C>{)Tɕޭ ;!rdK٬7 YJϔC'?եO(EvO8ތ0!:k(4;X$ܿ5F4lD=uؗ&G _\m?jHN_V^i)yPн,i66Ɠu8v$s쇝?Q{u!4}cN=zrXk{?n~b£m~^y}Ť f=c}/ֳ IxEv扏o+~I- 0R<:'2W`ӱ'gOަ%`,JL,? ^%sT>~e꞉D'o9Z2?ϰ4R$ h E#G׌@|aj-0+3=In>^Uy|JRw)p~氢3>rcW(s<jT&m9} z,E mDZV5NkVm3=;f}E^q[G@TQ|ڒ|< ^e,kDW5hu`oL:^A@Afj iUd́7Bv}w}M Z+ldj#^zϣupSSm:ۈ,*SRjtj!Zݓm ~@uZ_<_4l|y/7.f6y!mwB|(Z;qΐUU-3[gCC |xoS@a].MMoND ;_$(y6#dtf[HOO#11A/t$9E`z۝c8`Vn,KMㄫX˳XęՄ3~x::%ߘ"MG-tbak+H- WU4.Ӫ,PUuʷV'׀ ^[|=GCX"D5DGAd2,9Iʯb(J&O,dЪtɇTkYA\Lʟrk!zȁ?ߚ=;ISj$ɻ~$'Aqg^"+laVXLm=o+RMkQ?m /XY ՟DCkegi!R'냙 7D"6$£>ZX)ݢw>v`wWW[T`W~ W,[%P ||@GU)0I~4wεRHF ||ofKYc3+}V}.2uWڂ+IvȽgb/DdbAYh8W7p~ݩ㥷I0֣?Rkt:nU*E/ vwYԪwq&_  gg5%8 /y=RJ,LK,!~ g'O'}BK qnt c/kKaeZwE7_W+n}ɀ,]+n]pTͬpw$1 e@"dG-:4e%SegiѮ(ʕs>*8S/bCk7>cjCfڑy;|̱jd c*?#Z0NIk - /J:uS~~_a.*m#(zHkyv7ZN#D.,4_yuϢm]Grb Fﲚ@γ})xS{SnX ad .k4)h)AγhX26YU&K;T3[<<<`M2EDnuy5ټƥs~~D[",xDNew"/";Ct%_m5O.vuGX#:vyf/Rɴ2NdX?̣_tS9`̛;wug esQd[Aɸ ;?߽nYɹϲR9=&\ B, +h-0_׵#wXf#EB?/i~G^UE4]S%3f*pfDe>#(Z*QxWK1~6<*(/Kp m>» FUif>лف+wu~r·vY{Ki އq1yrdcA:unghP{PSwhjaCW+~yҳX&w"0|:4|@[Xq^s,qfL,z|J@eZ?{Hgs7PzI{9ؓa^2P9 KZ%j4"ď;wi]?B Ҳ5@>b okan+[uK:4揪<+$0i >O>*kLV5KuTL99ҳG5JE" JzlL׬ %6F*పzZ'Nh@(!uӢyz- GvDB)q=5P /Ƕ2v/ o'Ykj.OW/g̶ q0ٙN;PYuk,>@1u "' L٠.ʆ5<荷 1[QZiL-Y(؀ZsD*5*oY7 Y Cہrq gX(Ɛpv椅!~ZS{[š4̧/힗*݀{6nJisG@}\\ ~A87lV67`: Sl3xX/nq -z>4gDI.˔Q5u߁[Jw!;!>kR%{`<@$3~ l[ne+ˠNߍ\wv>y'Hě7k=a-V2ay\Kr9I;JTg&עy}Vl20DkT! 2<@wg&*=yo53^_YSA}ɭ._B];Rw!-.x&1oI~\\9bf9\TRq[U-!yhCURg%܏bv+S37F%CysusUȨ~ޅ]'e}.-]^ i5JوVzdU>y,7 i_3hݧa#̠H@yh%׻; IZ_뗧?ЌBhV;uXe[MF2q:KQ]u3gy zҁ!h[^ޭՅ!RP)dWd MF]A6pݩaq<&Xf#e;U ԓN-~~Ux1A]@w]|EY0V><;\ۅ#˞9|fac݊D6grgQ72KRYh{r|dŸ)&ipq;;+O `)qo&I٤eLF@*9oI_ ֪$H_H%C즟9~~WNlX IptaU$A56^ N bj)`_%<=\@o=DXq"Bi̺aX/°OKgG@>Oq•e,ځSÎ4x*]ZυYauVb0qp_v=i=/N\GK[،&('ª!? 6w9>gUW~ǝݍm7cc &Tw88B|8Vv |xx>v!ogz;>r@ .]u緾áV}.#~ ȑ78|'8_2^,8IvxY+Șj鼉Kg< G5pڪ8B5_Qi.r跉N[˧/Go`ίWqZ:2[3Ƣ= /ywռ5&T^dshh(QYhO€.W5ӠGU`> 6/Nf8r]{88 8$?~hw, 6S׷)6ϯ?Q68`w;}b6g5$h0>wY<%S=c((.r{ (д״{i{ C8<:U0^I3,T2L6Hpkf0U Պ$D@ȍE:ײ VUY XGtǛ;S4i`%J !qA5{NgUvk`2 2˙4 c R!ӃE.9hmU:|9Ө6|s yJ5 :iYvր,MvIWA)]K2Xz/DHlDX;y7t:1΃J@Q,xP^@Gv՞)0nJd,DSI[A.H|"s:^T,ie^ {b5濐d 3_PqJZX|CjG@~RxJ':Z!tf0/XȬ7ty E LZ`TK'%+Xju4g7Dh(LzצE(N=hmr'0ntYƋHԂZIB'*-)тaz̮;ͲGGcga_(r~{pX_Ŝ"#f-$8p]jTN>i+dK˥ڐBZз;gn7PJ Crl̚aD_˷PjWB΄ǓG Ay C0Zm hę^C>5>s"x k{1~\XX!3 2Hd{2b9ے[^`ܬAf =$*?]qqR|{[|VK;U@WC IMˎd旿|PꝚ0 mD2M >ya{go>=+ҦИͫvd +|8y*RIB#LoVN>!-.qU*{oʾ+y^:>,W1R[Dt)=o_qq/$p 8R`3`+ Jb RKY9V$A*/7܍g~RQ]yx  Ve,\c*]%@wcFL$"/”>9Yì?OU`߳$BS*u0<m11`A-" ;=[uፅ< ,Ēq2s2,/nR4@c1 i5]I¾57a/)q0 ˻sh LqW- <,fD{\CO{ʛ4~%&7Po8*R- ;^ARA)[/˜NςSqg{t 1JрkV%CJdPt~G X1iU<H*mvomPbS&b8ٖpί5GzCu_gi*\ȱ=O&ڻ޻_7*FĦ LCm4< v,WLAvim@H$M&'62!'Ǘ?h G|׵ +MID+rE/%A _T} 8W>i U&/5Un- ߚFP[{L2nD0aTꙁ]6 ̓Ae,98%ε^W}Yr<;eI*'>XqU7!OA}lj*oc7 mA/|w.XCӾhּd~L%P/A(ؒvY"ug>Cm<ϑ 4mBy|A߲] yAɍ!.hd(} X?lw Nr3qK*Y(eϩz>_]i5{;~ŠI9haHv1 #hNA,-?gwŁezK_A1In+M&(YAP2$1"tqpWJtŔó3.v:j:^/~2_ٺ8ۭhףq7j;x ~|v; r~sAKТr/"\SP;'Cݎmw)`LT91;_yfD?Ѫa^;lɛ?ˋ00:g0. 3sw~qNbu$puK6"`_o6:;4wy(Eq<k,YN%H(_:|dadJDU><˧ՄG?,,AQ3CE腏p~w-Dk'K 0}骂 2}֍4WY0nESiK2Z:*!mw@W2 {|W ]>DŽإ)p{ϧ]oӊ:Oi? \Ÿ[cv>LARoHPZMB5zQa ԲUYȏ YM/3jƞ^{6nӂ4شhi#Y3:ޭNUHcܒ愭*7eʙ(qYVǾ&KYG L`Qj.W{/oOge qC[8~9vaƫ9<'}z BNsqc$xSi w(e0ʴݺ;nݡ"cG~%]aA48<Er!MT c =9i .98VEshV-)&M+^ّAa;(ΟU2PX$maW9T}6GฝHYt?6}ϱpX;@9HjV`i˿uj_w`K%Ct ]V B [D*O0FhvB{:ȨUod :~BVc3ߞ/lP^/TvoACz.ډzYw5#Tm|~߃{޷&Ozfa篑 u NQoh"z9T$%i۹VЋ_Z}j$4nbx ey(\[əmq4>{wgPh+A.yt=" ϐr^ڣ60()kz>t"U5՚泏\t@n-- c~ݿ.-~JGg@ heDOXVft~Eei PKa Hg?6t%uhYj7T23И'Oiv;h^? r 1x2'JP /v_;MOǽ~D/CՎYd2Lؓ~U68ݘ#P|!isl)4%+!Pth<)٫Ф$l,Nf[y2I:"\q1Zje+kF h;"P&ox;ŭߴv4YT_w;ڌBw B؃ Ө7d$w{9xv;Wү=Ù|ͭ+QS"Q_b /iDėıv,}eq7EEMmnwiڣB` "Ekx!Dz%5|; F}f߸ntܤ@TU%` M|tuKhB-Hh"*tFϗ=0ˏ8Й"Be+]^)4o,&2?l,Z9ii??-@gceKsׇp![—/ˉgr/N:.B]lOݣ&VY-]n;O@t%rcJXy_"E.BGUBd+TemX"fP+1 ֵUր6 $=R l*Ћ$+Q@OPU͐-՝}Ǹͨ.%Cw*vQ_V4x-Lvp 4{d\[vzMo){ٗy2.+\kJ/\ZRN-expH"pOYb\,YO}=X7]A@i3G}iuO3.L#AIyXB7Ӌmj#L~j$<㻗iH4J ;uŃֺۈs2`~nq2߻T˹Z)Pdmucd;CqheͶx1 9KPPuw{p1\#o^"@HQLbֆ"#UX1{*.NjN^Vm[y3_,B5ߩIк’_01gslxٵ IM( 9zap`=Ak~of َN0Ԃ}&^$Tos}m~-$}7 o鴥M O@}T!_Ӄy={Vxժ"=4;eGTR:H2%hq"lcKᒀ]5Jh@ۣ`F~ttߋ(PQO8oY0wFI>F{{<@Duð.A ?=ݿF PbYjO,F|{68 KS\Ivit:"Y^vS{pôBN?6O኱#/or:iy= Z12?q@R+r~o_>p.GOb b*W]?Jh)k굣܅$rh _z`-0kIƗ! XH3 ו%wy}[q_mF8NLXK5"2eZ`Fqfٿ{)0Gx2 Bl=@$  lI +uRF2}+a2-#e?$08&~f(gNFeYA0e2USTwL*;+G2}P@aWا PֹB X\Hy,{*(_9CnmTpW[G.i*NkSB#qlIk8LyU 98o7YVg3u1L6>ѣ߽ĩPE8If>g}v/5Zֳ䖀] vv!Q,'b9V 'K [ +PDdY)d(_KXvT]N~%52dbjS!R^d QTd~B^YƲ/6`Jh\/] w9 êaJ ;/ՒV@[?@q feX#,8{+lAKK=Xu%OáX(3 Kŀ0w<DDBD2F)tPDVwH({{\\z=9z>yk)X4  q p ֬b¶ 1$J}aga~L5pmvun >#Dw۪nD_d٩kwE™ZduokU~p;هf<>FжRp#u%^gC tV8jAնp dlI>So^EkGi"zZ%a9MFtegQDE>H'U<GRhR±EnpZ󆵶 ֑\mpEZT.L>^Co .d$U.ziZdۆeB趲nj66mFJ4Zԉ  ?dZUTB0m@k}lNm!`' QuU#:fqo8br u;;Bv#sBβݴϡwnɨU0*'%OKO TLx/#nEEu H[B]KAURaRyt huI-yGSL@Ե|3-WӒ_’OKW"h+*tuBZb_<`F0*{܊ʬA{?M)Y5@v31t#Ns%ХuUy<+z#$Sďш]&kH<_vLv4q"ȹ<jK GNRf3k?XW"E\bA6 'ԍk(PnZPZۑRO@;mM j_ 6BJ{M`$^I yiZ0ﻡ7$-:41zn #~31o>7<O 9LUN(d<~>b^b&AfЃ0iZ  JԒ)W& 4x5]ɍ:j.((ViPO&ѫ Q=x8dG{({%Y,ydw Ieh"G=u_07tim{{̋AFZ+[ K F S;+мG'jӉ;xOf)]\ ^Kx`*Q+w]$Z$<^^6vB[<_J~ئiL-9F梚 ػ|IFrr6:dw`oO:t)Q렺iknqkc(*vˆpixh?+s6i5dn>BtdH-CFd~W0#BTή$+o`3D!Q}Ȍ>ӽ,9u [F]uwAf M}>?YbuUd6&Gux.L,u9W hNڀŶ ZD8hLӟXT6po8L},I{m*&~ xKK[m6 ՜yab,7^}2y[`е;ŢLy PB7 Bi 8ҟfS+pH2>EX?, YwlLR`aA^'r^/2Db }4ЏSb$F̼z_"FHrκ{j8johm|$ѓM3r.ӮGB%43zJ-eqPrA.gk-mxm^?mٲgF߹3Dr`Ч@ re_Ǡr^ëNh?kECTdLYzH)NfvZFedozm]>_ }~azecyssgQWiY2bNΣf[󨧌<&Ra>Fu*_ K!0`hTtLlAӐygnN,K'uΥ]s#3 `36}+} YQZU1;__<,L:&[|2)01W;8~H<$|)E;;mL8p, _) i"xLl6d bh.V'UZ^T_ &K9hw mV @h~v/<-v:譤"Ħǘ!/~~K˜d\QN&~f2'L ͔X1_U! mۗK:*MKFiϜ ̧(7]Hl{1b%,HǪs6W.2iP _")r H?e S?#+y0wDN끆uhc@/W7rMXX$9mnwM' I,-(bK/e^gp'@054Ө-_ {I[k~8hz-~-C۫-%8⢡Y+( Aw@xik2|Xw||ZdV"qpW1FۻgYa1ҨJu.Yi(O 4xX>~E2âP6h%ϵxT>T]ZDg{ss8wxn YQkbP[8Ii$!qYtHG$q6zľB\#OJcB'k)à3,3^N\~΄H@06<٫FgX8A64 U:gԑ%ɀN@_/w5ߴJO/"/_NRl};E˓׆(G$ݫTۉNddǔ7YXFIKřQh<4cá>(2/OJAVa}2s>dXu>J<Rodض$ԕFIof%QȌ)xA^#ȾNܭ~oxpѯY\"~ȇB쨻?&@IrZ&x$˟#.DD5p7%ND8ksyTT+_Ϭa&8}uUpNj1!i~ȄF˂SeqhÊ,S]}W˴ nkm` <45̣ ХZ&2 b쉗6vFʳ^o0 <=S@{OHWy՟5}e2i#$Tw*hHK3%SS{p Or~(2H/$i,Ф12 _әd2qJ-j£}9@4+4`S7+&z~,GϖzJ=YUQ0LA)p)&ctQ1bsp1IH!,Kq$¨ {/(΃OC'~)8a\J.&2Wl@:AWUQ U>;jpwi"d1"~fA_"3:^=.RRu*WIh^x50A#N;يmng휠,i _"nvK_!#;hb"w%¦x^%Pd~ʕ0~.hFkVm\qI Ϧ+ϕ=GI2pC${>?17DO]VMJ%+{4qm|y]=:nZ?/.IפNkW*)}Izd- Suv\) ~+ OFݐO%뵎J^GY4\Chsf P=xR|snpЇU<=x1-M/bO,f$c+틧xC=!֗dȘSM$9D>d i}$Cڂ&PCMJ6A^ S zm,pUq[x{Jt]ޖoif N?%@~)i~ypo\!O<_/ۂ{k0Al2od/}\2467-a[O:0R[Qk xjzr:P4,vJҌc)ɮs0z(f/M/ܤHUb}:p|k[#GXf4^CpL827Eס!'|Dr9$/︶d'R^hk2d]N}ه~qJn Ƙ!$LoM/HsAZ6oEo\$wNYoܝBLqJYQbv~p x@*RB(^6yt%ruT&۬s~UtZx3Vtj " E, #ӠR;TZWm6WA [(+U}{;u+n{[Nkψ~翐oe>~.ZkYK//2_yß`2`@ ׾σV\No<) o2>Go^*Awy?Ada [^CϬRtOCl] 1N 켰ׂvO0v`ƴ gFL]I/ }J-(5[}M0p<:>vI|UChR:*ثQ\~^Z== ڐ; "B*)وA:N-_К$32 "CiOjQȸۉ 9j yA{3xxlk)hAq7褌A2GQG38Y!1QJU+A<-h~* <>5GF9jhSx;ŕ߬R!ϋ_8d}7y|Ol$O2g|w)q`G <^ v@͵9.i3c`dXKz)<қF>=ݐaH[{wa} Bϝg3;Cxn)Ixol  w8&Ҡ$-H(H*9BK?$2BFVdde-]vI$(#;׾?<|9 M|Ĵ6GpIW:_ĺq S0xВyץA32snΥy6_+wYtSK,|L9ѡĽa`%k#ńH`̣A9'@[d*SD0]yĩEr1XTw#OLSgyK/φv:}_vNE/h''BПtnWwS F~t8Tg{mfx(xm HI9vO-)Q2 fNqD7V&ӓÀUR^Gew`j3 'zG&XH'qw?RV܀Ynmc#T37g}o3کd|O, 7dHÏIosw krs$2hY?fy)psNt/W52|Մ?ݚnYT7~:0n5͛gCܜEtq,/~~+Dx/g+=vJ$F;ZXOwO=`SW0gl]y'Xzfrav9,Ơ\0\5LGK}^>Ʉ_3cJE.mw/g1=70U;=H< ~;#]\;Ѕ^9~bV+wf\QlmkTw3{k+Eڭ薪'%^{ZyƃoakKWs"1uL>lN;_@󱗭"W_Db֮Je}GHq 5$VPKz\[@B<߿}6j"VR此>7}Sm5 7mp%K4S>.u (}aco ZT޿7ci1w(D^ ]LW/٧Ba115OKtw!cY,tvK8(}^Qgt} | Wfڲ^(."M`>'yos֕g ]E@!8ej$tc dAmbtR+*پ.2Cs|.v*ͧPC>UG,;b[H:%9r%c,?'uwpʐ$mqWfn1gҴf>+mχ-RsEWKѽFƖhI;w 8FJ5"}rW~]ڒVh>v çn &;R+ɠUqpnx' YY+H禘 w(r^G5? \`эO0@|]Q9NSy0[+~FKNA})>*^##SBڏ o L0*&휚F Qrt6ƲRp8O2YGq }A[\F0\)5[e(%}*I'ߏZPDnS1#Nx+v84K-O0NYj2= Nc+DӉOH@^Q-{@V-AĶ<5z7qǞ![Hoϳ~!;&Π06g0K!L ʅ: Awmh{ty WuLʩф;.+ P H`TeO2S-1(Ş#O㊞K o?f;7] [G핟)N KC*ڬT@vtUP3zޯMk װ@NJʂxʴ?:e1p!:;}Xۤk6aI1bAY?[OWĚs m4x7]ٶlNSl|¼@Qm0}( ԎDqKmA߂}v4n\Y0 ڿM~#yDp O?z3fB}8%eA3lO=*gX4Z{_/4 ̳s&`y'} 3bIl ^:ڊmlp8_d,>`qP\Ψ W;Vcbo TWM9} {a4kو2"CA(t|eDuM 6oʆ>l(=쎍 Fm݈0ՃPͲ>FT'킠H N6xzl[WcCZZhpxZU ƅz"\r[,o|xI.NzL{ LnK!iWR&u p#3ekaHtΫTP19burr/3'udA! $8~k"QnuMrVl]䔋U$%iD!aWaL2g>3Bi}?&"w<өy{ $c&jd{T6ّǻo8:A{_ۥ臇yk}p!lEKxc˚IpHr=ΉAˮd}YfTp_iv#Q4fdM6U4]|̃ bk}$4?i/ήYjEiwyhO7-\K;ָBpxo"?鮩[Wj {2z_Ri:2O1ҍDȰ6+\/~B򫮊CZ,F8jLSlVH5\e- wA ~mn ChC}~8q1|TqJ VtN :sJZ GWڇjPBKn$W ݀]dF\ͦ+qq_+Z}??(e.qp!%$T?8/0!#_&>(f꛲#(%'?Fi2 nY;x1|7m49 4WLCH˴X=M`$-3NmNQ&}Wf`c(;ɚ6:r}䱦#A+$8婶I BVFTLDgyTLF7PpqA99)ʏ{!P3 `+nh~(Kۖ#E~XJWj^nl?4c*gR`sqlЅ>lj_oci})tB. yjPsпbS<:d恮9?3 Ƙn q7 ^خ⾄d?Pdv-Ou:d$#'됢 zښOS*֋SاV\=BoSsN,w{l/8XNF.\ީ!cusr/}*_w  lg#E3n`-c*X5S$2o}sǶN/EfiB{.0 ,4acnF9ZʀµoCמ- c TݎHC܆0z9Z}ÑϨoNUL=\c.[}yݽ;@dW5yj>hA8#r4W ij?-*ڧ k?f_ᎼG2@ P9U[`)Mt t/ &K:ޟHjWݬ v(mPJ!ayAB#96fו5ʜbkn,<׉a"$*7 5k-4?jK)5cE<΅>#)C,P,Q OtY>MA(V̱#s҇Vgy{aH佅^\yawe=[scw_*Z};kbF׿xÀmbb~&e<Ks%.?>򲌬"`0HO͔1p |;/K$xxp:sVɯϙs/)TX9`B8ɔ2RQ/Mlhh#e|C11k(r L6d`zd,.&giPqeEӅ~Xk8 ǮxkOIpMbG't꾖$/hbFC:A}Auojz:$42޲vPZlQ~]ys/g$do鮣n$@:7ηDslt6{=({/ǢIO&oFf3pU [jJk]؜YU\,%sψF.傕xV}} ߨDs'>ɱX(aH @YHrnq+N1Kk_ݓ08]'e@٘/m1?n9[هУl׉*+Cᶽ 4։0PmXLlKr;OltxxFfmru64A^ͲxM;3ߡsCCez,o "秤4¿Xh&Y)B!,?Lٸ5L+!19۪ɹb2v~]6*Zڼ+rI*!|%% KW;w|S=l {)ʂNsC54ܿEXaAnQ62:|ʲ!W}IFg.O z$Szis'YhWvxG_9K9 )9$seG^]TlL>ׇ3W-S$0#m Gj4mWq,?&-H`ٚ^v5#5D~m"~`NomJu%E?$:#x,Qs@˜o_rXc`xK")5W̘EXAm.rP إNqNaS[Dô-C+1ϾwEKT7gi;69-M[)쁅?^Ă]sf <BS>o+ tgONp?H4n]P jg ZѮCꜜ"7Jb=3pHġnNz`qR`W!3҃AcFu=^Hyح_qԯǾ-ɡᖵs5 ^*QqhS' u!RyEu=+P[t Y.siyqP70Lwf IL!V.ϭ/C2УSs ':" ǝSY/|:\mÐ52UwX.Wm:iIXf;[NAO)߮)2 _Mq%>Mlo4T~g1g}ena15%Sx|DExxvTlrыG?/eaB펯#-TaCHcPo.W4E䱠~I>4Z߻?oGOǰNv n\Yp1rn;paJfyǰ`8b^[瞼gz |2s6ѡyy3U0 N{{/~+s3 UC( ]_ӏqNptvޯeCx]٧68Z#䰪wL?hJߛ[ ޷k~E,hŕwjJ-7oTUkol_[Uy06QfFYKM=ݭ\MsUdPkҋwDiCg<nK*)E%2* iP;4R*"d(HFȨrȖ9سxޟ߻\{p.4sS;T3PF!5iS-#cO[?Q=8w1Llqp֙9{y!!Ӽ`zk ќt1Y v#Φ?0۱D֭;oi% >Ǔncn!h55z^FntUCǃM`RpP%n.wx(L$#Q/Kl.wJ~L UH{||Qy{$A7,](3O! kdz)Z9@ʴ{b$E6x3~\r"2 *읠{K%yZcrmmWI ueЉo{y B2Sc7Q8M11z/x8GB oi(u@nϭc\q'/րZuob؞.+e%N_^].Bzժ}zUyrq "?4!yU`=yD CŇP:y^S ܫ02ֱnBS{Mw[C-=ma辂rgm xx% 7d())HʩL"Hv1$Yq}mv [^xzm+LN9w$G̟`!-;sF4l6 y+ӯapY%(Enz0 6v=#,6$$!/[$]'`4(]ifbXs$xXHkrkhQ]-m%&nbfҖVy{R(5ҋVH)WT!4bp} ݶovϳx:ڸ >ݩ EU1zB zdFkؑ#G)}VA>Ԯڣ7G4VΘ<1z"M8TAK ׫a+=x{eεG< >mع`>|7/ӏw̕"xw ?篖 ;t]'\0Ppm ?VĀ0[k>rV> zfqsarI$n)]i {(N Ȟik),7&3h|w!w]mhHd`"htύsZw]0(yXоvioSC; ^IpxjnE"kiZ;5s/ھU΀نH=>0oAu>S&6t b@ gQN(6H7ӠyO0. oZHǙ$S #(HYzgTo,h[ 7`|X/ Ϲ.2Tǭ77rZwCHK-˂R!{]]8fՂY]3>D5i,wYmn)$\l?Rv20|T΄GQ&vRq2 i=W#0=y ^g}o74Y !t śffK4S\V?zYb4Lvi!yog)6<ړ+mE%=d ΑWG> o퉸= 76c7QseGݑI{9eko+i:ZW wp%0ِ|R_Xr`Yu)磺 Cu "990VA= Or#+h5x)9*Y2Hl]N9@dZYڒՔW*Ol6ȐE60N'+HQK6?,Qʙ{Č&(".7NɄ̎վoF*Oș/נ*$~eKb)GN>?2Cwˬ:B #bbj3;N?[KbNy׃:`Kump/GۯTdk &Wiܗ瓑Oצh:.*C'KOjRywģ.w NV*ߠO[{2wQSBi+I^Ofʍ>,SuUW7U?wCtzn`nD4<ڃ`^V,sjώ{u˅}X\}$Wå ƚڮgJK5.taOtmW'yՆEk6\׳ jNYUrk&3K(X%Ӻ!I:Oo0?}vXh0mz<=9VIG\l -y;vF <ܞEGyS:]ɥW׾ƀ_4c@{-nN0"2FcunκEoKOuvRPkF\ v w T&ĕ=͕*=nt{4Œ~(5_셤Haŗ 6hSlAnj'j&6!{mOGm#ߕDMLR"÷% 8tsQ}~V7A?nHq86% rO?%E%G&~gLcIRfha}J?Oc6HBǗO MCE*w95hHD~g8>aWr[m 0P\g!#\fEX]$璚Dyr}A\6Y_]4e34"-u2;r+Sɮ& v0*?jiZF {. 㽒`Ud] =WT{M>YQ*"zW|nK|.ZI^}^'UW)bkb#"TP6,qQD"=q G^u(]o?^L(uae.sOz'uŮKU{/Gw-eCxD=ҏǧE%C sD:t| =؏lFGyF8x+Q7hю:{ݼQn~?kim>Kn8oډr/GZ&e kZ7)-ϕɎB9SB{,|k]m rNUZ֝xDu|I+{35V-0c27ЌE|[W6ƫ HGZʢr"4{ a$0970$(LFv!֍HqDMS7)m _=E`5+G^io(14pwb֏ Ufg: 9g$S>Wyʺ>F\h`N >TKjQ.llU yR֊Mp%I]h'wQ8ީxԳm^uӱo}u7~RjQ>G dW_%c{V|+#>t |Y+s ^%KV6Ⱥ/2LzGֳ?c&7uD{O<'3 T0-"h**qWO] %<$ᄬѵɟ@=]˞E h(̯ӌˆY{?f"SZ4>+E#HHD>wTj~7xJn~rjnct&Y_v49.A!IىIEUnXB:[vwg2( |l5.atW\֍ _r= O˱ щA[]/eW,\F]m.xKں~܁+J]wIZ#>xc!>y46&> +%:@P.vNBԎǶ,_zFWz+C- W!yRHZ/ #-U.""HBSt@'L@e<w`O E]c`vFvjSuk+>]@J=]u1677 Y[Yº$Ӆl%)Jy;rJsO.߸8kv$K7Vr#(y@1 I8Qޝ!k'⦠㗳}4z[TaB633ڪl1+ogڧ(;>Z.X?$40r55l8sq:r\=;p(Nk)(/.{8kSX+f׹Q» z(6F|ZA(ڧو4-^_׌8*]c<ù8i=\<33"bj>})-k xf~{ .߷gJ07 MT:ӦbP5)GEgn0%ߨP`vxpCrBrϰ\utn'1^n뻷` 浍 LBh;VNU9o[Yx@"L>iD_ڿr댿pTr4[\G׻g:6)$9߳fiT VQIN 'OѠ|AL m[y#k ċs ?a@DqB:#ehysO(7QV2t}B"N:/<[S&~u p-{ut\kNC+yV.^n9-ՁUW K6M{ s,>^e i;ZqG5@cry n qa*}rṚ>ȝ}q_K>jv;{9LU#f\Zg:ImFl|s|8Kqi3R늰UO%+w,`_ɕッ< OA/6`XxeHk#N D.=،\_BnWZOUh;'l*ՙpxלBBZPQڪ*#XߨΪ:-ڳ:wU4^nZ{f8- w_@_sI+=Q Jr=6 :'++gH: \"(sg#|}Qɋc^*W&o?4߅SsWkV"oYT򀰼fL>}釃E >`D0rHZ--ۙ8RWnwX2|mm{m,aep3 li.Ń{<:ƙ"r2k oTvcZ?4{<A),3B?!{:'2..' rXx^۫.#]+u9qZقI~6Vqzr45A!*s)˼-c{@nbONOԫz>ZKnCv1 < "\3X߷k_>.}wΝOֹI{xw*sN@ZĬ ڊDeO$46hHL%7%LpwUM&2$^cLbRjp?e#T5DŽ[iH5>!29 blf9ΩJjҩn~|îߩ̳(_ ]:˽2ta<' ubWFyv<ՌIg1y3o}\jԭ˞o_uv\h^S j叻끌MtJ('n%ę5WM@l$v* w4oU$++%UihPHJFBe){({6(B _{7/Bɯ~z}s>Y1E!-MMI =,ʯRjOZ+Ri}MMZŽ|#U6~;s#N+͢ oB7/fYjfJ| M;HZk/I\yV>%܋8݇}P x܍_fyrq1d2 Ua?|D*A,gاۘk.gAہFq^` ze2)?%c2Јtq6.*T}o+JzMXhYW[A.3ulԅ< 2تzcb0%\m0 j6jxXތWZՆ*ڞڂ7RVmn&^6׮"U(_5gss Ӿ0l8g ^ _ bDUwH^oCG,Ga?ocu\]+hJLkieU7Bxڵ$E16O#JhN[}q)Scلΐ QeHќg+X԰#.0`s=>17q0z Jq)=dwM"C$HaHx6g/nkB=1s3-@~[vaPS6O򽳅8qmcƫ2Qp?,ho`XzGh+oYnAj0kli 竳Q2 /y]>o*E'L؇j o5eӭO.Q ACgjE =jdМ;5R﷊m#ɺJJI3׭/Wn\PR&OACwYıwf K}l#{)PH}!X_t_39A\i`;zфG#ѸWk̚; 1Ҿ1>fܶ sO75#zL[ThIֱzr3ʂbqDtK{XzZ!5Yi&q{7_l[97vᾔXBOJ7r-,G!L6fu #HO/w`ԝOM\i4 kڧfCdy[x5+inj:.*.@YfZiEJXă%a=}K8p%m+,L=Wv P1iL3'2^H n| MC5Cn!aoɰLGV$Ξ 1256;<]0 tz1UǍI`x$DO`$x$4 W3P*n$F}g`~H K&4ꏑ*h3<[t1@ډ܎,郹N-F[Kԥ)8Z~1rҳ0ѯ-W.Z lPYh;|NUDM1v.K_;} mpU-N%͈Rxn馘څުp}U :ToeUCfq;?hЁmrq?hv-On#8 ?T"Dz9L.w҅='\;ު+3w kF)eW+Ң "Sb*hYFiI& F?^ ĶCK} |oCZ>0?l9xF_HLgw |=..`nG .7b&&ND`23[9'[txiuBFZ]CDض :. کCrɢ$2-_1ץ2H,5Z>G?ߟGєuha*ثt<M] $>kImnKw,"N7BkJ^>1Yy’X/58ǁnyӰhա+|KD͜ʷ'F6sO*ӹA9rMn>d _^3{uC\to"p갴"Hhu{aau]v's#p*rS/)z!XNLƷ͊}`ݾɄ]6'%4hQp-m-IcP5T6qt?Fjc1G=/<~̒#a%tz{?-Ajdx~`]=EIySTYW| u+z*w,io;E(LCê_Y%:Y\;ud \~N! 8Oj \38[gaw;_D|c#6YvN]tEDk&1AU֛CLŎݜ֌E{1>7?B^bW8TAoOAd "ߺ=ZN5qi箭?0=ŋU4 D0CuKT,Ě1l<%D,cMf(bmOƳ_BErTt9};zvf`o;U.:g9O*]OLfW[ 6M%~1Y[cK)HK7kA~q6O)zJOYkXy9.Oi%nZ9rުR56KMIžWQ@gSkV{2>նP[v-0nϬ ck>sc6k# /W7WfKB:3.~ԁ?.L0E3*e/}h:A^1zx'g>R; }Z~eZaE-6S߿=QԽ6ׯ4%B Oh6*/Bh:"K\,B"OxùЮxɫQ!>4SӳMk^^Xi Z#&wfz|ɫߵtN{˓'nbNs@b}H#ZoJlɠNm䐒1M5갈F䎸9œ}ufy)~T'Qr1PG?$w8Gr_+5P߾Lh?¡MHpX& g-Z։ڼȹz><{ߕ.[vZm)aH 4_.<[N2ۂ5lc(ր(QJTYǡv&TV8{d+~qN%-!xhNFn_Mf)7"%S? VN=7Oo8v1<~8sUJ \./3'6}ngyH_>)$_Ψ<Kꃽ ),x }g':]djo[Ғ՜6y[&3pIЙ"V?3ƈ:ш)S7kaiWgz(koc&>qRW#N=JVjC=AA0O+6"NfZ2Wݵm99BДq-u1c6øLDMk?ܵmCbѽ&0 ɳ u JY0x 2G>Ij[),XĈXpP4,t5zc,.g=zЩS}(4wRS/As

sv7ksw1DRU<^bC nPn !rSiK3h(#N>wtF.H^vbFIP(_ R7Ȫ6`ng@hĢޏ0س]0 `XLoÉ5c{i{]3k7bmL]P7ϜQ %ZNZ\-vuK wMF_/Տne>$ Ni7`G\^ IAkzzBucN x: J&4^C'uZ3 ~+|saF,^c$l+9.[x9=ʅϨ"xx{m_CH^ޤ]U Fy}iXTà;^fxRm!A֩귍CgB'= qE`v2K>i'=APoGZw(QU?[?Xb5[Ia&MR-0/=ۧ ޒ;殮b[d4 ㊀]lW^~ȟ N}0 4QAwOd͚3Px<1Bokl.TrS."cs#glY}li<,o^n nOx&ҐITPY>+SQtV< \w͡ncpz?J ] Y@S#eFv$Q1ppI-wvAgp| /׸ݏ! nПW Gg/;} CoSt.R@ea [_'x9H'QӸ&מAi^H0՜OW&~-ѡC*m2Fsg1F}׷)h7mYGbPh3Վ#ы@nRi#s?vyh,BkvʏĤ]#,hݍ~;y o̔On-t%+L #"lr^3q5w͗5JDݺFwLuS~gޛ:W9ٳKC$EPnZh1@o: /U= 4p=#كԺ}jyGz5K(]7voĮfxubm:τ:ҾCjOfYx"\I&uJXu] ~%(y1)6*~opnU1*qtu9[b4Y<)+{D 5eقD@os1h-CA$,#oOY_˒"[ PcR3v#ǂ˦\}e2S?c 7g#Cvk8䵩:- P:xٵ!4N?m ︯_H1飳D3M~|39YEp%MSeD_aw{lp^։b8wwW /M6ۋ ds>Fnk1GΌ~9{sALeq laZݖ {qYVXC?T'u u!I ꅶ9 KG԰L ZOuh+\ŝ?Nހ#^uO̅@#ΰv$“ThWl!XOi ui\o5WjՎ5<ⲉYI{7:µq:Ntjx H ?T6I,R)9'f2[͑8x}=w<ǕPIF)IFPNBd|-$eEȬHhPFvx=+*??z}T:Z'u;;ս6ZK{__8>o JAOz), {C*+Mܩv%j^]/5\]Lj-nU+!Uguvb5YϮ x4n r͟VͰMX ְ}Q*qe=Bcx2s-PU=2mG=?ʰtTrh*Gww;ʰK;zxΖk !TF͋Q@DHJdZa [8xĐ;:mmB(KhE(q{~npu@X<%g4ޅ3u;zp̉1c!gL4IaeĕZx]#,:8}JAsem̷9fsz8U\!kJj)|ֺ="";u]ڄ1B &Ph2fvy{vj)"GѿwJkCͅ4)u=2vRalz7ՇOcŞ;]K)Fƣ|$9e:>TP@}b|K\O+9*Jc3l & 0Bl='EM_)27j}1PwP Q ]uyt)> x%I"{+/keE k_@dE|n?ri" \{ x1~<.|) 2M!+gW@4VxWܛ69O$,5J ZJq)rZ4/pXzo k2/b[RsOK/uu'-MqiK$)#d' t<,n~O+IG Oშ|aؓW|dq6@}SxI3})i|n45zϺqCcè\b}wiح&\V/u 0P=?eOzW:b;m Ir.kk]=fhP( 1 پF4^/ǹ5`jXiU =.,'޿-u\!=V7%{wL&V{1Y%hX>]8S1VFw5ar:H82IqPëDJ5_0n+yȍ7$,1=Z~2yh٠{}L~X-os%u$<gxO!UoGnQgpm3<5-!Аq!t{} Iy} UoV='E<Ն۲\("4PKq fjV%v OX?pėuh]T> EYJE؅֗)=DXL\ՄZt_7_=&oItweV|t6 /IBSA.!R_:DrR˸rP"4{l+[)qN FJҺ~H[? ώj۶2y (&AmJhK6Btdkmy&Ø*^Wًロ=A%Ci4I=٭ 2N,g* Ivij !GmV&m2pzces( gP5=#z>t{FwWx^z7@~IFX 7^|HBLH0Aa<}~jyceܫbຏf n%w .U,r#m-%9{6)so[xW4:~Xle)(d&yQ| 8d !e{u1JsN O^^_xV^D"W"GqP20{J>w{.D E17q듔|QLN'⊆ԋ'U(sr=VT;~30şA׿A)èBŽ,ٞDa1R!mF@18I_8@||XZ;'U*T5ʁIxD3~1a]k«n5TVUN}ˎ=YC^`m`tn|î^k=BE—g8ϔA/=cD'2w=D*}]ƥNusLGLl͠aje)Pvj}Tޤ҅ͲHxJYHQk2*xghcDu*]~JŁ`x-/_ tc)\F khYO{9o|>t;2owZv#/媛D;.=,p6+3D+$Ǐ-B[`Tx#]jχ3f}yvJټ7W}c< :]ȿʼjR0$V a-'}U30|I< A\F~DAE7z!CNR'І':27y\r5E$/:n1;aA q/@P/6ϟ9݅Mwm޺1Υ><[~tFpgSDl'"Dvn6q7CM =_v8cCI-3LD^qaVsL`F%D/*fc*$M8sPW婂 b_m"]Jl P1N_VwzpbvqN9 FWj$|%<- PT<-&HiNDЃ< ז#3"w֗/䠀da xbs0P ug0`P' >-4ϸn'-nX%>HbO 麫}I,Y;CKG hc_K^.uD8]+͋ai:3e'ƛ_ z};wBu?„^XϹyF$a5ͬIוğiF=^XtkV0!OkƔ*}v7dԠ/њD4ao #Ŧiݷ-1n?g5aLTv-yg^ 0X/;vJw|l*SȔ]:T=ȨI8oh6Zx8O6C~3bxoj(;@s(flos'1y_jg zIM0>ƑgCAImyjmC{P;}#.{" F6k8$ق@j5Rqהٞ͌Rt=q-WcP!n6_6MDI˔T0.q }JNeaF8,$ =mJzD-YWA\>z8m@ Zw\S/i<ת6uoZAQ$ǻvq`,P($YźJkPޡ] Ӎy}Z#\:Plf:~.(?&Q EfE%PzEkO,{1a|A^9EqlO#AY:xhD(yVVG}Ch mu˚o}#ɥXw9(>ɐe1g9.0T1D,ec?u)TLENpL,vGKQɼw zjn[T'[{}nDQ;@nvμXO1pVNW" .; '%tJXDW>Xӏ(čp9a>5b撳NxI2ZZl"a׏wF1Gd4) d&)j=[l82nli]h -j9xg(Ӝ0"N?ęm>f+U8t KfU/aXEcV{=bix(cIƽsyN7mY "ac&|Ix'E yU%?Flq%gS7iOiY;*m/}}t.:flm\&h>$n&$5g}*$61rha!j"%U;HrhQ5^rNixEo**׻ٙkyo`msq]8 6z=U ]x%uѴ.^vOtDd"-/1MP~ -، EE(!]&_י,1g9Ϗf-t\/z' C=(3[_wMSZ.Drmu#h)i)Ö.?:u u^Z-Zt< h\t'=0_0o  Uk'bB裨`?V(~e@{^N KJ}VYSww`֡H/&]'W^?#cZG#95z @3ԏw19v3;(.`Q^win}a50e>W镌mHӻ'.B, ,Cxٱȗ(1-Q4J4evHG"ufq3,=n&(̈́,ѯ#;C o{收o-IK(9PG\V߶Z|̳|gmqM(`s@\s3\Y7| Pm}6=ݸ >mH=n5FG!U0xK6kqbkcG_kemZggaI<=¡xgb5,P/ ZљƲu3SO:FǑн21WZ.-f<;)NF۟W;v C1^!J]sߙ҃Pq'+/KLC3A["0/,sk&8%!jH6~8Ab0vdgz-bW|DX^~%GwMALLM <..4sr:FgxJ^ͳ:ZvW+K&)0e@W-2tv)n,!Uꠗ^s*z'܁vh–,QF*6f9)nɄ'n+y^2eэ[%] {h uti8R‹sϫ|b?Lu>q.4!E"Xrl@5 /?q4ԟ 4+gs35_5$#Fd4K`}?g3yXJ,`O6|s=1zm9p6a "v\DeEd^=o ,!E s<D w1X.|cTo%SpvLIf f4Pw[u8QN Z*ԏ.-&m&u^7:4R1x,x>69WQd)% %V}b6&tAB9~ϾEè|j$m鯚hQIQ2߲9FDCRrC8>rf_*A+K֢5XC1{ⷒO Dϫqp !aLTTUj^^An"Z} !HPK^ɰtYX9?b7mcQ葛]ߛeo5L]ÑP˜Km4s XXx]?}"|iqzigAH޳JKmhTMCgPO\h $nL3@oWCNÐuk<+H--B qi_>@ě9<Øo/jz}B1WՐ5_{׮ mxI.P/&z_GCG!M c9]ob-:_ir =VZt&{0nMU4TtJ4~Hk>4ʓ7ѴI׀nZ?A;9='pO2]1|qp6oe ^Xi7Ǟ,\CJeh^uKG=׏O[جƏVD\\pjÛhuuItJnwwrq"Py} nqzM[Le}ɰ|d>ȷcIm Vs ŵe N^c=IS_՘򑓏\Ɣ/hקxsn `ܺ}< S83zD8OҼ'X9"t^ nU0O {gT# HZt[4#أv7nQ,8p聰U.=.8)2.'VU7 HT$:U'#Q #bk,<"!#]q=&sո^bd X vҊ[ގ3io:8ׅ"։+ւ1=^JƗ~>p_3iT D̈́!:pj3>Ytq9z uJ=O>,5jIB#lNSFn7{F'` 967QUOԢ,2"cC+yr://O'6PXl_X ,eZms R֬ sR5ԡZd ?T=ɵzq?:ؖp'e5H~ g9x) ܚ5,)9k>f nlZk,b#_oX<K?:A[m;9~[BV½ScFE7#(=V{2vQz?}zK귵 be*kQH3u;&o  !-RILx/=CAo藳BH:Zs;.?yw'̓&` :YEO dȝԫA7!l xiteayAT dcV+jmW>=g_ Wm=GIM4Z'>^[bu>߉(v-P~ŢgÍҋ5-d] ZI MODׅul҆ڙFx9Z0X (rc'L$ AWj 59uS+-{p(͵uI9o-p`yf)41=LD4l2XhՃfxƐ(\RA'T[>yb-C E5YAX`8UucMfcNqF@(_+۸z;αHM W滓,|~Ta~ $5dFTO"R߹p.+?3"XlK5aIm(=|Z[𖗑v%bQ=oIB%F0LuG2\҉9 m:<շ .X4`= ѹH=Ҩ`=djL{E> %VCJأ|֠L~H /A{]f'Sp﯊/xӹ k6X s&Y'3 K 4hXOYA5Epjg i2Wü $,^z''pUjԢv: GCG샔;~}PCpj+NT}!{P~Dڲ\@]vk\# Ԃє+%l甾O& @U $sV(1 M|9$ͱcF}QhXK0 -w5F!S}$yfГ͂TD"P9޸G3aw>| JU({q8c!mvC. kBX-N($=ԪA]t[4g@V'f |t[m7S?oZz#_ R(xi)K?PP7%H7 U7_DI^3N 9e<~Z:Ks뷑a0'bض9cc1z<*~ =APU_z&(ܽR=Bo9Eov]hIs+L {ϼmY/ Ԃ^<)JؐD) {ex\py]a׈#zca逝!*lnɐT h\ɛmv]ls'kfMw:!SPf拘{oaypw%i/@i8;M`ѯqT45S isZ}Z]QH?]y Yg0Y*w ^ t~Yl5vc_a򨨅; 5I|+? ة!8/ڑP54Du=MY+ďbCCv3*N4R|T0OcDQt34hqO!ںWw^H 6X}zl>.EjFP{[!|9ƥ'>)F[3OQVU;C`fQGs2?څj4oW61u3ۈmرPb5TБVte(rt^l ]T 曲a87S'"_\6D2J Z{D(֓qf f!+-5`\/brL,V(9k# O*A|$CجbNRF,p"v(oWn W!$~ H\m ?9 et;L2쩾p3il88Qksɿs aSc?g96y|[Q(|: &\΍r6+B?OsO["N"ݡ$uw5sN]K_cX| X<&)Ϝݻ`>}n0l._;}3\P[I2ߪXP^Bxz_a)'ypeTArK)s (C2P gu "WіzzdM g~jbCyt2H}-?LV?FhL߆nqrm˗0K~ ~ }'Rzvu' S73N;1lQe5wmJǑpVz?HnLa"7vOp9]19Ϗ`uMDes5Ok2fq oO?ԋnwEd6G#|6 GlyjRLY7*L@x7p*4);fabzBnZM.d%-"i%D? 3 D\~)wMĺ]O`RwՏ⮐RL.%Ͻ %]M/~g~lO5ø ws𠗯'f| oWT@s^j`R' MeN´bUQz\pO ~{> V@p8-3GѓUU>*": gbvXA+lԬ< a ,/bδ(57D%`j+/W\ܛWЈ)^c8?6щr N1OE>b  w8l%(2ZTIDC:"*+Rf$ck\9snr`Jz#]]_MB̜0^ }t@'2:A)7,̴3{2֫oyuѿmo;=6%}ܮL @~p[źhyPPU<sCDxI/u8hܠV!+Ql}zit 7kߺX?|]D|E] n1SFpax8\g"ٛEø=vav/z_э >Hu`ڳ;Ylu~39ؼ\t(I]ϖ(ƬE%H;Y87V9bWps!~ W9-rg&YjaZy0,INM9r} 3Skaw#;xդqL'D> o o׆ PGw9ܚ{*AH K태B=oW8=U΢@jG# rI!{( \C#(p椴2X|~uWR|x8;%{CS;I#,(|Mmle>o}|8OFwiՙ'],Wp D)6)%MphdnF3v`i6#9m +<8 JhxCSp~k;"hSY-˓ ׿[q5; [eBwf7>DžX'MVxr>ە0-̜F"%'Qd;\$hH+CGveH |+5ұ].Gn~lW'*%5xE* MkdJ O%4c3;[$-:U˲g?Ѥ (UuK|?m8|eʏ?t'K?%:Ues\@θ /?'XP=a^N3vI<4ݙ-g{չ)Hk JG=ihxAŠE2xDdPcϹS1I],kBǩ'&rw|5K=vJL:cr:آɔ' ]5RsRkk6Apք%Dy&.e!#7o0F0AlCZ,E^jИ^DBlen>OY6߿ԁ2;m&5!0?E?O1g:_ɱ2kS]Am.gu*^f;!Bn҂'8MTHNZd[/nӀv)q(|p҄,ų%o.W.ؓ4|+gZ'074nb["\ٝ0t GƶG+&/7ϣ=T|ݝkj"EhSG{ Wxmr;ewQe/// ;Mڦ;,{Ɋ;hcge{X¾3.dnݱ/UZ#yHeQB7TͶT<d`䕤U.?'C^moן8> X1:q_C^_h N!w7fU 6ǿ;~Pi1'Q| q [oQӶX!(.Sp#CjIsM0;R[fv`qQ8l~Aъ1xW0hGsݢFcvahhoq釖0ޟ~H=DQK>%tC@Wjp˞}'F= jyBm_AFa5u{ nk?WB?Щ"E=$!h_ے[\w=R"IOhj>1T @Dv Rl]tA@GKK[K*H=4/OʖzV=/'vleM鈺q UTI2*u^߬?;meg߿Rx0 A:C\r9iק,]rqW$ 㯡2"mo氅Ю1Nr94H$5U3*_scPOO6D )0~7n]CU>dYeT3I/ۥѓRb*{N8}fU}|; ,#3%޴cwUF hhU6ٿ}FToC6.n1حM"pRUa-\;oC\gWl{khljSORP>LJ Oĭ?cUWw+*Noť'r+/3=Kff/(&%-t[Wq :`8P0>au8* |G~ގE=z)iwvlBs p:e<- u/&Y70D[s[ٕ7 KwR m#3cl 3?N^|OܧJɢduQ\gxj5 o[ϼCU4h>:h3:d)s]b@ mmtpԮ$Kgc!7/NJ^cPAHM3wr: ɟAxsD:|D(F {Ly² :OyA [O֛2;*ƀveyZ%bG00O+$6]M9߅t^4OS6 ΰD~H3:5oRAKkh5ar:yE$iV+75}t o'F!lroka Jo'GvOdG4ޱjXϯ?{5 fJ 4G={} jD/.ף4V4oR6݊,y% 0r-CbJ.!>2^{ts砦PE9M֩*_Y U>>;1L'wb ?cyDG菣Ȋ,+_%tSp:FNQ˛B$W:uv }{ǵCxw_Ihy:FFޝ9>X"ve _d靽!HƀP,*z2{x!qÞFԠTY_75S%ȻE]hF,iR#.z/,!EE]$jﶫxFfEjn P?i+_ jzXcJا'@$=Dt!E(s8g( pmޫqLB;%p?cjq2ᖄ)iC7p<&69`2N] [9=t.@g G%4P?uZq6IhjIqSlc-WeuVjsCy+78s X]!#:\A1_CZbdƱY7\)St[]xm; k~g7UTT(iyw?ܗ%ǨpSɤMf-(BSY:goFX:1`CTK Oa*0-aX t0J&`/xcvJb~J]qMD+E!9w?d9c6d\8 [6_; 4UNW|5FB#s~|_Sͷ>Ͽz4y+jiA.Y *´Lǣo%}GvO?">yšeևUonN2nA/98(8TvK%^qMoodk1軴oKu 3;ŋ3a8+'LNef[CXմWuo ~;dTW v< &J< }KNA9 }/?G0<4-;TI\_^K; k$OK4BqKҤ'R:E1à0le_2-'IgGyke> _p'E:po ֌օP5*;:YRWUY蠐Pw?.^>8jv:m/ӂű{t!3?tvRL*3溫hc=}W 4(=:.y߇/.Iµ !/($V_A}xK /i $",rm HVm8Z|r|ݗRI!k8k gSƀ˔@zN~4mF,>{ŷ//  f D:5|F0d׽p^|Z7PǛM|%蕕P<-XsdMdAowPyqi:>Z+mI،+/Q6Oh2pPxS +>w`[ ?Fc>'h)K@ݪM%Nz\S hډn0FpQP,U%;1K0rE3X(>WFĖd<4˖ |u|S*)ǎ̟$w[4c4m,sŦCؕ)8{uwί4I)G(&R0DGl, u%x<[xI}:}[/GϜp'?CH,oͳKev8Fr' |7'7h4jsEɓw2O 'zá~xƶx%?y)Q-|"[g@ٵ.A4B@G,LN#qᗁJnT{~Gf"7T?l n{^bUxC Z{0 >s?|(j(!O@ݹD3ity|w F41rJ6d-6[Ĺ3/Z@h/-qHZ6 66Y7 ]}8 kN0u"}U]@8\\hׇhj)53gވ1j?Wx뒌v8g$rR1\xWoz|X*Fہ̺l7~pMōNޥH`ecJ $gCH/k'Oz;?? zgL!ݼ*&h;Ô/#9CQrU]Ѭ;ĺڏb֢FJ S? v1IR~N/Tl̵WK|$2,ȴMÕ~dt >G7L p|׮n$Ͳwz AoF|CjpZ?)a:ͨP=[FF'  pއHYʹ$!9Yv>W(&%`gJ4j3_'6AԒ[ڣfPf񊬇O5pnO اF*ӢlIĘ+w-D}" ex6V ^P g8|%$423RyRJҢdKRFfV(̪^뱞%3ECx}:\;'\jB9WZ0&.UG#bzvWYt(9߃\FNhEX.N}eXևM '3Џ# h89ҿjd6ZRQb:6JogJޯ=?FpjC=P%{ѣ2>@}e+z?gW5gzK$'a!zo֎#޺lYJFJcPۍK\$V0萭k݌ƖD3Yۆ/1,K_Q("m /*OP#0x3EyqbC pzo^`= S i-cI7,iȗo^ي} 7}K ot'hlqGS VG>XzPFZ} ~+XAؾvY{vaQDgKt__Cs$5IoeػV%Q ݵ .To8BI>'<NpFԽ[E#t:ac,3ur]vFY\V&qb Uq.jJ> '=ܰx17gu5`K޸_'H(:ײb0H.Z[JÄqb9Zbl?jw>@vaX@7]9.'Zsvׯrn"L$j9"]ŵ"w`09 d]Ieb "foO8=\<9&R >*X㝰ɿR/AaBCV QǡD(84(% 4Kc?~{ g%xAS||_ %zQˏl;_#y(pn`j?BnjU)%a>s?`qs* g*w})b)Sp(oxf z$M빿T [Ǟu98GoB 0fP>^"BlpU߹ ]B19< PP@9@9 xV&*b=J go4OA 5gJZFtox<3 U;Z !psT(ֻf" ;rܧnԙ~ #OP~P[|$.䷥&])):. Wy B'Xx{j^?'+oZdҽ!F#b1 _ <߲qV@y\!cиA )&;l'U]D~{Z5ՁiqY=i+6-20unvMa@An*+0+ՃxěP<+XzHbP`~={X?nXMkwr)F( TQl՛Ф59K#x.[Dl5˛ fC5詭?{oF\$^G_qqL+cV~KXPQox)M`j"I߇x^KhsO[E:p6Oi݆k.gf1y?4*( TvGs{L˿l\BNpMxt. $L S}4,s6MśF+iIu]5  wQڊ9)'8x EwBI'h2f>FAUW1ݡ\Nmv!xHW޴VY9?9bSCpi|#*ꆯ?1&+R䔣J i{qVNgyy. -m4Aen{wHQ3J;!Ѳ"BD~8oy",nОLdsĉ!BQ^,4,?7g2 aO0~ }m̚o=f Gћ(FWQkBoڰєA.] į]op2r[JAΦpY*:.Ȁ[S &aq/9>9MULı;ϗkJŃBetQqBG5ț/'ю Xݬx{\;zl?rShyJCWЧPɮ]u×ӼhS ie $Vv9ЇkIrCdVAy2X]'3UV 0Z_䡀\|Xmա 7߃u IYmx &yȥAH*:/` ϥR*fI6]j34Kh"0MA־#UW) (֘k.{5 ?R0_H>^XAef[H6JҧbI >^r} ͟dXo@sSOCޒ2>Õ*6(6G U7v w]uG+XnC-AF{ed&&,Kf*F%;-2C4\ntx#vtp}ڀVK6b_뗄6~y3k fVT~D߫Va=oƧ5C\u>t0N;wC>$~{:rm&g&OdG+:B0aVjy?zL!j4) D4zC+Ccc\)k~.iHX+pmC]qk)ffSxѬtmY'<e+:/Ia߳&/$ۖGg 1鱃m\|Fx6!#ͨ}{tV%W5̄U|^o+3! cά/n;h ƪ[ާ=F>Y|K9gk[S1ª<(U+GɮM*^gr{Of$, mik ?+BSlCq6j2 _,;]T(>jI ChD7I4KڃXQv^tO[Fwa vøD0uڤ+MHVna`Js,yb$+G 7pcu%e gFNsCc/*%?*Gٲp!Ck~6\$_7 U۲ִj+sb0T _hXⱤZ \:0 .3Ok AQN!&'00셅|yw7w_>!໿R=}T!bEIQ >x:Q3âmZOx AɊuJƣqha 4UၾTa$tpSI,q£`sH2x[nI0ofLP:dܺpN/X}"VaQ:\/\0g XN:sCTprb-F65J0 T5~Ӡcw$t&lQL{gSܡipLq{4i"BκM~薐A[G^ ċ 2WQ!i)PA >.ؿSo9 /[ߎR`8?2Ftq2X1L^ 0 #]z_eMS'Pv >w+ E"x{kݫf͏m[{@8&Z6Bx>@Ng%:j:nQpmb<3Zzv5Oxj+$H 4 eoFNA.0pdHʓe=p{X# l!ARWQ2gOk}3u*b½Wm=[V>I9ql8 g^~~4PR- v8gcV4[keWӖB]&(L!\72߫Zz Z燓p|VnW$rp%{mQ>4WuQzK  Z08 9#(>aomvÚBh>H=P]}l )>6v/1Rr~X &.䌍qI'AuBYJZzESHĞx /A?f-C (h.3j5)|Tx{~,I81{[piV/am47jy^PggpKGKV'b`,|u| r>cH pw~U5 #K~ 񰕡ɪJ2NV:ˣX* qѧy?b.cʙ`E{›99x1N u~ɲ0qt<ڏug+)pw Nj<2ֈ-T㳓ɬyS+' `(ALy63Zy}4Me8u MWQRNK>:rqGH3:T_mlu5,{M5 n0O0.- .$ "S/ȟ]gwL{*#[1ps,i 2llUǀpR%z{Ԥ - $Hztkh  uw~qо-B%~qܙm;5}>S X4iP 3=## Ks _d e4}{s vxgjz?S`rC0 ZL4co/ ^6oBOJOAaD *0UWA!Iǧp QǻwmǕ7[ ']J9 .Z5OϜ߹ؗ]SpHp>  GpF!tf^gWQiV*LӤz2&QK"?9GS!%B"vP)t3& Ą[ɐ˵03H7I`XP\;Ez&I ߒ@X2 aGmY!z1cv)qjsl6F5AhF.Qe⺡"^iݲK#]>`H'RW~ R{;͚bfG%pl-ۙZ19oJo Dfe­ŕzpTUrenr"#x׀ͣG5k/Rqm:ȶ(-MIqȽٱ[)G]-̿>\+׷y5bMPBm32~/P@Jr%n9ֆ@믣.q}x9X=K}1ӅLDλU[?ߎ-e<ѩ'}mDs{F%:joӒڣdv_AE$u: oVe7,{T>Qæle 8pCk:l)H[< ]CN1O31DV(QP(.X{O3ϰJx[*&+1psGPϟu捺|}ɮJRI53Ϳ>U#Kfcٶ.n62e}x5jaJoKա2~{YrjK'}4Tv9[Ys5xUaُ# rV2W|jc %\hI7pC#7Ln[~O^9CE;7hql;ՇZpF;rJF ʾݰN(w}쉴k9mRuii~RJDv$_u6 غsO+ u-qPExgLwiJ$ˑ K< کrě!N9@gl.N@0JGHо[#dzkMKMK+꒏1*O`҇Ηd |N&V'I,eһE{]wc#\ȲSMd> d9xs=IԶ:?aH#%vLibk܃wϜ}1ƮRԊw<^ҐH$ό|H6 e'dM!#ee"{^\qRB%z=Y|Њ1u/n>|~?N)%#]a.ZInr>h_۾l%)\a /§"Ԫ'UC8 `R̟A+wo R[^Uut@%qmo~t;~O]">X(朄Nݾ OnL ߖA.*F wπ¯3*0_7 aZΪґ?vɍ?Щ]͞J#H 2cBDh|Nρt]Dp #BWZLd{nÛ"=+>I2Gu= !Ar( ܚEIcQ5߶AѢE*;CپF*EJ$ Յc So!l$*KM/pp|IG Cz(xڥ" p]aF:egɠ3 eI(&\v!vH'ύVc&g*ۄ+6V7"䛋jHHPbԞEvm1dqaX;iK}Gp?_ 꾔I` 7Ό}Pah}9SͰV_f/$>^+ðX~r>i=A} ȁ>SX e1A SGr`,80zD7 ba oĠƑa_p_͂p]—/PI*?*#teDgp) iȇeU`Qzy?~VhE7Zc_IGLYQZ4i~B6UB˸%.rł_do*kPw~XJ$)% qlP#1NK( %eC=h`dq^U;N-8 vs:)%QB@ WLfIjZ)TaQڨEEaR '@ Tw>,6 *KG-ke.E5o[s`Dq8w$(U'%“!LK.ׇ],L@V ,n|lȤdl ^2Xoxɛ?"AYWe% Nx4!sy6"$sSэÂ,O1&T&Alf xFxJBT\v23]dܚWWej/lnеxf]# d\/*z%'汀ycѹnk%`9w*i-EG^?B̘}"j2g/y%&4=C\#!yC-1Y _ks! ~ GMwQ,FG?^[Kד|"BWQD]b|z믊FO}E,k:NΟ.W(5݀n.>Es* dXDEqϤ#ʖDS|5mXE[d㡿+yqh6 1cGYh@I( G>ҡAYE^wa[y%Q;Ƴh\V9v rbԷM tiITQXs\k=/1}܂'z L #jJm=ՠd#PUz5Zʑ6ְeO#nE줹;_@GHx5;F !x{QRxrW`TA|8+!73 ׄ5r 30ȗ7:AzT9mwc@oL98Jmfi!GxhmuX<|1Y<DttBP3ɦ(+tMc}7dq%͂֞ڼz V O>! -`ZLtQ 'QWNqlo4)E9kK^ڻ ?iNW>;ȰTs~C׼9Fxvp?(;$"NsSS: _{@ mcKOP!d`s]일Ƿ&z4*D[b'$y y 2<U)"Cx]eQ>28R@AS$X0A|+b$1&Ya7ZXhs@,Ӥ&C{C- K7/t Tuy1A'&(]"~*~.g5dV}mq^wI @[G)`=P:P?mU*Ѷ/cdDtO|9Xy< n\ 3#A.2 ֽntVi |0 _t>\aa 04<4 Xܕ{Ƈ%-8B /\;*uA΄x [`Fx64TV%WxVmGrCcaxף)tWUr}pD?GmK9^. q0}Qs`]KzMNG[fC8Usr$CohE`Qf}AtZHMw' j^vZuv Nsj7F2:oԼMFFD4j_dod- ~nlBEӷ)AY9j 7?J2A*-=GgZK?zՙ?Dk>N:XgBH#t_'h 1Ž" cH`!Nn=w9q@elkAnXtc=NiU$McEuB>,t`~(~UYfTY@lg+(L76x}H (s .a7073Õ_OGG0l`{o Z%ɘs!!tf.zo龈DU#ty ݵш֣xf #i2Y8iT΅rN dߖבtl2 rO|K( ZI@ h3Ym: d!7s­błnt%-} U;l4X\WfShWiqRX:>M] "Rt))܇/hq=f;iu*Az\?*>oߊ<Ҁe ‹?IṈ8S9qr]Tz23G&RkFjiØ P~vpp%9z>1F%?N-1E. >s+$Y@S3jzuۆa~+l~cP )%7p@#xg{nz2b_Cν_3 S'I}bxpvЗbYIl`6+G?z`YpE '%5 i9fs.Jjz9$yٍ"?Ȇ[oe4gu !DG{CpɌK|ukn bVK1AlNF-;Y-}_@jgD#YF *ܸq 4#\ca'bL{)Cf(=::ӋkRz hXQT.[mKЧ f77ǜH̛np~eruy aC a0EtY_0u޻\1ŀ({M]'jwrzNVo~Q)D+(gQ&`f($+^F&n昵? -:Z4 ҁmMDJ?X DG$Mtn_ \CM=]H g9jY`1[fE!9= t%>bw:.7l /ǣUQSpE$RN)U>;ÎLO7 "A ZJAo2HR6d8ҭ3W]k)A^qJ-ᒬW̫H=C."1I+|D(eZK>_*ܱO%AT^߮Dv1!>/p^_%Bor)"9pP`q݄R)0>{brNwubtn "U4σAB~_ Hc) s#HnTcP֕mEҽI oղ^zlu* k yĸVr6 ƗԘ\ /{0 GAQ5Xpv56#a^_șɫ[uG$`fQ]K_\:;__JZAk.7Æe-DotN߿(t1T{䧇8ML>끒nf1}1ΐZgzj{}kdn+Gi2 |>MZ僿_ڬOd q]D`ht܁ f)٢zIOuO>n mvqz* ;8K?ЅAىz't3оq^nW&> u@8KD ҿdU&|00)מȄqgZXMP :|^ƭ+bk?%gk}љ|8$*]g:^ޜfà>d²rK=_CPt(>Wv&Uyѝdpf]xc XEu@&i{(eBO( Hm!3{}EӻNBg JMiA=cr_j4b=5ͣl#qt?QD毵R'ߡ`zَjkTdq(vEX3'WR o( {h(iRWP)QKxVWoMQ@}; ]yOc}E l6; mܿw7G㩂 YbR 4 _'@=^4Mf"^Ѣ9 |̹n.0;{g1@ab&X / _t XxupDDhrmϽPy8:osm Xfl963Av=KE[J ]ЯYjV@/ax^~y,3'OH֓#˰rdƛrl4%Ao#kx|h34hO3Vaa8fҲ}Pw8G%Tᛊ1"$Ʃ$ "܎[L =T>rMᡊ1D5/s 5N]X( ~B&rX_ ϝ$ YWJ~0EsJ}%p// f8 _cOB=;85paCr%bDe}{[z'ʿ%py7 1VXa"u`é: =@~Kuzr(},hI/BH:'5L#]7u229QJyxunٟ_M]13h/-bX) NoBASA^\jyr:TLP~~-ތߩWsi*R0J:KiFЍVuQ~a\U٧n\dJBZ.W'* ]U G_mC:V(,@} Ź^]AiKòūM kN4:"sG.˿LDAnu}݉Rso9¢Rzׁhɳ@g,pp }Pc,{`6UWw8-!T7u PRAap.aV {"l9pZ+:rr <Z[m]vDŽ Hl~%&{tmw{4__v YGs@}0-R™JlqNӚ8~<m{`%F_YIU joh K<kHxM C'Ol 'FмQ@$FքE&~0J%̝Z1]}? "g#ۘA/.1eU;(R~O|]c|,^±E}r$F֦h- ң U'x'Ȱ- O?,_W>ӄ 'nxu2aE;t4/kzQkuAM}9n0ew  O I"5*Övb"{D_[X;c<:k4Z~Nn2G!rpToZ3'G|=UfdZM4NDŽC^VAMuɾȩ[_!:pׁ"M K5&YG>ك J3Jʃ.Jyx8Q!ٟ\}EsȜ֩!o?$.F8W|V[3c8̺|> W9`9oDm9ʊU|g\*ɿ!uLRD]%9<8sJP+H%k?-]^T.JHˬEa<$ߴ05~Ìd `O{A~<=0#Cܗ֐^rʚG)f+",%6& զtM+;pU|3Ў)#5T~R!sI<j%+S0pbSyw}!lL>75guncw]u\ҪKaVy M!pPT[0/+p g 焥ɋ!{cqIsc F^`뻀+)@&DSS`dԚZs=s?AbA H+uŕ<-{8v#e3ך£KZ›Awz}˪G|%wh K(vj4E>ҥrZ{. HKP q_)pELWܣHh{H4Gl-D7Q 8{4VƒN<ʡS)fV˨xtԜYȎzrx SJ$H!m74Q/)?~` kG{F 6 ЯSg n#ۣ7)j-qHOVZcTӌQCXCh%)%[dج8u:ҡO+m`9i0xxҺœ!f.K.u Cglлp4gSn=c0|<_&/X}n~7! GD-h=Su~B;폒 .\ـ{{ZmvR ( K3} 'r<` =hxuy!h[j1܈W-IORh2Rଅ1:0HzV9m [J FҝBz>0?W'smf%pdjMB۪vWf͊pxgW9kcp|)xi@;]S>s>ې3U8SXX^ڇ*7|rŸ,`"{˖Mo6 k$*kibSj(q1$BLr0ۙVB1FZdObO0#_u"& 2ǒd6dvM#ê8I} M<,KsNJml/Ǔyyv0 Tj(qZT} E*mt-/"PYn\ca.Pj h Lfe(p>?WNjX$/%,2g5 DN|웉Q,2wT9peeȽ~agKwLtĒ`kmB~ߙD`eH#ߣiW$z,>i@]^z!+ݣ>CҶ S.e<0jԇ`^UDiʎX1Wy08<ԌX$pu\E5oHضo}T(s\G,\F0R|w}RYFY`:<`?Q)FxY?LV<)1w%@Ly.ܰN4Y9 ЊA3 G-.9MLRL秡x0 ?2 fOB 'iS-:?  ;򄞄tPrQNEmX1d1HjFɔoNFE>k^AJ@_0lw9s:/c J>8䲉EZҫtw棻[˵_E(Vɭ04git-Kq6ؔg+ CUoP{ [ ⺨E^QB"CMKOF_~J25SZƠ<8sMFs<9azsX p`ʕbt)Rh_2{LGFixCnkos~j{ 0#b?@.XG$+8Øbw1(Su[nq.GbHW~E ;faHֳbpT\I"[>Ot )2|H=XqeM BG|}QK~ EJ ?h9GB_ 7G茄& Qh赢x;Yk_]c)ҁ$ 0.oI'wy YpPU#}s5 :ޛ0ۤ>?٢4hRJݫOL>-.K @tB^NZ{P][t#06OS;)!4NSRK*ds-[ͫaD| <:+ @?G4>NؖTxKS>Vru"d.$YM18]@Έ٢d0(Bau7:w[6ɗ(0?uGrfV}gM3S]+b[JYdoL0K=ڝo"ExSM$Ț\|:9DuM 0cItؠ<fF'~md U,kS2'4IHOϧk3=)$KQ@?N&$$AλW}y϶=9 rcnࡈVM_&CLݜ1c\lIsOx8;6'N+/~Ak tm^!=%{a,`%V9HN@X!n(\0] KxXttQX 9{IP C[̆8AG =ku.G!DKjG W1.|/"=SN= e1BEZHB9di&J2c ݍڝ$cܮ/{Wf~0w>e:*:I7^V~lZh1|s$zJ~v<3!4a7FڵI$,:W86ȶ-'_5X?{mhq*ڣjo;?Qq{9HYlig ^;Y]:@i\˭F{= ۣ"zDW\9]xbP`{+ynv7l,!!Vb*hIǃo:+ ])8$`cq AK|]ptн'c24oW_U@ctŋv[j]._q)'DmSӐ9T5=;yr/!ρ &>QmX5{E9N/I:o گo4`Ⱦ}'u~,|;bky$>jKGeZv獆 b9^f)^`qlIcSSop0|2"ŲxDGJjβچL4 7a'"aƃ']BZ̢|M<~wdwM=9ڙVe"/Ws̭fpeDkG-~fЬ2BCSm躔Hy]i+ d*AodF~ OwF ;¾[Ͽ} 7*ޠҒ,rK<^04BЪ _#8Ia%r0-[!UD/>uD۔u'7r/O˵i>ik/##";5?ڋ'a1M8]N݇vboU1yx(upi.y998"›dY]ʾN˓?|l!m 0/F %rg4V/u_#afwV"𹳞w$'KT<@ ϐ({r8h_\{bٽ3Pɞ;,Hք)}!xH}mS}w Zg/IsO%"ћ*Lcꓭ1twꛆ h1DfhZm@R|}Md!3 Y?v (R_ a1E ydIw:բA):6ITq?rNZ~Ђ}lU|PGUgn/9>r1d-*v;+;jUYjgWP{%=FxOq^.;h9f֗KlPSk;8X '"Jf_&|#RnSd2 &G*`g7Ю3iA+N]g,^{S{t@IB%5x2_65K~q8\> فJ_'H8k xp)'G'oLC%[sd >9q,w(E75JL1$A8$96 So M[BZZD[oL`/)P/)-sZwI0|;}8] rMݻ77Un`M.s;E h묺@G?|>$3C3vo^oĻ2EO0j`_<i9nRC~͠I!bUKRHi/}|zYE>#`!Y7\&7`mX( evd!3lp!:aN=dq{?$9-`TB>Ėv[z. nH؛ǥ0j~G_EgR_=DoFO$r mC!G}oա8j]pqsC[ec-=6^P1.c4\B̮3MC^a+udD]oBmoVEɹ +؝Fu8J]DZfwA+OпQQ}πMң1 \K=4FjЀU" O6|ߍ"̓IT@tB o"DᯝEЧQ&5SɯK ɟʪ5 9} /ӈhnѓ9ci " l`۵.;Uύޗo@ŵf$p)s<{cks$]݃/U %c.3$O+ҤdXr7lΩF%NSHK+X=C Ge6uF!RQ!TGզJPahĺ0yƹk=a0gJMSL zGDX"J Brk~[ iY'TZ6E{;s(RS¿XL&"ewga= -P`[.zU#zn۪E*U% aO?N6#s )88wy4lEN+.75TKJ'TJQ"B37G|XfMI[fA$Ǵ I<z$ y_(k 4nn -t~hJ;ߧk!Vhu~?LQ-׭a wt,*ixK%'œ@X(Bz=*!@49)_:_|>h b 70GAf\r;T `<`P;30\ !mj!c# ;g!C7O=o'WkO9NCph Ԋ~:R%I9rVh3q0޷>/@x;36K>CXvN㰿5%4 iT ֎%A"*|syI#|z]'!aoIf#=xki%$V1H1V\q(5yw)`ZiUbA{?2H{fQ -)7B57T-%pS v[g Kg 7>{]=u{ڊ|9 ~pvWf`ic4+kgů!@ݽX`P_KKWIpOjSܛijJ솎$8o}OcT<ٰO[}= CÁbdXŇ6 )hi8ն Gck9 l[|k/L9wkkfWyG%|릋SJW sҁi׫k4JR!P減%ݯt!A:cdJʩ]]{,q`BT74 />qco(_1~<̧l_u2\]N<;hM5i9E/t.R=q]Ju^*'Hp]$a"3khP]!7ßyd YS %}o~JX!~Q?ˠ5(~Ev٧0P9lv8\\E93ryM>ū u0Le x`̾4"86 |.5n6N-UA'dYqH){@Vyz P5:Z-r} 6g jEm ạ8O6bNSp(4Le?WFBQ \D }Uٽ0el1 ) qs8tg ߔ^b`Ҫ@{ 2HFZBÐLM2|u" :SPo͙> .ٲaݘTfg4w)C{2'Rs,_zƒ@cZ]WEjt.*8 K/zY12}|; }8+2-j΢ /J ԃ'/G.fv" Mrϗ$.:qPU-Mfsq8Ԣq(iI>냩6Dd$Ar/f{$t]rSӌ{Q8n (<\n9RB Ǿ&W%顃=e'4@*JqhYKRw 8A۸4$(C+ୄ.0}$BuPˏ=u/8<=;eD ?)H=E pjZ%Q^MdÂБm~ph^"x+.L4XnJ) ]9 :;}wGk26ZHb+x8z NA;gR!s z!H4.`\dT~} :6V9CxcЂf Z'{I$?ܢ6 cpl~o(^i84# NyU/|Gf0ⴼlHvؒ7!蒝_7$aoQ<M0CwA*G=YW=3cѰҮ=rVQ'0*ȱAl3i, _k {}פJ~$7sBI,M`ݿuY8<WKJx>"^npH,;*S4[gc{>=/ },)P )QԨëጉ_tbRL7/@gY*CQw"G?Jx̠tS$4g&P@@_Z;1dV{S\{s&xwþ|_/,k*'s3P=*@|F sCS|feCn J1Q]o4_n= 1CRµ2x 9*jAB>UR)s6t {1g>}kjGUJV%](; V9kyCr&A'e|S!(OrGYAJuPtV]7.(7}:>&0/Yo~t=<-1˱X T$?SAc]qXܱ{GX^!etnԿ;^lǚpVumuo ͮՓ'C y}w歗}XH~lzzLjdy:{wLkzPi!Š=+ۮ\2T_ގ%Ao''mGa+e~}vX0bO=`;[M[1L/0*o0jJm,x:|/Y.‰$rNj)SpHз00$Iߩ{iKwS(X=#$,4m:frAFTȍk71}Aħ D`!3l׼bګ&AQ2 ͳ h4'8VmtɯpX0`ZMЧΒo!VӀ ppj+N0 3BbW=-^&9ِAJ9p v.h:|_h2a˶scP1d,3 GT2AL$%.ڼ8}K6ANg,%Av9_)9 "<1?R@EW9"S|•ߚ x#߽pM]Z- )i"gM"n$ܶ&?~Mk1,\2 TVxqaY*T0_84$f*84oC0یa [r-&,D 4qw+sكYŮl&.BVcn/nM7@\cx] "΅S`Q=? 8hoZE{GM{0$Y уa8o^L N*%oWk=^AO{n?ʫ-I(8KB[ں!c !gT<' Ȳ~҇拤B/Psde13M?/6!WdɲoYpU>cC 8uѬC@nsa*?_eT/~]tW) e^A7&|QqJՋK|L~\Iy,$i hЕL+OJ]BQ"0skH{82a.DjWS6H.ؿ'pS:D-Ȋ8fڡUyPTo6f2ԭc9yqJi#ͦsf]QKW iS?_5ju͠k Uܥvw o1kX^iQt)[@$u: Qs"PwoK jL6jnƚ D>ܻ6sHFn R:3E#/8t%Eb堆Hq,]v`3u3z##_xZl)ՅhMP̜IH{s2 1-R?p-U~G쉞1مhj~uuK5(ϰ. 1XѳS?d_! kǟ3Utdy(WS=AmWz2"ȗ+b!ă@ 0@>5 rg#YplCx >iƀ.JLijR s"0œ 6o 2̧{td/>2Q*?xeYN9_c!9$ŋq )3K)hVݤK_&4rxpݥ$m ܁ +bGskx\AKj+SȺF ͟Tw!}ܜ g=01 Q -bc󔗗?*Mnr 7`j~ 4q8<Ɗ^ t Rı΀ l?Rr*>"prFD0k2־Ɯ=Zxп.#YQDyIy8%,Nq!2m8B n%. EhFhy/x<ȼdmYtDtT^)㥙2fqoV{y3TZxȒ#7[g+Bg}Ѓ;1 n>8s^tt_GJ!$Ss!3mf avq9hw3g}3(>kGR-P,] H^kjt0C[-A쿟{~X^z&?ljSx&\s]{#j'Cm,dc(;|f5{/aJSLl~-FTnݘQq@SG9on sg0$Wp}\m!8S0XݟH{, t|)j8N%Ȭ);qp/"׏][֝c;QSȉyTں0O6&P%dī!' [W6} o9YN_1c;:^<ǿ>hRF'kz!#1MM .!{"غ~V4wccMՓP9r_Y@v7gB}4U<2 2]`ԝ:#]=ydsb_@yUMu.qSi >e\#GV_RxSW8P^l€mGNpbاKǖXmȋ.@Mb<V`s$Hi㬬zKɰ)}zl{ aE+M`Z|+e U\:N>ݩbcu ZFOePu*e&AlU:ݿEȏɉ*'kkbaqҭy>fnQA.hˌQiQ{DƃpܜL$C*jd*.d o y#k22+X= ε1ؠ]2U_t53"0-va`M=$5,7.LK*``=2\]yEw]ׂݐ)9gTc]'([8J@rr74,A;dž"sFM7@C gA~v̀gQަ>ksYmuӝzu '!!;*Tc~έi_P^ϹxC4%WsTJZދAKÏ!JL5 L Z|(}4KI֧hrps~ y67[mQІCFW]=EqDx+sR302d%!\ J>?BHV iKJu&[e`gTG}W54-1N'KR5s[moE x BåKFmWPNmbF:31I/iuWԙR+ Ib>fާ rE 7tF;\?J~y@'?U 뛤%?$s #y40ވ)pv1V!0`e qmaA(mB;{`>t/5T y*7~?!{( =G_/1™7R?WA^7p9i4S $.AGzPȰ litY$ i JG8!}"iG?f ym`}Cq#t<71/Xd*,V+uUEBebW/Ps9>R2ugz|_iI)[;C5L_ђ?˭ztI&Tv9O$]ы΅+1nsP)끕w@ [ԓӧuД[=lSihaCf^d8$4+\zFǧ w> Pck{@w_.qӮPtL@?cKh1*-'} Nm*žyۡ2QmU`+ԃ#b'\%b LQ!q{{PrRxs;b:\?+6qٶzq 7o2:uo +aT}T}-:]u҃`1? 'TYG 9u[+bs#pK(mD7g.ɰ[)uffq@MgyҒOaQ>$cv(X(ɻ>$86V{*f9?9Υ CMCJf,<4=  w8\Ǖ]lJQ~*B{DW{VVH^.咔Q)oȨ9~"}^@#tiXؒ!PӼ o/]n(]0ئtip⒫ȶ(Llg [7oD Fi0Q?3U%g୴9Zc_n-~K LCh$܁^1]}se!wmfAhP噫4(ȧ(˜ԗKw t\^S L 59 f ~l Ў33 J,nZ,1qO Hȯ&:EISx@o 5ՙwI~&yBy`t'Ɇx1ȮTMcWϚ/03o;f ^q+x8'R"|cĩE>a]&rOCnh(4^.gOhƾUYxXk@NJG j*8AFRtt`,5^(: ϶jP\&pK4^%a3k>߃zVy&K_$X;Mg3-0SUgu r9m.Q ?I9q TA2 .hP8j9(;#%w͹ 3x,.ɽ><'6tK4Ѥw rg`.*E6Ĝ GS)n-X"q͌ݏы=;r<|Xl7fQ2QmE42I4a!׆Yr-_=F>:ͮ+Ǯ#nR9$o 4P6Rq3t@vks')ȌHcXrO3Q8afQ& 7|ȼ]A]dNlz[Ci#dݬ3F|-E*P8ka}&v ,mBJKX۴u{oJ#ڬN2$*#;)Mv9t&`=tEru}7TV&³/;̑B^b:Z]| 8l)ynBsVj ]j+fʳ(߂1pE/!r*(c+]K2iƗ/HJq {l%pt# =RАDvWxȒ@e<ݿ$ ojx"tWJ'VkI  4JSJ#٥{p[lU4g!]o%(UG]ghLU~ffKUVӀ'rתkCTė7M݄$ 6)\z!r)q .+ۧG.vD"d^mY>ڝ8f^"z ܷx B 0^i0T Rs dV/2 7>~vm󙥁b $I x8rd T ÄZf! k8vpn+k_>Ƕ菀mDzKyyrϨ<3aOk+$*!.E+@wFY3'^C6x$z-3z\TG e ;!8<\ `(Sxzo: %!X, XLb!%iMvCq79puy; jkX9VzSo. !z BWASl8Q]أ)zd(9" RJ!ՈJJ)Q5",4cve=?{8Hrwe} +EV=oe)9`eLcz ɗ!<ӎM?1QgR;H܋G*ٞ[EF(=7MJ0)FF[вI!I_/E?%}HJ|(@53"w.3C H|K< \7*@/ǸMo^91hm\ǣ-)|\38OE$?D<,>[f^UB3'ҸTS3Ug:hHc^ʏPK&@~=.lgY{E~x?S!扫w=`MWԁbZ=!ns4^M:DY3zs2Kg@pCp^ƒ9<4/<~{ :tآ#Foo ury w?sakĂ]ҷ)jtq&@3fC.;[@"z1 l:9~^ܞ{b({= ]5&AY #W(AB{עR6nlcriD 1)͞nc}y>v eW߁쫗SS=~up 8Tz~JQ}F7cZ=*  ӟTcgh{Dz}DءyHF&.xb׮ N-H34vnʙvSH8lv~ ǃc y9\t_+%0%1A gge mW؏V뙈S_ ߄c.8֟ D}tuK z0L*5Yit4 vrm#x j OQ=͙hgO0h>ow?Ew~ %%D } duBzЃE~cF wȋ=Ts_,UAC<:19tj(fR61I/b,ǮC-6|5~4RQU $^:)IË:u٥k(RK:L,,:>/Ko~D e-u>ˡwHaHu\f!Te/ hwt<87tffwT}y ɿ@˒bBS6xZ<^hS(7k< f$v@`kg9u7=.{jאت{>R׬Yk؆hJ` lŢOj @<1UVގ"(Z;_?(-BdnE^ǞXi⽍Hk9 4Y$Orh)XԬ$/ ^.\F+9Lxd[)V Dk(pDNա\]`%l_b/|kѠ9oOb3Z9T Ixh+sԃD$.!_ճBk _m6OQh y ь7V(4j Ywu{kFKjƮ[ ɔG,JǡgC(~m%hEaࢬ0Ifvㅾ30xQtSݡNfD`! 7 6}MLX} H214D c܍9Fc"i969.] $A~6i~.eN?ւ~0&|ia>=:y$$63az^] vm1ڃ:MuL֡6 :>f)k:I};@o>"9:l9N$8Zh^\\`t:m6d-PU{=Vxi0G8 Qu# Jh#8\anF9Z:) ,;!GW ;OM+!V5@3Z]fAY bFWlըaTRSoΠIM(󰗢wM=9X?y4GWޗNބ AAw̗gpI[ B{- E0vVWe0 .Sךd tLoːD[xQ[RUJ:և(֨8YG풰 ɂϸ g8 )E%+#cg=^Yd EYٲgds=^EVFD_*|:纞sŃa[ƏA' TjV>'Zyz+ڂ<_AQ[ݗ.HXr$usG3<^ۡ a(-OƯ~ Sqݎ_BSQ\K/"sAc܁9Ijю7~ ̻/"}-|{le# p2vҳ ,![/ReKA7w A vvB'R?ֲ͂P_~Rܰ ސ{\Z'Mִ3ى;'~|#zzV Ol( K&@~K#7 >&܄p# `#[.enۤkm~5 ,R[ĬSYUCāSPrR^D[wf1BN=̓BP<:0i?|oǗZKUI=Ja6 nǧaGᓱpBA_r6IUAq55o INv4<|x4_nڣi}3Enl̀9j,@tp0}x31bwIMɫޭ9Q#M{0 [;$*D,y?r1>~BqTPL@\*)qJ80 ficKK`)g:t!&wqHU8;NÒv I}8 rҌk[{M4]1`:b@Q _Qm䩐4{.Ec[5ӛuWYYq p=J'DvT1¢*Hi;9 d_>ќvECvft[ғ谐!DIrZ/3Ubv"3+Lo!$fʁH |x>H&C{>_hskX tR(Y5eAey#Ɣ+l#fKLXs~6ɭS H?<5I8V7'$y"4KX9)A>Nv,޵̑c)ُAf`:^M̀ )4Ѩ!lO aFK3d!x b]n}wUxGA'Uٱ*W9ic.l".}>/2:Q6wZsC;nz`R6E)y9͟$!v^ܠ|7i$ױ;4XE]tl.OBZ+WO5 Vﵗ C 19OB(CغF!d/I=o"+T; J8 epcӐ+'iҜ:bKï`bnl1Fw=r դ!)fQe 煍3AۏG^.qjy=&ZeVe4t΍L T fqtE vX&PЌnEUlP (;>ۊױ @oA+|& 4vwv᠓zM'74 ؙJi(MQ,j2^}ER\WޅTvo1YJ*̼COڢ7DÏc1r49>|c**"36黿:00P"H)g+[Na*7c v?VNj|#H&d\еKjBTOusd1%B0P H]a yL>26z_M6SLП'PF*zwzmኃyG@P ;&nuanìo,%NɪԴ%RQȠq *xx3>7 p7A$S&]t}o\l!gߕa~y.UE.KN<RY.WU2o]B7jU"Xmi2 Ɓ.1h558R@ i_bVog"E1Us.=\gv}art!̶z?OS==;JZM+歟&~v591-+ӤaVv}6񵹧p|W!~J6^EC 2>a7%2n"e&Xۘ\c2Bڭԃot~F2](L)nk~} fEW?6뮭dҊ{bۆ#NNu4U7 ˡcXvftY~:5r=_*1-'Ӡ)4v+_ 55yيwIs/D^_Kv5Ror " {[7vߋ>?m:(dbK \T 9ahZf?.ǃG[QRga#'-tӖᝮնY >Q ,NU(V4|-`8WP?ecúDVA/94NҌ5fφ, " s#>NF1zf9 eZ=@K#1)> VVо`v?bWq ti-iӭF;[[ƪǠTW/dn2|b%-yxs_RoBi"DfǷoYh)y9G?ȴ,ZKg 09҉2.spYwnIe2.NP:jxl*Bp.֮a^#{,hJE(@w@~?ݯ*ϧ4>o =Jm7WJhʽ7`I$^dzg?TCדݸq{d0un`f=Lu7v W}J?=đZO/2R8ĸ $LyEt*/p%A >C ޒsXx bw.&olaG&Sxb~߷ӆ+?"1v'`ԗHmq]v"G\gqg%R7F:`pp,?zU!`"LZugb9R_ . 󵷿ޗ4rCX҈BwAޅb6V YU!A*LHa ‡ 7ZC T"Z#!26ro.rĞ$H|N,ZhΙat S? "h]^*M:tv#mL$h( ˣ70UsU4vzf~ji9U\ ״.񪴹%,g=c\M;)m H97D7 iY̬N]C|{G\LcȤۍ16p3QU/ߐ$e`jz [LPX {"vJ4gp2O.Zv=N(]H.Z10R[.C=.uU?U_uMկ7 Z:":XN}9Z؊=! v,/.}c2G `>r.>cу.Q(=d,hI>ʩyr>Tε꣩ձ8q]YxPvwM ӲCJ8MlpVaۓ~F2_#2H=Γ{ ?S}Hvvi/@#lW]W{؃(_ǣ7b;;Ы,em{bN$dž9j3+RYʭ KL~ˣani#š`IMۋ9O\"`W.qw0=q^X/'USh ή{JbF|p)#Iϴ@ϧ./#i›Zkr#gf`BMʷ1>i|v=ś[[c8t렳aըn.jq{N`d)fG:FYFo&$PNT0| .`3π=j[ %f87$i 'ҭSکkKt@Z/N֔ ,p>p /| j>C2< Q6݁<EԎ"}{nk_=Y ~-2b<E4 Yx91z#@4Y%WF֊{{WF׉$SpyhOE؜=1UT&¯kijp CL"AR|R ے8ծfv/ 1=[ w{ MBu_hĽf@P6k|} &HWie]־c π#,Bص-o_{oњ1"} {AjoP'ݽ3JxzOHd^KU{ 9V 3n7A2P#Tq" $z\ixD.||hD*^'h PB/dmq'o7rRzx Z?;M*F+ů@7yVSX\?}ebXEQaPd'6R@~>v)fDgdY)Jo$}% J̣ǣ UkL8a@K&O< G5© a7g |[q$ni̋ 6@\=UW׭n]w4+`n'jup@8 okTl' d\"r!uQ] 2lvquDlW)0}XT c?&,'*/lN6 HRO(QJFl~8_Jo*gG~ sg{nrw#K< COy՚oC4X*rӄ%/"<^w>u{bf) LLbC&%;9u+2RnV7^xjzl!F-,Ya)nyCAƳRXDn> s^U9+5tiY^[ :j9b͙ͰCX b2Ewi͠dq 6Ě;2;YG 06.cy[zxbsu!.t'8{Ob3>1\Fg-m6DA:)4 ?2mu(=# *w5p'm 5d;Q4:O2+V.RG*z_0#@٩)e|yF Yu/+l5\& GU].9j>8=L8ԧ Rn ziZZaYU[W|Lõlmq7*d4@Sa%W)$A#|K;u SW/a]sʇ(Us`ϠOݩ$y#EÆkcVTmkhTa!Qp曋%_QJ'a\/;nې*7UAdb##MUt~ ]ԏJ%#_.wm^oO ^ zF*VTO3/A\lS?){՗c>+t$(,곈h$'D?I9>Kҙ@JUǽJmQt6X+s W[}׽kCo'{uo^@%}x1[@盇>n7JTh UNB[[Sw&%&_G= |M>njЩvPg9N$F;[m^t-Q7{KOyޑR?@OS&}~iptH!~R g['#AC5O' < yu>8? gWZo_"V %ȕVTKRMG-}]1~d!ѸG'ER-|1H:[|>l哊Nf$})rUN&7KER%]sPyMdR6@n D9E勅qWVG]z0#@F2ӝ係oW67aPp$U^' UK*L]^tM:&$#'3oCN0f9keX=rJ a4gAH[gQSN ^%Ӡnp*2Mꆅ.Zxw&y g8ƕ#R!TlyTBv6Lf '3l!d·s߭#޸}[*-v; e>jH.?M<% +1QD7w}RHcY+\ b1. <*\zz}sJ $qn=٦#gmfawö hJ<9G R_s0>,$!-_>ޞJu*Aȵr`&}reC n`5WBQ!8/Z@G]2!w? ֛gq6A6x S#6 ,߹GX]Tn?J d{_^{nG󆤧|lӼ_3^p-s3D.Ϳݩ.{t23, ??b~y%$EFɵ ƨͶn+lʜ]QJ&8Z DL+Yb_@khNE;lrK̀ ' ?G&xeJ=5 /]Z2c&Fmi!{o^4f t~8I{"9S'n6I6t|€a.\>{FP4>,^7B{ }43%9f2s ,{b[sDLt`eNR;9ޱ^nbD6lTZ`V6bD+.ȈP^YnԔ6to=9xɥj-S!@uM>'ZYӽ+byU0D~O ^^Ad=+`yNJx8&W!U|3 42f Y^f 0e%\qk;M+Zd`7빞hlcӻ^^MRA)P :],3*LUIAUX`'0[k(VZ!.ЕFBq4 cuEKrِ7Jml چ_t-K{&{H 8_]S~X219whXC﬐f\3oL}m~k.fH{|}LԡNZl& ~W4Y~soǪ^| *hy%Uӏx(JE +HqUBm کwBmt G8,>yg߂}Oq *N)L U7_7cA}Y5SȼdC6gCp jiV rabX1yǔO;Ax(O2{:nS?/K)sG5]=$]c 爰3j'bXw;uzQj6^hę[V);m*ׯ *k|о룪vIR<#YM%| IeYܗLr W4p*UǿR/ټ )TxT;{:=! ;>Q1V>TR9*Fa~ݕ1,mo7")BjlOn=C]bFOiD<% "]LҸ>x}&>*D'/a7U:O]ިWzncL4\–wH=YlzWcXo.^ھ>=Ls[aa ,b^mΨЄPUh?cWBLRSXK|d*ZV/ּܐr0Hg{y:2?6D{9(aa.{L>w.ּ>Dv~#r/BKۆT$"zf3m/WYJ Q^d̷&kNXو? ;Lg<ާ:b_Bٻ>Vg_RW3wa{?&8n7ܜ5-uEÆVչ|q ?~'EWaABr-8@+6kؖ5YePn Sxy{66Jyq2%Y {5v}W{TG; u>'dZA:9:ÕORycσ@jexiP>kkssa\x˕+xi}qoh.OnHH/6 }Cרc#4~;2 _X&V:} =.Lr[Bm/,,N+sua~_؍ױYWNc1өb(H-O/8,SkL. *|#<5˾blERvvFwzNdžgzjdBtK̕l▋ҹ'huN`X3L~x^VSYfKu:?` ~l=.~HtY5ӼCщS$ ~m?6Fty[rΈꌰfֿ7 .bx7!Ș/瀗8;tdP4W2xWRvّgCw3-fe/©c%}l57X;`4sJ&z<;s`zg}=r&fOU>*!Q_ߴ{7oW9D^hLu;J _/k(y; 9ȇ!º?`ǘxғ>Gc.W?#ӟd 4 򕫖quXe%:Ptg4,^T3r\ʡƔR*77%=˱ lO@TEDGį#GeZ\䬨h$˩U*OGq7"4RW׷<Kp?zM|G:rњ6EֿH0y&|t=;3r.ȉdjG'4㗛bt4,3gMSFZ /(=WrR V2@ƅA`2g=18ߠ%Z>R n /0@5`׀RaIȾ #nV_**]NrFc#](r^m([=qW#ݐi f9Nz-.0@1Kakqz| ]tWEϪ[8 ,>uu6ÉG/|pN[[Q- ۤl Kl|9e}{LL2;tgx#{wP@ءf= ,3GaRp}eCWPf$5'0a.5&5Ff"64-%ISk 6E)L//g5lf/0yG@Kt6F:)yU5ϪOΣdc _T͐zD=nLӮ.k~MW}kosx17DS:@_9:qLjxeA'%[bwDΜ'LEPc]hX0&)m C+C1`B4C:0m <ڼaZ !xQ骆<1bVՙ#&Bg"޲>h]` w{敐@abr 9#q3@< 4#9~_ǃ7) \o7Q,tCL JNinnIf/LSfuɇs֟8Uk??<׍0N4%79*{ߏ8::_;~ܟ,2U>xbR? ͇Nz3|_ND(8v{=_?{|pŽ^~5g~!Აh,JYעSϋ4;MxL|YOFi ЁlH9v ;C&]-7lu]a:nkTAi>uc8iQQCEՙS @2`j?TsaM;a UBCXXum g(ŋW:U!w_bYsB|ҳlZis֖ܠ^m@-<'~}L>/NYd4PmTGz_T5CEC-zP'?oǣ'ZXk((,3_5ɫqob ,2éxyrQ87㰗\(;Ѵ|tn= KsYi0 yx;ډg*AAÀ{D1mG>/$׍u O\&.,4;/ALvo6y}'oӁCZ51Y68;&[!dW5vxޘOE5Ɨt Z+.<>'탙CcpY{K8EQ?zyBU~o@IO9վ#JF/k748owcȼ OY/栝@MKS 0/ބvC$=d]ѮxoyOY`Vܽ~IBZOt 7#7nH{]Ù`)D}E,=d (5=ZQ`ƾ~5L:pkpŀ^%t|&te2GϦ]giq]-D~F(L٫Ͱv" oJ/*qTk{&Ӎ8hڮD>`"E@151LcE85"O=̈́*Zv$&AYvkoGOs:Օ} eaTˬn34 g< + e%ke˖d23EF%*BE<}ĽO&1_`D'\!OV#_+g\ŬJ2y,-ֳ\:ÄFXj))!&C}ӹ_#OQ'?GZqjkvJA|d`AP8(uSn: 7jZߨw'`oNa|͏'@yQh (|vo_Ρ0[}`mQ%8 ~!r08S0^HĐSTO$cR*jo{,XoT:VCy6'9K4*ϧEȍ(jiv yyXw4ߗbZQ?ʜ-^iWF+ClK3;[]gJ<[ q[N8d/$US[Omkot@IۼWqg'ddȥqw.(v`Ҟd!Rm@KQ̓PB σ 9N _`[Td((:T!?*drǎC?^8+gmZК~&z{y?bӦ^w3(?e Ghh€l K|^?d 0PM* `y[0贡[NJk%YaZrC[zϫX7,++YWҸlx+25[]J8uE,jXǟ+L-X1marvkkm1]sO?/AKg`h+ x`+6P1_vZ4$Q*$=g[H4)k⃓@:ާ CT`5lrۣ {{n!R<8|R>*#"(q}9/(APH^2 \n^_{:^OANMhZypat[!(;/zaf.ul>6OzFNƫrN2ژH8@sQ:q7T;߀MY1A[1uif"{`h@AEEUqnάTreG<!WDѪ`y^]e8Rz o-!Y֜_?sƨLVhpZd\j$Cea xl<[82K HD@Ov LڍD/ /I4dτUIEz|s YM~oD9 QI۵FPwoj][v}w*?gS8d2ݦUz~OU(32Ϩ/LnZ":&HDbTRr#6v [OSI&N/xVI߰ -61o:ɏ>:2a3i˾B,}3 Nj Nrmpugt|ܻsuWNv|`q0Xg!E킅Y=, ׷#fQfa }AnFy leVGp<ZӡX 9;S18.!e> UN5TIxJ2SoVm+5W&@GEh ͸X=M am/P罁 'ۡzHh Z)ys݊?"{N+-yx ds[b&[Fya)(-k햓ɵpsc>yDPtan)1M!S77n7ߑ &$ABy8tjuDK @eSSYDQ ap!cL&B=9\@O*ɉ2i@kÝ]oH'A]jȪf0D8ñVeSw+cPp%X3l]XJ -6wТ^a9#k4mop]n@o@,cI^ 18H>G <WաkqPKin|*. [vOY%~> *{(Ee k5eGI 8Tx%x}Jخ$\dysIB.Z5p)B^%{/O7,z vxR9C:µNFO{=l}OԎ)N[FN~.YWκ &?)E"ڙNכNT ]ZD e)kSm:$`6rےƱr3@ilgB>C% tj$}K-MEe0bzD$^ws@])?yJjg]0SČO->W+-Ot:ڱ3U@z:jotZuFT҃CBB$BCfR!qq|C:9E{8Б3܃BK=azęOOl1#Hf]’L (4}n [Csf

xO>1%*0(2zvc {Jˆy_3-1ʯ.]P%6tF7 NP޼@d3aV>&+V 6CGH;\+iRQIt!q}#%Osӣa%ELџcx @_mi7:6zVOP%Nv Ɓ.3wh];_ڋxJجCicXCLJG%!s2nkb8U){ƻj84a;DŽQ{ɓ!r[7޾*.Ʌv,ىl"U۳~}3MWҘ41¡ae-.1{WwγYgy?ar18TE-2gXkag-DՀ")[vZ3QXݩp II'(d]s(Y'+y [?Dʍ_7P Jy`JbhX᫖b'C5=mFw>y7 dM$DŽNrH9O)r|*) wn:@d;,#.fl y(U)$kO-2 -[8Ŵy-ðO PfdKmͼ j]!>c_)вF?}i#alhb W4r5N[?{g#9Ř"&5M{_S`VF:ޞ0c%ٜ {H{]1`0Ӥ!}3>VT]}s$C&Y~UB7̵`FsEݐK_SkË/ :(Cuf[Phܜuqs;p?!]tN֊-=Ɔb$ LJqap>k9>.'7 d:Ocĸ#XR:5EƐ?Zw DžŠoFp=k{\ ~2}.)vF/R'ʟY=uDO Xt8$eE?֋iCqlR}'(Z1^~TKbOqCE6ny뚁Pϣȼ?C 1_؊ٳfAomE6ȧgXM ̉\f! ʣW4oQ ވw;~V<,xd un<b ωI H^88]E 44ѲEÃ0|`쀪n N{qw^Y삥 .8fss, aÑb)CS}\/W4:@OR9_- ?7/D -7y[L5~ѽJhfek9m w5Z Oa"dέ)ڴ, fyW:4wf ʼn+.5ȳ`Ԅ.G8a^,j8V3"gJk aY =(O#1ݓp8?)GaP9Cܤ4O'~90?%܎{2T&*ݎ׍Ğ;w6qTh%E ŶׇPm,Wmb#fvk՗BT Ֆ'{"7,S6Ա6E mx~ +d:ֆ1Kf퓊R*n32ڴ@͢2)`A#2_*G ܓC)'5N9ҿNy]*¿2yͥ+(qTd#VFs6U"^X [2"G \裄!nj]5@Mi @C6+}\ojQ"> =s⹦ WKϟiMA7qt{X %V.{MkHudIn#Τx`Օɾ%/D Qi/dvk6)& eޣ\&-|ڡ[ ̐{BM$d!xIs )P[kҭeu=Qc[j-v6}*\*# V_WSJgt*T kY p'iܱ~6 /3Sa F~WwLB՚F_,(QNF4ҍVR08m UYNk1(O 2oܘ p$\6\(**GA\yaʴ~h)Y CHҾ(~G!yȈS5kw'޺W,ͭdpX0 F3p^>Dv{y̤3% >< ۀ&(%hla4.kz I}uDڒ*a,G2/(a"rDzԝ&}LZZXiV%i{m1AIq& I\􅏎x RQ&!ڏ;m2-v]S`&g׊5.d5R1?qa.`0\W}0P&B2ڋn ^fН+;</uV7uK=GguXPuVEz*d u xxqL,;a/P/HY8fw8K~X-ᢢ}(G8' NX,/cʜQ+F/G^/׍ _ Eܲ' ޥ@OgYR7? ? )E%TDIFBfWė=C.De%["eUdfHV({dEd>pý~ӷ%K%&bxU.|vl?LJ{ &Q+Np6Dh;vcEYhGj7nO gUkG =?_] V|2t~{̅2pz"d͏)73dV !M0}IxZJ}YgT"m b=~6"WE6G5z#ˋ;b!Z DWӏي#&:4w[P|`(W3? }a!_npn!1)(3>'~ Ať5Aj17P!Vc9pd=?G3L6n8u7qBU&XV {[]l솨;g]X?rLY:oVN%1'BqG k9M\ sjiĘE)F%qO')Lf~qy⑑6<-^H,AA0'C Tb@nxr:5Mq%#%CLfl}(GP\t5ū>8N.V ~ z1:5TY_brMӣϾ6t{knK`-w+L~sbfuJ36 G({=:ݾJ\b%\AA ;Yd*`Hة0LjT7,|Z 1mtG-@4}\zhT .ibM`&cv! AMH ުo:]UbI{+ȴ@te$/F}y 70WI#>mCB ̣< થؕLFחp\"&e=_BW'` yl>zDb+6ǭA{[Ξj(Û&n7u=q֘,ss7ng7 o8k}(kP`yC'|5φlJ{M;x1Xk :{¶L˸tX7e@''yҊN'ڐ?! DHgGdWiJ{2 bIי`Rqt5M$v0nz2,Vr=o%Y?K~0Bb;YD >jk޿'@8fQU=I%!x${w9I/keulu_z(2ċ+@~5 8a5^p(:5`vp6F!Ѝ@+xӱb!6(<_Z%wLڶ+Q,fxY:?|fJ9JVVHHzm! υKf5űI8v#C (NPicM640tk_dµA>Xl"(%_GOl3KguXo5ʧ8qdƢ_|ohY- c}<[.5l^"Ϳ |SO!yepd-lQfz@v!=[ @r?;zHSx*} )lDo+=ǵh 5ԎؿyQMcɺ9a~%ϐƮ$M2DQqR- OJMUBקǵfi!r3zUu0jÔO(,C )QBZEZ n 4l aZ\訅J:Z'?^ sUw8`Fa1-q2GOHfW+c_VIWퟫ2Hcq\ Q`dE"?7eggD<ؽyX)vLjiZ8K"jئU`l ϟIh$4)fﵛt%*%k2SwLk,Ep{X{xa_kmjټE#QrKu]BkPQRMZ!OZow зMΘk`\}{|P=8=r|ˁR_Ç[`8[:{rؾ I,8sB;""}Փ~c ]jqi'Q7j2[4n]XҰתY*;|yqI 41CmZaTUe|.iȞ6/x~SUYߛ$o@2?Ou@{Ͼi[$ʮ(#+^4ɍ 3_PT: ;s$B@p֏GRP~.fk*G4AY@ Qm_%݆z:5٧ykI(٣/!ez~Y T0@[qQWs!FcWpWn[_~0jƷY40R%;-7' l&R*eB }•kI[/L;A.穀ja+yOssLvIfy `s 4VkoWnd'S 83rϸh@M|7WZ8aS@ ζ K)|\|pP ZD5N3 wJ(vDL_l)yR!kqſ:k.hKĶxVUk=Kfǹ۝?=p?d7f&$e-n}*T2jC+Ӗ"ۮD$Q,yLU# bL`w?(O5{KbJ Ly.Uh*n$A"/xFpS*%IkqY4‹㒰ū%שS=Nt)'E2@vdzWj;|C;0UMkp,U՗_y7)r"yBG[u"YyiSǫtθeK55%OCSSNujiaƛD((9<$C O;=::k7|ฯ;znNxR`am҆ܙ2:okQԁn9~coCNöj <6 1).bJ i+V][1:ҙV ,fƜ\4b3e\ĂTܢ|9)9 ˉ uN`S ƹ4 ;q8 $ǝW gVa@dݾq_Y(xbk=+fNM j^w&ס~ dJik }׻ݺAh>! }힄k{Ӱ8O<3 ;DsP|rz؟ikN_[NpagO' :.(x Mg"?C$pjv|]E+ +9zݿ^,#24QX( VeokP BCG:|C}dj[IL"_[n$ r75Z8@'H^ *8εCszܡaʗ!( ]5FPfsʿ~|ݵ ZƉx(XDX礥Hxԯn>i-3|;Uv&ysH>|iV8?l:Eʑ&tgʼnEؤyj:_̬W^<7)}Zdp^ kvWD4ܾwkExjmB ^)kMQ1@P}=p{}mׁ_!|Wѡ05"o>F!7~"Uhz0$$+{XKѶ3XF:crqhltNcQ`fQt$eDsNm5Lg_73cq^t~xnzs"A'=GK햻ғ&~j$۪)'UzйIz {\<P8͆2-Brp^ X-G7h]l'!hR̼O*Vߠ>8Tvi4g9;Yʝ&:׭{3`yz$ݶ2s/]kpǷBo}BA!}mU5!] Mxr;0Ld1ng]LVE~MfUGqK[s}Nօ9>9}JT?8!5O-^hfK' U/$;gQŴ~M.Pծ]}n7O:n%mx SL6\<pL[…}W`Ҙ/si]_l/̠5s罦:0zpC W/?H;xH澰\FUvi84ϓץ,6{B+3ov[SG/9Y3]Da_ӑЄ*%i᳟TQk D;ʹ:<hP$IK#lN|?=9jo7fMί`7w^>tHU_=i{x5yV"ԽN=%3~c%9h[fCu}Ϟ5;/+EM,LSj+!3ڇs_VR͍X_5m ҃hby[KD,`0HNoʋV+G&">8{mMf=wW|i`Dw-оu0 I"EKs{ k5*`5BaRWrL1ݏtb xcaؠKm\ٗ]LB!aPQ/Cy,Rvݘݵ&k5E#l`Iuh$5 4$c{転װ>(v~k$>۵ x41<al_*KBl^v::?ځe~z}Y~ Z[@ Q|.:6 $o;R  ? dF<٫%{ڛl2BJE"RTOpܽ!{9t{Rhs*=i[78+g6^wm?ܧ^x )?߷fwԇ !`g9,^<z;5jG!BL0e[Cc2Z{`] z*^vkt[â%NS)BP@B&:cwHw Vn?^:.>/0gr7?6J$᮷ɏpC\eh.dp"e H4 l0A"gOuXU;lԪŶa9@ҕhadLXQ_lu@y68Ɋ9c/dښv?̨-ю} EU% 4AgSC2iT~u<?n#ݎt_ |Zw&&Ij , .S 6!@A?>̍'m0$%N3\E,()vkLL}75D?~pljn}\എ(uA%E?n} A+m8"Vdm Ar%2tS~Wr+]Nh,J,W[2> 60䲛kɣ(kf/6y9ڸNt.#~z.m+;+`b\iw j(+jǟ[v!Yxn0d}sEc"\|2pG8D\IX9ڂ|"K4OA@ˇ@IPR. gsqj?FxzhȲM :.=^x 7O{u5s@݂&L&?:O̶FCämwh{ߡ#s7gɶ A|Q~yv (Y>}7&_h'eJ=Esn:؃2ۍtz$x.j rp7l/.z(}.R==ͼWRL+OЀXVDR 7U*#+ 5Hie})˽W[,񛏅y2eUq٥HIז?}ܧ71}R"& :/|;n]kݪ8sn?.8'`|!3M]ĺߜnqY9}Szɲ3:8*XEhrZ k*I8jK~rOn2Ⱥ4#I.K {8w|? <j*D}.X:J   kv9+>q9E׍I'w ՗\:%`iZ" q=;b`k*c/#c)wH^`C'Co9W(b)䉔 3^:OY6E6b]4mq}8%@ѤP6;ljaiԭuT[ӗzbiihqy @Mȋ;0f~0:05/+ȞIz?b1l[qޭ*}xehYjbO@A?AeDؿ>x]3Z.ԩ}͆Qzz@ȱ};SfE㑝&iP1,WhM| -G|vl3! u'!BSOPHiرeS%a18sl$*g(<] *dz#slwF?r7DTxuqߧ-rE?s_+N3_/ AjZ7| <t4? sMߍuGRf*+-UȟAK5mhsDJ7Ц>KI2M-E;c9{[F\q#|'#Asm gN1 0"]qˠtvcMĐNHP:.Bo?}L.˿ɣo@ZjP ދ4`>4)|L_sW5JTN$Y\MF]jYZQͅ XٌBV$t9aUz]3\˷G J)o||2|Z6%`*y9^V vqFRڦ3{ QE͓1Bˣ%mK|crˈ/lU1^tF-M N}G݈?Ѥ3XS/%c\ulppU^ +]vQupe_DCLH(ISaVu[8Yv.Px~#30 י@y}A0i e/'qm4nQ9-0W!=[D$4@f$~~tS6wnS$ LcؓЭuS҂i {Gflq҉OQ۷vE}xfkY[pa_1 1h;Ȧs}}Ƣ8udfݨZ79' i1Ѥj"pRm@|.Tkip>\ɺ3[H6R+Y]"qGѤ|Bge1pZ8Pfwof$x; PuP6]c@pedh#cm/dcJJ跨lk#3ӄf O6L76y̭dXpXq?(+[4/~'0˪pF4JñAP8qVWfF.Ս!Gˍy`GvXT2N_-)X9ޟŰREm5e}קBćZuy-c ., wVTA?톨MuJ}̺s-\#{ZNZ؁O Iu.x3N L&Y0"3,vS8Ԗ<ُcڜwd5ء6( 4y"Ǧ/Z[<>$}V[[eOrdbb+D3OkJ^O[l w,sR`m렖R<|P}i7&Zបō,ˈk"dJg[Ү K6^_YhBI'zG$Ç[c|p8Mk{ʢm2=}يjpen]"_ߛx&KW4GNC_Ep|H CGC@PYg@BBG+4z(WÌ0G,ɧ/M?[2TRUvk }!^kRI1D= Ϧ8?),k8mXn)t?ސ{4rn_مUPՠ'}8^ןI@S? dIyc]+gGW( /Wf8ΨA^t|uFj]?;r|zk8֝9fD~df3\g~TO]3ŲB`9h >X:v0f8h gzIäSM27NPJq4C.%=SFg"ris\s_Dg"VҟJ]|g+lp4"`Pɦ_\A?6ؕɧ}Ņ%jJi`?!;~+ۗI'ؠZHWᧇmf:HZk kd))vjuD_bq\ :09ŀÅ֝ǘOf4lZafڝ h;{0P2953&yӮ &Ou*#1ec ~s,"/ćHt J&o`+A/WdT4~<}/C-imp`z>ٿNF ClE,2I8Y%R0Z$MJ@KXor))gV,s άhɧU5&A/`bu!~obnesT&BJb[k{0@A1G 6ޤ)41>~;-AT":  6|1O2+x// KR{LAX:q|-j) ve Rsuµc2 όX"ߤܨKDN<7 s8DqV.ĉǖx逦[ {7Nee- &B03>3G߾ a dyj( \\9m?ˋs \?"RSXȍEʗP4ɋ*0{وg%6G(IćIC_\dvrUdӨ\L'>Al<"=Ǐ^&pd+.L {O ] xr݉͝$(\3lVnQ&EB2^EI" p&cEyup$t}]C!F9 ;tB&쪫gtS/XO@4jݼcT~٘%eLen6%FahC-@{:?~[֐kپX\UTe9” pu0 d_. JUg?v t?f S|Z"J"E/YA/W=)ߤd՗ˢ yFXܑHE DVD4~4I9W)^P 1(X:Ab՜Qc?875MX2v{QM؜Hf8d\Jxz FLZoD0aFM$vn ɞ W=R&t $Z*˧c1+`Vػӱ1+y0Ν{;+9RnV] Y9m1g9*?_? BI)U߬XG/X+8=??,t챣Ϫْ5k9p!$taH_) gBlj,4y' JOcx9&Z1!3-15< Ǐ !"v]uZ{2zWH8i{hޔl}E_9/܋]*mmpK"D|ELrɣV}1zuIB8}n B%,U?m_qԫtxq@ tՀɘ4FCؓK\c-\iiTAQ}C bǘ=HΖ趄 "' $_rϭ<x;`Y?ZISЧ\R3G>3sWG^|c¾Šv>c@|%k{NyF(6춷' Ùk$`vvov#CRU2G{ݎ zgiɒfU%O&Tͅ'@Τry;B]8>8S8A]ן`ɝ%O @VddeN1j!`+8\5 3# @&UQG Dy:9:,uh_z`Gډ401M>#AApD]&q8N(~>S> YO S &oBq2=$U9g?>^iKQ*yKQX`ݩ+ˉݩ}/ZݡRao7b4׶Gыocuɫ7s.B:wQ{d'T*O%񜝌18F@W맗mKzet21 Q0AŒ]ǗsHczj%:lT02|$?P jȗ 1v~{qA5yG+FCSɒ;BZS'C >!ooT1δt^8%rT x[\uH91RݝĐx6*6Y # E)dMF!6dϋkkd˖UHR"$oB%J_9s|iC}q[7=NlR93=r>_jg Z&#j=TP-L؍ێ` 3zیڗ_ڂ#jz[djs UxsPtd {AxX܎(߷\tMBhS9gE\8#P4p-Ut-F'50N Fׄ9I"\&6i@vVY8Yc_w=&OP}+aesbX/`/)($J(O?EbfE I/LAcI5!`EHlg> w7ÐQwyoӂHȲԩu08xooX 4.tgu=Z#W7سD$Ͱu2>L^y7 Ȳ3g 3 <= zxv7='àH$~T~OܗdG*t(8&.@& LCq[Zܳ"4NV; T+OFҚo+ q.OHĽ{S|ևd+RQQD\fT)'`3/u0|y"sxTWc#є,T-)= 4n\}N7#ARY r71W6ۅ(=( g~}rz(0X仓IX<꩏LzB.00x7(*]| /Mk'i?8vC&OM%l|ÚO#Z[eR"1}IG.\w;yr&e'P緌H5feӪ^8kV]Fy/.Pdoug?rc "^voDL$<~~ CNTF{xb燣^ v_i&)c$5񲵘D?!Iv@QK:%Ԃ&)!5cu\98NE*{e_skԝ/=`G}뮒t:Bf.*-Ђ ˽ͷ~-.+V  pxJ]}T˶?sW1$Gl_2Kr ;|wTL OFJ5*)mP?\z.LkցI#:´O*?߸cA& 0Ib}?HP6Fe9=ؾ:%jѫ$YWfqX}L[mnx?]R~\ƥZ|+-բj(a(-Į %iW NJӿ=[:+b}ypb$ %u>b]lX+Xۑb[VR$4hK5xթsAQ͎嚢y:#ok Cj}<7ltpx䤿|7$(`f*6˛;v A";G)EieOv ]Ýz©ʑSDH٨/~)mtd}(逫\x74UF!HN2hdv=^[-g4/%FxXƥa^) k3Ի*#|A%SL2 =n-)K4$u#Ƞ5U9CeC0PNTw>zs{l<58 4'"KT^:2  ?GN8k'B%vj}Hկ)o4h9SS٩:cs땍 PV6WkI.~:lm5#R~0;b,}o2GB %>ıs*Ey`KHӵV=J)GGദhGHc>},.1iR~ M#~>c%4`lO-mPU`evӷq}HMT fI?TG9DlW|)M\]yaS31|lLKl!`$R$@ $l[Y\1RC߆2@V3$U}a z+H:_C#ѴŒh=}+VpPcu`߹d&CDٗ'޸Oa֜::x ' y@3ˑ+m ~ſqELM&Xhkx,Xҹ'۹^Jŭܥڅ~P[-rdQr5tDfGK‘ hGzMdkX!t8e6ڽ.XdSm״EFMt\WSk8JeʛZ@8s%ܺz[u>z&V!!΂5kf~!w`]a<2fGp@NCm n0c꫻wQή ;.`Ķ&J:zǀw;cj~j}c;,j]X\Di\IƏ۲j$c9XXbJVz_OU;>[m|{oDO.4;$s9 +疮1h":'J桶 #4OMz@AV,FIOQʀ|A6Ok [̵ܺsb8o| Zhfw=x[ k\jmOHLGJ{@oOk:. 4CiiN 4p&*l4cŠ;RbC 7px#!Y6[q`OFW^507WvajEW P6{bw;Sd(y(f"<+cedpT },DlR_%uuQ*2pE:7 vU5 /K'WZN՚p<#R]`f.5Bqc`Q{"7Z+ E·ޫxk{@ӬV0mm9;F<h㈁ZUune _#nkT 5s,haM0e">Յz80$ .~Yq!Ix7n{e,AL>l !r3Д3 Ѽ8w*Z76Wƥm>S9|*6Vc$-J]YU R澷μ/D X%vQ\},tW~ ]{ډ>B";c "uSRq {PuLuE04z܉ULRf{JcO{QgJso*(u٢؄uQmLyfóRTH ߦoro]"8[2T h Wg^-,O=$TpP Gt\\)y)4~uh"9Q{@_ЉS'$X L; ˕fޚV @-,>sr&l#󏧀/&/sm2iB]4yq`B-9E\'}ڙkgY3Y]B6 G~,5=é|) ~hV^HA^av5~ݰ2&FM14j2pǦ|a+`- vA?8se KeBM|]"2X`s"Zi[<g̒0~X ZoK{f0BGؓA+,ih>q>ܽ15a6&]v(Q\/kf-~`lI#S>>gelka3$/"ʾhH AљҐxhOm؛i _Dm̂3&9u )4Kw=PdO7. %3ǝ"4i JE㱿c|G:,azYS\tF쿝6xPʊQ~y-b/o_pj-* #Rol#ŌJXR֦o%hX8䆸\ Igr*Df=]Hx[n*rK#(Pb3', IWs,,Ns@Wo9 6X~U { ـNi`僛OtC+CSa?EiݷzbR/'Ǜ3bxIrqZ[ p;L`_qNtNƾ}$"w7?=<䯻#7-}l8>c*U(G}vǜ/;0hsl\*K)CcttZ[RЁ$7 k;QB^Io=ko0ynip!͘|-\^qbZψW,2g_j΢ϏCA8ka2"`A VG:GK]=@%X׌`$|OUw=M韙AdqC@q^fHB9%g]]3VR(&~) +c"dz3 O%T H6+X?ޞʋ_Լ\%hCu'm"IG 5K$G#=9ahj+JtLM'kn6 `uzr4'ŇCk,yrA1T ~BC8*PLK Dޭ~\ڪQ 8j6F)BFMUUI!xU) MEʇ {m^5bИ6AE[4v'KGˎya2[}( -J pf=3ޱՌYg:sDI-t(Z_4+h.O בu\.mh7 JʰicQ_ ]KZoҬ L6S#Vf! KUcȾ;f]t9AL"ڌw5Hmn:/7/HpzjK_+'}) E۽>p˺G~06nܙ'$^wvh<8S(%B/ ԅqP8YV_?ۢ:hJ"~taǫ*:9F?)V>+%(_Ei>Hu{wt-BOru wV3J{$<̎l]NQnFrH&ilPcwK$rҢ|!.LQB^w6&CT &BYޗܤz?(`Ӽy8"q$ఛY~ΣhHzi\4f^ 'nEO^0#N0NqJ+|v~KrLD5Aw/WVL@06A7vY) # 03l%;#󐕽G =xeH4qPȨ/pw?E, AtZ?B ?_vrl@$u־MLSDLU 20'[U7-.]!`ß{Gn UE5Hpc9ar8|QF\ Ke1Z7^߽a8+(v;A>V>7x@\=cߘgP tgֽqxg?$|BuE5?Z'0j]`K!A{`ubW6p!==\&%TcjHƥ E2Vck;u,^8v3  cdA{'otqډZg3;A ,AiiH]Z]߃)!K;(PU1Ku]kѿvUt5Icq#]&!N<3K- ca%"69ޯ6qf ̌G9w`uE\h>;Umq\ 0K Sſv%>OYO?/F{'\R2s=K ?Y?%/_ âG]CjÝ^8y?aVߠ Pw oε&AetӳxvX +eEK~cz/ 4hQxA'՟{/Y C•IajSWh[Ci:{$ {Ns1eTd@ci0<->1 䊟-\=ԣG .wߕN< G_'aeC&xLWM}S~2>Py~r 2 ߉h!桾;jA0P6`ͤ7ޚg*(Ũ'cľtQ!6x,/xw)RL0'rC(q vt IyfdP5ڣ[M"ܨ$pvܰV~AKMDX4Lr9#o. ;8D敦=9/- `^ю'8 RmN( /7t&b̗GOثG=Dkpgp+N,[>PSk JN &`zK6AN[;/<;r :ܨTÅN6Pr@ۤ aE2=Cz@/8OQ,P|k+WY߫FLO.=s ubIuL0.jrYWU}urS1 (S'7ձFsTvʮL;[8ugoi\NLQܛn1JXQ sM DCO~[{ЛG U1BUQtg7-M:3_|h ̶ikǯcNC_b+|"D8E5l2S3ċrK{\ uus9(`}y r^Bis%P_G>t΋nH|Ly ײK]ڽ!~7VwYk'$@_MIZO&UBwޏm/olKM/$;q*S HgXSqPH}8[_'HyO,5',䖰xšt?e381>腃'b"M\֡ WR<0lAXHe1"ǁ)ńl#{Tn)A O8c!ؖ'ճ*W}v,SU}}[4o{/#ʾ%g(7<ʻ mRL#n {Pz z6w׺1 /So3x=ܷw3 VQ^(jA.[@(U|~{ ¡ñ@O (ӯwYJ#pZ^BqԁixN0b"grI p'4wNmA۶7Nn0Nai_]BK#ܙzݛ}pG"c&o!hS I p|\:_K]q-Ӌ,p3 n<= 'OuBOՏ;r; \f6F˻]@)b9_:ݑ٪B`ǝYEG[낭 !Lq1>q[vl,C5.sHvú/L>pxUs~@9A툿RjE&^~qaWBQ!9ЏK^l~Aӳx2G~l! h8̇/Ӧwƌqa{rR ׼^|0$0d^wfRfr |Yi Bm{pe w#ZVMS. _Ωn#oYn;K$_Kb7j}_&7-#MPzR7.D"ݢZm>l.d$=wBq%+cO ׌0d7q}e7x_Z?=&HS:AlxzҔ.*FIn]дև "8_:Sat56kٲay햮>6 YY KuaXh/mqҫ@"]2F-G٠\Rs))o |"@p/s~^;a^9վ x'o~,_LLaCa6 [0DW{ htX=)$m|Q2TkJcQ%xK߅᭷Aj HꦈVoCxx5~8U}x&jgfgZ |~>c_z/6!牝ԭE2 a#Gw79x%6 `% PޮTÏ V&PO{9]hG$QK⬅*܈žxs̚>"#Pn/tOGaQ$|_8p[ Ǐl^%6:gӭ?9p5=g-/nq"y=_p,V?f(1W@bͱ9p0;tAekp g8C9J Edi"$g5P:08`nf }FTFy`TuCnQB ҵGIR!%3E:u ϥ۞-ej 0|Յ>(zb{|{z ^ h* L4R.f0)Tjbr 'i*%a)mƲFfC+fo-z0" M:H M q`t05(R:Ȑ N30Zqmc[PF=Die[RdwQH.Mmi=F# ݟ]< %K>&[s]%m y{SxSI΁HG4Xb &ow6?T͉wWp%j0GR%w[Yh]<_pܡR!H_'TtMXن2or[HZq2z8ɽ^:| QXMlT M۝DV"y9D@%c8QM#OЪ g1\$\)-Z%Q`K6AīN:6uD+Dqg_3,瘍L_ա֢֬\тg½aKfx0l|.Mgf ATrWQYR'rUyQ+7n4'1EKiƠ M|m'?VX ɠx3Kᙽ~Fo2s=PU凣z"ڭxMEikRurB)c#uT$$bW7-F6 ĉN0dF n-&ʏŀ] ǖ s -G:TZN[q='o97vi>kljshO;uUt_[S@kiޮpk=RZFd0_ɫJ8ó`3 ,5dwg/ɠ>$ HWhX= ?o>}M$):!{3'Fa ; 2J) +=6{2*%;RI=>JHHJ̾羞ܟRm:w״m>'HWDÀ[ >Wt D_zH f|y,D͝t?&W<1I{ԁuOC73㥍Yvub)\#L$@|Λ)Tv-FYǧ@r- Uhlsэo lBxae!{,IW쎩h3jo"t]oI-x}z٠W<(9-'|PIx> 1g %]%7 ldkgg1ʎq>2ONAKK};nKT˅R51Zcw KO߫h:P&^+\drAm$e KLCP8U,sٛUgPkko!<B s2p3c!}6l4~Kր7/gDk,OwcWEYnWD=K66_a2E}DIw:E{p3pcVc>ǃ~ى_y"hTp'49n#Zt@laNv7s5zP,e`_"_0-~PF!cŪzUlEc= 5L1Ǚ >1D7hHFpTsTLBjLn^PNZou+,{ay 78yVSY׷KFGg V=F{v}{ul4= B>+{ 8$a Bj@G.e'| } FY`uK 3?v^4%@Ţٌ>O|>5J &䌍pQqV$[y+%x#ace/l!n3¢0y]xxK0j8]%yb K:ǟw7+CW {˜L#폝 ͡0oq?])RD; 7TDFJz \{/kb\n UϚ=8Qf_=}1 ۶c%>@H\I-[G@2?l NxsBJ1dT7AYA =B7N-ShWW> op$.}ߝ%w[A"{a9A$۲e ,q_C!5}^*,ZH%ٲ.XģN>/72hׯ Nb.pOG/L܆BVRuD%@'=LL[0-B  H&ɿ Z,&ƾ\׈ `ehwAe! \f ?<}w)0o.b6ikv!7 ( o9\l 6xΩ9hS(px̣=8_H@if0rU  މypΊLn@ 39z49,wp4xQ9ڭg5Q$F005h~/4!j=JM)'7SQLĹP7ظr<,ȏL(Hx?>8&CUy,8-j?tsac/c/3zsd[>{3%xHC;Gk}*c1ñс/Lm,oeb&\8r$E5:52aS ߵc K fjuRNӪ1>aZ߄NPq6Aצ[ bu篺Cz2Kd˱ȘqBceCPd7_lA?? AF"Y8g'/xx-_rg 74q^8!FOec^>/TGىれq]<TH*Zdqqۧ;> 0H= 57~_|m;\g\1WE):Q" c^V3thK >VٕC+L'c=b)dx'%ƒ5}zy#}+)au= u4C/;NT:d[ym]/[\ρ}Ф[IM"&)`K+tHPgqH>F{߶1s 2@3|jw.5fF4w鑅Yv>$^+$ٻ܋Bk99''!Sf*aKF<7ҷx+UBoZi:IX[@jSé󻤭/zdPG߾LѦFbڰܝG3qGCeQ6 3*rcZ'`2SV>7L08(%x yÜ?M0j{Zo 4vpa, Vxto;0k]sb~Ge؝4?/F_|~>MD0f㼀Ky$E@Cӌ5IL2]l9X<9u33^-IՕ羨{cO]cx2&}**L'j6Fo:;Glx3o V`wA%C~MgއyG'!;*g=V垊CQrΐOr1 ݨhVPX7BɩK_#wDtY >__ {ew_A;_KP1ם Ěѡ+0#}Q' b*3 8%(&~Bľ[pl\I:< aJ ~t;hx8qA>xe\7LG<#YW4HOM@2RP )Ϯ6_ݴ:.H;ŎQ.WapRO(̱hRO1gӞ8az:|,cBm׵ba-2f4l~}e0UbbnIٙuY>p}=fQ` <t]v(\6/EV,jP㇋ PanKP[69ҘHnR%; &:%\t: FeӇ}ȩϖ2~0u#AyްxvRP??$MShIe:\0u2`;g{g_E B<5鸝;[eY>(V\oأFԝ-^o +y꯳z ߞZL3ś‰~rA+f3{H`ǀAKwIz 7-`j/cu{u6MD#<ዔ3W ocʜp_+ V楚wΘ5q+AOEb ^ LT EꞜe80Ť&=} jhdA3e74m,o~:YZUST!sT$S6KgۿݛVw|W ?ݻ@j#(a5CGf5Ibtg/wYNeE+97}䣍[9f#gpŷq>XۮǗT f)y/\* 'qs{{ S\$U[~K%#K]PGq|$ e"sZ}p"tǝ+U1~cr9;۵mqQQ $+rkUɵtpRr1%Eh|fi%=Lͭ3PjFoM;12(V]lʜ_uKF\irn~p\ WTwLTUh5zlO.( 8y_WISu͍ Q8kbK~*%8_Nv}kHd0& ,ޟEķ򺾅Byernާ!͔Kh{+n3< JQMZMYzϠٛ_G2Gh8a1\ܷmw6*+!:y6ފ>B,t+SlDRp1U.Kh9 0تޗ? L&-Wx+t/kz/DXy]- `$+]j6.H\&Wq+Ki*P\Blh.g@&/]eGsTX?*겒GS-:-!@xGHh(~4bH>xYzFEu#XXkY Y lj(}n i"%;&^rzZ*T:^7q@[hZflzJ,N!YYŠ*IHB+GZ[@{b>GTrXXŝBpY{Cn-^=<q4M_FWezkz (y& DHpNLRc?q0hdD:"]ߓP$:.ί1N?}nJ9+Q rbddJI.(~Wp4~Z? $vmrc^E8 x~&pdbDsv8k6M-?p  oʉBoKa`7Y84f8>66YFRAi-Gk)l]`'0@!g=+NK[ V32BRY:yMF[&,&Š;߯02Bv`Z9e/tz~,r-F;f/;mL{_pBܝiן=B=HW%[ex)f'|\"lI?3Jx{EҖ.h*ڎ%jyKPSwC&^% osXn )"_Z=γR^pNO)S91n0;DMkDB.[f $GKJxTP{(&-`@=}|9Qeخ,s5骱rI-%nyD#P|:X C[)J p=kpvHL6G_XG8}pOIdE0$'q~_sMwCN[/;#3h 4pa$33P>}N\.Vܥ&pWA x$j4ryF=$7}b|)ann!{\77ROj׸9ðeSqk1I6#)JEX}jM,?{2>.چ뼪ΰuI0L~(6LD$(!Bn<i حߜ ^`4#ڤhCO~[CX=wK|PẋX"ɑN@ Ugr \[Qk#ZΔS@hSv+?:&jG8t;;3F \4g"MUsy#du9br}dS0\?TDX3"y kHwz{*嬵+U$>  .aC';@m#o!0olY'Btǚ#@|lN|zD>v{g/^DYJbl4FE>]X>n9YVZf0捿uJ'b{K7r{i- N~\ŖN%,&UuE q#!b靂0dj|]zKѾ低1o}٭2ëa6Sn؆' Q :1YMttv`)~PMsr T{j. S<0gՉ eHt0zW鈏$zC\кo!kA-tǏ՚)FC Z;ݐ/3'6/Sr h_dž:#K"HxJ'u؀'sts\N 6 (.O#E~>`oQq=vdȸ@O?Mxŧr/vDFsVXbb*d҇UA7ihNx?<#'t7:34<*ÊA)|p3u _O@tQxl.,@odx(xODj P|tHSכ! [͌Zv I+Zphtば_aJ^(RX*po_R}bi_REfnr2`@/,K+RA霶`**)xagfJ|od+5ry =n[  ?%Cӑ4Nu3"18"/#ų¡(ly({idN{ `.Ÿ㭒1}R0 = bu1EH;M=+&~^pjluYAA$Ɔ/\Dt GSN=ׅ +E'OoS~LE<"ᣜlyn00VY%-J7NQ'5ƒ/xV[In;Щ"~!pOsX(m Νaj>TovY݉e8eqr;wfBX?lQm=tOo--mᘦ*Vƻ9d䄘VJ>%!ajb+qj=d fϳMpIfeRNقai\LU -R@_ǫeO72Qo' o(B2ry%+i!RzW@+^ :ݪOn+b!k .'"(T~Z]t`q1PlRF%jY ~ ٗ0ዟ"L`)̈́-'AdPKKhݷ#`"͙MN%eWAF̫`gJT.2S#tg ͠ՃļS:=p 840 _|~fșW,V=&5%,`jeu@j"Zz`</ç/Z{9E}t ;8h ;{EzȟX,$-f_S뷽P~6${N v*L_xBV ӈ[iX]+[.kJ q@e6"5Z2p\pr 1QnHqp IgPK)5bY#о`azNӭ\VC' &I8dFgdY[GG>ڲ.Qrr8 3͆!d'O쬉N ;@\I"Yf\ϵ+]셲I-n8ܥ~x'Č's4B^Aކmc :W)t#K8g 9tqz 0Lm+˜O5=|FH˕=x|e~ǫ$E9!E{pyG:Oξr;?YBGڰ9]h!^a<|z70Ƃ-R_:6p;K,u}o*z_˜|}=Dp ߎ75`&}xR|)wLcl(.}zn%]?XCCRQWh>uHYv8 f4e2t^7GYD9 cq xg xM@-{16f;P%ZH]pWU{HMJkGXB܃ rhQe&-/yYu:fY[sP]4OO4,\jh(#v G?2`"y2df9L$9]>JךbR;~|֢J(5;JT|nGjo/0|,j,)bpoVPpHwcاLE8:(+ Z_3.L;}u!6OiX:f]9VY,ޏ]a eQMk4'xpҿ^,#9nbt-HhSHbѲM?D=6yk a KyL:a˟C  <쇳A^X3-ǘNp3THu/i͚|ر~=J!f J?/F5bWGu#A%P1ILGnny BT(|DOݡPr0j[ mmSd!)K&ϐiF:~i7NԊ3C >|*i$k} U[܇0;,y}m|C tlZZ_ΧE6MxF5ʝ=-9ª쎧[n4WLJZN]4nSWz#O#7u B3g :GOM1 H=uܟNE/瞬5 Y=T Up[ sж =l[c<7. ѵI}|],%z5vea"_|GGB/^m?5)wZއ%s;DMJ?%^ᅖg'+ɄpotFSGtUd؃g@1vOF(c㔜P-WZ(\vdEyv߸+* ~+ejQʩ67!&fLz˿ 67/QLNe o,e @3w(}}-WO`:H@A˔R՗T+ {z$S D9g 5oOxy1گLY2;2 pA.g[~hGgnv D',#^#>Anغ-` Y>oqg5<9M0S/21'usK9h'8_S|:v0xu ҖYP|2#7pi=m?|tw>mA!W/{n0gsl,FPⴻw،3k-:F+QN^_xg"LWc>fb^ֱN@N2k[h,KG,P31 ;{hvV ,̤yﺬX@qL 3{WNiZi/v͑X++hכc1řä w%snbYLj<ɋ8a}Vuim0]'uX4!^l,$)~G}W+\ 0TH}37l x~Gӈ9&%T``{YW0o*A!k16ܲN&$'(yВ!91d{ #]_eVoJs$ ;8Ry8v['ZYfmZLgGe=B ,ݰ I͝#p?qe7etDZp#T- g8 Ӱ )U"TV):k͋l/HQ2K2‘M(J(eϹg躊:&9̵s'lreY&T?Hبȼt_aя\߲A96euJl2O?6 8aaIN#4ϯ}Aݤۓ=DuLW@+ϖb䂒^q*0DٳwWn+m7$hH6N!!{|=J{ tF8ޚbri2WYvJOXX6#Ul+ILsA o ZESrw&QOPO[1(Ro;E:d<‡CN^AO ܶzd WͰ<}~A< Se ken XKHi$$']di{vXt?Ԓ°&y߲742z鷃ܥX,<h^c[gZ\io=w[L?i5zN /ǐn/\>b!l -'[rJ>g[kKYd5`_!Ϳ*8@*ePhձ" lof:x?pLUFqG$<hӥfcرďSOCbx1avg!y)k] okigFvD,)L-$ z-5n wps݁EZ,w; j漴m?hSZՏj ȧ㷾l (v"%|+&U"o}h;jM\QD:uOH%QnvˎY8 GilT-ދX'S8 ˵ux.IPg|Dy}6ʮxϜ4uH[i;pp n녔v?' ATc"R-!E?5\kJXTǻWy/ zךB`Dd &^f^ϚBz((@ߛVȚV&]r ƈwؠ~N+Xh޷(>OĊ"࣡4p r<ItosX LWuYZu}`RQG.\/Z چdQ49s'?Wfk=RU3(~ڤ! z89n{wy D.[7"Nzl߄]?V{^cw9$$ ;R4Yh, ~9&  ,sBKcyM( #ƴ-#.q ,4j0}%<67[L BaCt%N0l.ڒ%D8*xZKq U;﯁ꭰU{iNO 輽#rl~]rEL^pG):HnGq!=S|N@0npZå nh 5:pL}> :QK`RiNL&+Y5M@ǘ%ot !%I;)} B/o~.oB[{9[q{Xc fj aZ -. 0G3_dxG?F(߻VuW4Otd'PCw1( uq=XO,qt.-rŖ_I=m7|@@Q0-aBk|}XԗgSeIN~ nKo>. $Gr}Z>* 7O,';u6-ǜe?52dY퍕Z_XL+yd{o,D酝U?`a1k(WRs>5OKW6;_h́oG@3~a*%Л)3zϟ&}&Z1)kz!$٠dWڭ ԥ6KZxl {")kxrkwbkdvw5__TxXУ: "[k PD.!^*MEsx=o3KS0+h7=rH/'Z(Pe*nqyb[9Snc_&׿ zpF[UZ:nqvLGr ~0<D/wh0zWubJ4O;Y>މ;>X>>/Fcnqg}aU|.r45ᓘ<ʾΗ<\xX~ݔ3{y-vEX kP΁طM}1lC3̘ i4c<7Zs`2Mkh~8d| Q;K1 }`wvg*{) ^ԟsbΜ* 5p)&N1k_ pOUPZ; J5U[틲A^`+T:%ԁWP]nbuWJZL)nMS5Xb09$ugO=t%dywr*4BQ!&A+{{$! A k̻8sAc8=HF+3SmPѷ޲X(0sH *U <"\?V]9 sJJvp)sEC̫.U=Ց9ۡgF'b_` #ikax3nepN?LS>C )<7l#ټ`c~fȾ|y's{dpsWo|VKPUp1ܑCS Xw-pX #C,c$Y{WB8^\|`Pg͕E9\3f_ŃABbF2maUݺ틡E ԐratWNRD7X|P.J>biNJ/X뭷fn{ҨUX |j/H.Yr՞ٶaP_oǏINaXͰlF hDMlY2?'<#ml!ldB*zP׮C[0<ظ9!m!C&gQ4L"Z3nCă-ley$WӘ۲.&A$8iξ٧Ar1F\7,*"׵),ZFW oNe %E'r~^D*]y Y96,Iu,MV] 5:IR3W5)\@f`B ]U:B=h^HNr>=: LۥhBZp(K@COeK SvmeUykUL!+H60&GYd\[JS醦Ay"zd WQsL"Fs,uY"h)Vs5M8k44qݠi[1=ٴ9'@{r~Y \1g] &;̼\n*giJs4S;.OiBqEc8<:DLJ{#KE7f<HP;g$b]0꧕]Gwzf[4M6: ޛ6`,5*xW^Ͻ4"UTʳS)Qo`vYI0T\N6L[rV3CJ^h0g̊ƶ{aQ5a>ڷQ`Ʌ0Zqxww(uq:R5l{.X>ATͩ)xP[8l=f&g\Hۏ఩Xu!h6x&ҋAX!(,<{8Rta灆Z+j@qx?*mgR%~Z?|;^:umR*,օ!>V;]q Sbߎ M\w~i64F|X7n[s7AvȨg oEQKNFhp]7^[UCEƹSţM2ic^뺓K3'XkwdT}-OͅÐۡV,J3|>jQm%ah\[GR[LθP((W]2f M Cq7EV0J=U6 u W\o8g7Q01 agv&w򏂺jnKhDgkþ|\kϏ^H0wxӢ'VҿUW=_EXz+Z%Iן[r\0QJ;m/#m#zˤ.{-p\5彽2㈌w#4|vX4~sa-Ի0{_3 BrT0(Ϯi)hJx#.E&sf߀e̺$,J ݔҨ`wὯ w6(p9xޣg+}UMTg% 409UFWDICZ?uG~۔ YI+#/|eutbZs{h#cم 'g}Y(#ǬH8Z oXj^wЉk5(qh'؝VּKԸܔJ-s׏Yճ\ѨQwsH2;@02]q\M'{&L[# VᏡ~ X9^yOfdERuAԓ<։bZeo6|ṰRN>B=p8[p>dUv=M VxG&X'{fI3@(;єRT|#\|ZS=Ag 4k\/[FK5pXAxHRɰStŸ:[%4v-wj1ʳ mS^'='ir@+ ThX.͘L緵J0nUQn&{ʩ0:jJ;[oD3.Ofvw5M^ۗ##7PѥKYBX[<4Ŷ`|q/;{.R}:JipStQ^J#YV-.z틉c#ld~icXqHp~@ytv.ED@l(̳1ܿfY=ɐc2ͱSVJ)S5FRŇ(IRMJgO4'j^L3ƨdS'$| qd6$$dKw"*zM޲(BWJz_h1G zj{0'%G#ޠ*{b_'+ oxVEn f_Sv{NaGM/[cG^q@ȩN=*42[;zf n7!a4( Pjm(6W ֭>UOBpi΄oԸaEm =_$\R$v4PKA=Q>a;PM/bW* sRr$*ҰCr=G`G:۳ԋJײ /ᦃ;HngȡC~){"\0Zq^O.L0um2LKod },vXtn/V_sd!mPLmK$Hxg0=:c<-.i/X(^9|}D4@e~)-M]0CY4'0MN \*hko/]I稌8u.%*2 ρ-N3ܶ'x ܆.o9wO/Oׁb9r֠lZKQ|O=<sNTqf93DEξ/x li@>*-^(,O 4Sbj!w>ca|^2'@_YV-(}>.32 #& ɞrwӍP(}?[E0Sst.g;XR,@yZ!ųg3;7`!Duar,k]w~X+oE_BіB8sӏ+z3wC•)yɴ=w~nCh aD2ڣ}ȝDV-O'\pb8d{h̼,w.}sEd$}*|mK|*n_`- l,}iş}ɶIHΩuSxxR&6i eh0q?0E8]Wn"g_jaǑ4دEwZ8 gQ^=&de1nheF ]A9\V^aA۲p7n$z'1;ٵQ]܏nЕP 6>p+{Gufut>:m]ѵ-ַpo xP]/,"01d\ ՜8tNӃLR\n(z;vSCmn`wpU{)/W (D31/q[$D;=mn%_f_ҩ:U>YqwA/3g O8!똠0uX1*W֟+&`2-y![ /:D2|At2!T8̻R}]$S<`:铏ԝ#8Q'Ź[&L= 짰XUf<p -5edb{U4dz_Q -/DW0²^wTd Yqn$2sp 3561fLT(k׿cWGOAPA(8֍?OFߧO;pɚQF}F8?T^}^9 yDPǘP]ٖU t^Dž4`*Hn_V 5wݬYC'L>)A|kqkrm3~]'tCg偈C J>7bMA]H.` Q"/4-N^ =K%r\D6;wPPxQ:?c5- rG69n gZc0uokXڸpI&A*8mV>₱-n內n5-:#_8dif ǾdB{/;YvX4,1yjb.E} eGh, ?J7siJ1~U{awJ>[v E(_z1[h}xy.{}@B8x "WQy+|_ym!&$ՏSHܣwWr>B-tf![ _b |r}F8L2S[1Tcpb:EsFS_cKIk=|3C(X87ϝ}-I Po_×?tUpN]LBPl*&;us< Y0Ώ ބV,tٖMr7U̇7-3z*V+dM(z& Z080>~oX"\laӇjy(pWK/|P&k^aq4Q>O7qF?.J|FhpeU!ojڌiCK @LIdd9E0p7}KL\H '7qj\)sO0HGaN7Mچ<  p'ӱCIYy85o7O 9mj:g9]UdWc\lS?O.ok(Ga2;!m[@ZOwp<.0+Xq~4z ɦt76/OxnAyS=%_20?-(J90|D\]9S.%n3{>Yşa^Af jdYE#IH:h .hx ȬPv&=tJ$x0rc[SF/7zu&Vtxoz*[B5:XFg0c郻^氷Zc9l2K'ٸHW xO߸dEJ Hl|6)/! NrI5jne#f'@oКZR}.}qN0g1HۣΟ]콄+0 ծoBXu?ey7$@y)?b %2;kpAv+7ڐ(\[}[EĆdA$'rk"W 7Na#H4.Fpa5Ghf79ÜwPϊ1xR 'Ss1QΤDL̮[q m?7Nt* CaΆ1d#/(Xd?=qt@C'1sH6sTD)jP,4sbH|A PY47dG{^K a) zlU Zi(τȂw'sY 7I$я;$p%<艟NgK*BV%GEcsi Jq#ڴ7JI-2^WŗT~*X1yl$U:8N \>);=a9I+5xP[]j*'8 CkqUZYor>ScaGN/P=Ees-Q..  ϸ4ZѶ1Fm Qw -׸4~}_ÂBf%'O>nuēa7 n3lqX rйn8RƂY~)zo ^ƴ$;1prǜ'HaT:Ս7,ϞnuqexJc7&>>:yV1$z -ZL4HWo, \Bᗲ1huo;NveԮMtJsDNpZ,VqzUaqEAr?W警?h{ b^%6aG*l7 |%.ˑE[1E$\~(d¢,Dט:i6D$j ; 3Bh)JVdV{ddMFvdf!"dE![*d :>Uz<,GNJƂհ|aXx&F$CYF*0׶XX4z(&T`n"EI$}gy?'~0U+6-'|$Ϡ9X5nmU9G.}ΪX|=Rza)?AgSY+NAmk @w3'1ad2~#ol:?Oz/PB;V?dMyRT0{aXuzViGcg(?f !Z\񃡋si;pO4:^i7Z*&BКW)3'\IXE?.-_ME%h~ׂ=)?PTGEt~8~0q+BnHey s 8I_= olT/dt8:@쾼̘ v;0G%ˇ~\1al9$K%R4;i\+ @t%9xrKU Bu~!$kIPZ(m6&=ߩ!V.GVYӉ pώg.3im#Wp]jxd}Kf,Tx R~f EJt`A[' ޙ1rMW YƢb5"˯YlĦ_o'}!z?e9e$l`O{;Z,p"C&r3mBwYжU *cuR2hMX-x$n:o# a."Y9t:qsSҢt_19㹠#iɓ3s?3/|3کM$<$9ju˟2,ijğ@>< A-|קfzJ\. j4/"w{ȗes;O:O!~,㺙 :cUB>[O .CVYFvѯLžK8c=i$0 )G8E'"!IBgJ;ㅓC {z* W]\_q,d[k@ʆ=۱y1ɱBe"G0`MբGN9^"|V`矍DSe4Xy{<' Ow1fBL##L|4r)]bxA)ҥ3- c"P̜O]Lf@D"ގ~yd5 ͣ]Uńi!!XU2fRY- {U [EM2n% N*}RA]qǿ-o4Yva8~Ul|׆ =h7ן _̣i^T񳊘<QAJ\]Z˕R4,k-ꊠ7͙PV Jeߒy%k#T#5tBvP H/:e&_3P$m J1M ,r1;p k122O /== 0UsI}Wif=pC'-/.; <>?zݐhp6?\g³tJ]Ey`sI>PC/F~[ڰ,n1qG_Lw<ד$;oGnw+\X.j} Y*6zlTHY᥍ކv*pR׋Jӽv-%O*l C($?Mq0P&iذek>)`|='t^~(I:\V:n-4g3bUиf}4tgS 鍖lT:uk+%׿ivqd H6c.r鹌B6j ob^bQ,U-PgZcH )lXJyV >Q5FT䖍!b&6IzLYM+aXEŴd :L0os RW7sϵmA&?c̭Oࡧ]Ym #6|toxQ~in-{~n+rxYC> &D_Jc7WM[qbviR`R՜ {h`qTWI 1P䓦w -W픝0J/;Z.@^uۍSBgw~V4D 7-}ôo ]~K yvv\. ZUA ż MqL ePPJ$|0Z/޸4Z|YCb?EX)J(<@*wt 44W ME\<|w̆2~)؍%`IJ/}BLsU_w"G-pr]}^kl!RffQ,Q<¿ X8Iޥ4.D l!h 7V"H4哶kLG[Ibpʛdg7bE7ų@ؼT(еYGhRP\k;PF[sWXW>fIim&Sz\iZ1,pof1\jwSjY˳Egs線¯x ~aP} m}kΠxn pGֻgr琹O4 9G?/ΨltNVF,4 mL` <6rǮugύ# O39Y;.yVO¿A}Rh5#Ziiqf6M0?K*Jk"6f #*E|*uSmQXK7D,E'-}C~^XEvB>N )Hn#溰7DYքϧ%FC_t-a¿a!=O2z֬ 84j *,!oMT)PܛSqծŢBVUqn<1OX<w/yƋvS|Uʵ }%_WМsD_ ؝ȴA> r+ P'tc!lij4s+tkD"j7x7;ld{'${y p0B'b/yLkqH,j` wɚΌ!<^}cHiry[jߊ(8q 0>VVw}XdoJoo{ޟ *ST7+[ rH]P׶8Ș Ild :o6(59ǦyܰĻ*fƕK?98>o#LƝil_Z#\#TMCWv'?z`I~L7}zO 喙 eY_ދIxmƉK<2ꆌ/@ ϋ+\1U`xJ䲉d1 @ zA*~ q^~'?u AF g3)_Vt 3qA?p&]l|z5VtVߖKlae 9NU$k@95-o(7*SJG׳&~KDJdYB*Z i+2-RKyUl>k򩔻pplrʕ.W C݈Y23i 6)֜`Fi>]TgbfEAEXk4=_ֆ1Vr=hNH|>o6C7v&{q{vj[܀܇:4 [9N:}nܗj|HQqܝ&bC`Ps;r PIDR"Wp|0Ps&5r#`m9pg JC)ؑ}qC zba^}J~l I>ƅآo8RQGNuyPRV~pWɵ\9̌..ިGhov{9٧Jw#Yh9b;.Ucm󘘚#U ?N#=DwhNޫ,x& k뤫`lz7?^ H㑆di+ vFAי$P.ZjU_cI2:XBQ1_T n4̳Bل?Y›3\K4#'C2;d7B<`9Vh聾_t,rG0{pߝGP{m>MPO8IT!TJC 'a3mlnG΢:ˡ3ݏyH:3Ղ3?=bT 3xYe\92b2s"8a.e%gF_tf8lr?]Jŝ!Ð03-x}ToqE#HP6~;k =qBY( Bh(GBmzsRIU@* M0UNyjRߦ?ˋdE>>JWDqs%ogτ7׺@l(5_%|{Lv}x>u?hyI53>tФ AOJ5X]й]?cmج:X IspW-4'~?A0#n AJiH^fn ߾@QVt eKϕ&*e!WzU PU[]k O`RFKeDzN ;-*sh%9ve׷-A | x56'C]QrO/R$l=6W*pH IFj!.yx_k(/pvnTPaD!G n|lΓZP;WB_nKLCyb4JQ~ 5>O )9Wm* ~k/ }'P>!< RYRY&}ѦOZev.UfޑࢹyrI5[|2JkŖ2;ZMh&<9(nXhXbl4QD?-M.I+(hウD'>jѱDuW4OœN(xkX4-8% $B@*vE?TE4! _MAopGA5tCqlQog!1}yNTY's: Qh:S,y{LД\z7x%~24ـo%jI'ubV_ =NZ q?[jl/-spğ߾0yp T?f{*Ks:2^9mk>o eaVw1},hr~I DčCШd>D:bK+(\ cuFnGѹkw`p?| o Û _hLũH~VQehd-;zhr^@A;ww("Ѝ:BR -րI{jErbf ~8~kv[Y "c{l=xjWkȽ=W=ooPuF9f2"kryxc?^Qu eV `(&iDMޚ<k+z)?:QT\ I[,p=S|I>=QcQZP7b>iTM~1)ƒNN=KuZWhq-Htt N\̓7Mqĩ &^X)&GZ孨>_>A  x^ghCyʓ綅Wxt~u8WNce i,&l翞,~BJd3MciH27#8: g8.8. ZIN> CFD)NA^[uQ*qtp.;xg| B[W-2nPHNAD"?,/oܗ0xF ? D)t06a78  F8tAH// <79@ G~l:@&FZ,pcn%CAОq Ue8DŽX:)S[ 0gFݭI CXn#5Y@><5M"ńI.w8MW(<В1ƿ2;m&H98 YWfV"M_!KH,(]29ƕwYI=Rx5zwy Af')yЏ[x.$M%[2QJ_#Yd8lߤ/'V yݭGⒹ7 OU e<LY eLHM{iC wA9ZpL=o ފusmؽrH(8z+aEqt&ЪyMws-T9IknMnt"_G+m~DP0BJv$N~̣_ nEW_KYP!^0Q/;(љ'N6,]0cbJ;}y>Z|lED^(X']DХ@JN:["ȩy~^P s+Z4L }Ml"j0˂K~䃔w[v̟;=:^22c"!p^ Q©pK&LKf/~؏^·꿋W?`wnÃܺTbֿ^oaފsYT6E|NQ9}b5٣֗E$6Wǔ'pBv|𞆘qrŗBt<\'B`F"W5cCjk l~5ʌB;j ]fvp8- vEMqC(_sĚ+|WuB=DS>׾GЖnf-2{a挮y(c;W޵ T!ꁮ@ҲxD f#J?r#nY>洐ZҟҬ`ǟк?drQW|!]`3qE@bXT# [5Kpwx9x{]錩%S؎@'Q%Y+Xq/ vZr%Q "n/A3FG-;K/]B^ Fk w~!%Նxr-0EJw;|KI&}5I]w XsDze2EX_VL/,u^.pQC6Re\T_ >Tezv2yp٦NmThTɓDC*h]*tuNTsTΪA`mMRl}x5.Ѥ&5ZL&0+I7nF SŤ)UW6)ӪYUaW 0̴:\:گNe$ZИWM \S׏s~أ[3c8=_W>QwDw`㾦> YQna@?<2nOdؙ&-grdc$BQ6- QzwD Pb/ӑ\rR-j떹R;sv5Z'踶sGzFǫp߲v ֒gIm`lH ˶Hr7>b+¹p"Y% /bgV gjU[j]1K_~N, ڇNGWw$( cT&d#5cPxH⇌|3CaR?6> I8%" El5бWDwBMo*ܶ;*7磀ck8G:j!w}Gȩ(ǣkV,e/}[vTTɡd&4l5ZY3 77_C*1Qa:ۥr(, L{ҍ]\}xeRLe'.v=/߅-}' Q稜V u)*Ag0*Ђ%SoJ1)ԋX65-1+dO`HO7:Qd &@&ɧڽ3xnǝ?3{`Jgԕ|k'L)GWygwBxIpp"E \ A<F# _v@͵?e겪|(q4Y-z@XY\RfW' M}ժa=h'Sy7? D_蒡̳oL0-Z[ߏ W| ,<*&t>^W.`޻h4 4e^lm9bﱰw;unVu>kNsŅq &S$fPfܹ9xвCsE^4,%<A~ҙ ҭyKȭķlJziS=?Ƹs3PB,HqJoz}K!V&(H K7`bX~}~eHqRba0e^[&YTfOcf;h4` kK$ps{[C7RI8Da|bWC=Y!K"QW3*@TOXNw##qtL2 O>9@٪V90.ck rUfx9'GxD}B՚d"sa^}Vjtd\[}7)S)ZhP cCE 1b RgTH1vI9!]CIqVDy +D‘JˣgD  _ah F5bSERΪ@.tCLWT0e"EsaiU,?qYPΦ/JP(r}"V='*:eyi37Px0R3^3 JÕ/E4/"Y]`zN}C~HOLnjanBډTJ+۲ߣ3ޠt{hQ*-2k#gJ 5 |MW'ci1P[ghtp.4ۋ/{_c!?#w#30RS%,mLޕaJ`6:E_(qa3rNJ4\=wlՆ:<߳T}]e#sU; PWTQu׆𤢿7h[[2i(9JG N9OXh%>Z쇡B11 qHmGG#FÀ&^{9rmӅ> h2v16MIxQfAD1/J&!uJ] xJ4'Ooo1eUk#U;3dQ/bp[<6?,Qz-Ôw] 7vNLL~ވLM2.XkԎV)~w |u|K:z{Vq!a<{+xs|IgGgًW>'# n0 ̜GIoPo<ܻd}7}gS:9.xҿkT#ޙ6sR>u3 'kiiU")y.$XγgF-Kbl'rtvZ.)G~g]hU[/}\? I|vCJ#@7\fUsHH[,R1ly,wQAܴc. S<#186D uuld (ln|)f5M'Y.q([g ⮖0rGD#(JUj yCޡ%p.Uz M]UhWsP7:3pQ+a?ϭ+@IQ7Gԝ y+Ģ8":,n<7Gu@[Ah;&P {!~a11\pZΚRZ}0Ư{pE+^0TT]|; 3C0===9lGMQ-?;@"lqX̏`/S8)lþ8^=%ld#e+\0Aeil~Q,k=ZSv!1 A3"G~ ytʹTk1lxQqhxGH6al+܁E~R[qC?_ww;PJA1C{vy0M0<[wb #zƂ#mڜߤ{Frz+y +8|9{0I=c;OXc|CS/06a4kš5)Q"Hڞr2=7w naSCYW*m7f gXsumzsIeyٔLS)$WDZ5 %i[ W !xuf!llN ൒^A:)Uz\{tc1mn aO|[#1RRxw L^.j͝:Q zR y5={k-T!@@gri=ELzCkL֙̽笣w"Me˖P#HB/ tpZ?%v*r&REi:59I_Z_߽`m'ުc޵V) RjL #p%;DL={\j.2-lx^m`O&E14o|-%~ v(|P~ &oz 񝠲E-Qrv[-Q[i $lQ-3Şwv\mJyF#Vl>[soDs̨&d-&A?c6992 n̘Fm"\=OxY74lV\!Ρ;VGk=7m׿V">T_7泰S6 ŭ]7l:yysk!qG8Bd,t/e6#7aڨl!w0%d<7¦ݎ)hRP} /3^C͠n!q]P%m(%3bЁ.IזsmGA'X|X#~͸T"Z<}xYD!vGni5E- bv/q>7vR~MUUu6O Mm!Jw_DJ(o1bCo¿W&|:"}vb;EZ^֍>7ڱhzZy4/FY`DaZtfJ@☊&Qz6oTVcmR(%Q%r|u lűz8OxbR!_>Y a#}q f-!8FF_cbeo.2-R=C+wrA)OR=΃᭯! ]B$U{=Q~O˷? p3Ҍ8s<o}I 2P[/t4 QRO PqY.[P~Ӝ-S3|dݔrbݪ*H}ݑ`qa: g8 +d=lw!Df;#""Ml2)$}?\|9_Ώ;_BTAJ(<[%@ }J;*\ IkaI:IIo]\u='Z #|D^BeY uCqɐW9e,KF Ll1a)M-+CŸcHLԫj]r7jǾ腈qdxYzuz i>鴧9Sux9~;Av$':mAT3o]OonrZGMe6~fq4i ZC4.O\ptN]2\ݒm< ^s4@v""Tn[RO_:kXb PE*%ؒcx6f5/3>'ga n9DG4HS_0hzia 9!p*ѯ2gq`bT(a姿$6Pփ7xY޸|BY_Բ0xa*#n1dEF zolvFW57T(n#29ƚEV?zdSVU .:afa`ǐF庌5s0WRۤ *M' R~n |w XF4S^_3 ƫj')Xܠ+Kt({{FI8gqlk\ז>WrmSݎ/`viNG~lWsƬML{XΩl˵ǟiLO*}87ata&+Wu!BLpP&D6Pzvk8r@F53.9,Pj$`X4,WnIѰtZ5wg@c z!"1VHO'*閬q8 I oa\bk5J;NRRtBlč9a_'%ǘyƏ:=N9 n 8z#;ld@OA<z, :X಄\_O@M5;|HX bf̐DWTlGV *?[a$sB3qWzu|ӑn 9BG?5 {p]D oTw7abѵߖҥ%N/"މ=u glGr?!Ӈ?q&( Tc7%ҙ~|6:y-Xk#QgG_t9|"Z6Yx-$YdہQs%z0|.]{>ƾæG?hn{)Sq0sn\67jJ"ц\pxɷ/[ sS>)Z!P>te"aXkn+ 7قU |=Rp|Mջ *6ƾ=+y!}yP-rr17ͪ`^{g- [f4GQLj4!}Fvs+ಐ,ѭ|(o66v7`34ܻc&\\WEdY2Z a9tP,gd%lM}%U);OI`P{@ ݵ cy%bs^H~ϗ-tyؖx} Yq |ϭߖQݜ3mIx1kH`)v_ eA;Q7 E x=Zn4Y:O_F#m[80{Y^g jDa %WHfeuRj8`-3#)_qK(&8GE1[VɡM H7!D{|=΁ך z+$k]SMV.#[P^M)JEm3"L-?m,HNVԄ7y ʬ!0_7*~q4Opq1X?$w H?&g.9)ƻYw%$g\ZUƘ@SoR[' Ey؁a~;0l<e*3A@vJet[g H\6߃&5Ulao@Qh]FX㼞a *0UP[z^WV[ qX?:21B JXsgzr?T9*~bQVccVn]kTg?UK=dbT9f$Z|;`-/ @KyNs,~a>_ ?*F%ke,f_} {?t>5!EhG$ Юc2;Kcuۺxv|g!WϣR5/lZ >SnABltp ˅ͩmu@]QR%+S!H&Zu]߃tH/VJ[x7iE׹SpY)4E3p^X͚`1=0Q\aaYw A빠FfB_ a.kTg QsӺ~0^~>h.m\ qiSrVqmGQ2K;M@7ub mƙܧ -'AwU%A4|vF[v8[u| ǟ=d|f* ;&|*SjlJ[tQ=} g-4lzdRMWWu@A&u_Wx ^j 7ri5;4m/ ]<o(D}!S8q &:8b$󀫈^kӞƌ5#p7mTzV|uDr U~B q)sxzBW erW &&?] }SfQD0.@]; _z-M ?KZ^vK?2Gwcp̸B ^$̓s%m LO& :ʞ5Z(^פm:$ 8H)#SWEE [QcÁB? ؀TS93Z#r`n /]Nasnr|JPcڤ_#_nC\ڦ5S. +KKYM6`#> KsG Fװ;S\,8ZHs{v)O>u>&I1M/tDbH.;s-OO4; %sxSD 8rS^?-F3l(Jp*:az)[EƂRYԘkN{a8c^I_AR>/V؍nr2zw4I3 T*i^3dJ¡{?Ԗn(gnJA[0F9p0/ :^M@~Xܹ dx]{ ~#*{>pfov,vêeN_- 9m0#[R[}!x.26m_ ёVN *mp0yQ.M{o:fov8tٱu'p'HRW@z~v3 sa-m6DP?|V)e!% Uʾ& f# _%#ۥl)vCEf\rw%>BYg|EEk_g;ӐuDK5ԠRl@S"}rbI1 ^Zq^f98E:=c¢pAJtl !]-χ]~!A"*(MN`kO H)$]S3ì1HpWJ}?^)?&3+C6P8|0>=b凞cwc! &|g3+)?5]p_UhSIB;Kt"m玝W ̛^8cw^LzF 3-WWW^OXt;8n:ӻaσs  v'mp, ׫ hn 3UKJ`,N/K}59}HQ^BckLZpsg`.κ0Ny?-/xbp`ӹ`M95amĠ JsnIaDdg,ct^!Zm;1okH\ypJKxw– 4!Kh' ]En)x4._nif} WS(T6ʫ{<Lowh^]r @3stW*2lǟn״+6he $]za-UzZk\vY%wR֘("* *0_tQ[∹c427fIcPjF, >aw3Fq3+,Ukc=i=`pP-օ8AA]ut(vF:آ@pB9w[Ƒ>]G< >FޞWfజiIm6'S;rir%U;,w#( .GTAf8CQN-r *O-]li\\Al.('_8iq-^SkbXhs.[q6wW@Z}7':DK (jOB}jYVkAɿ,!dDL`=J{5l(]7Q#<=x= ((ÒyE/GMxpONjKl2ֹ}(,$;w;qs;؎Tzd;9=D@4T#}30P~qӭ.;l<4+<ہ㰗|C@KP65p+@ޟnhD?~BNUQ!zy;4 cF \[ut^||,я2]22Ͼ0O5'Ohe=Ę)ɩ9=[wշq[/uG g \CK$)U2+zddo =gFFf6ed";zYz~65#HiGG$TҾ5o{ ͇͠ #s?SG4>r{('G޽yoZ'K onG-Ҩ@.y vXu/ Y)@L }yS{z:/1!mj8vQYiH:3Pj2_ۤ"+ `)C-esWq̓Q&X3-Mq PPha= -MGbCQL* 8EA!ïqY+hkAP) 6AKar%2cs9!Z{A* XpUƊyv.Vȥdz<R<Fف<31gm 51P̉04; 뻆GAzc:`$zw> "a{Zt6?'Lxx08;tIKq -vFO9'8p ~*߻;݅W^ ̩Sx`_~ۙXK,+ZbmxY€Q^u4ZGP>~[>{'Ӣ/?3ۯ)I؅ B略{w7~yF8ۚ/]$ܗG=aAlJ(MnHH;D=⻃}of7fye_CpLS3Iֈ8*&k ^o*yl:@RG*8th606D|CC&}s`KC-ǠEAZ2+jQT;UNjAuV!wB CJ"G8!Rw+vl"YE-o{ zZ v|>1SPC3 8݉t6PB0b3gܹuP6d3BwWxO.dp^Z j8p]( 3]9Z vOq"O"$=WR ӣJ_Kަ\eqť Q 5/`}QM &@tB Ũ!ʇ_A{o6 6w|#~s_`#4㧥ށs )2@E 9ؾ=>rT+"(SeӸD"x)h=S;X_xWw Vdz@ˬ(!G¡*(}7 \\]E$ P+2q00Tt'OmJ^4r!´<,?ed~ NTn .F%%ycm;I0ކ / D=Q9!% ĉM48!2f` +Ymq ^v `WzD4TUoNT<¸&%gKЂppP@or7Xej!?6-Z~՘)1Ú-U{W ,N" [zgj~S:SW 0мƍ~j޸DzR B-V@ە}hU G "\{RCBl nӮ#mgAc(i[q}I-e!Cy_A'd Fja}uw+)==Sy':e~c?|k]P"x}yE"uCe|kjmB=-Y*{u#U9h}@$|8 Ym ! 5?K0SHD|u_^f-]'ihGgHaB qΦig eA֡# $VGQ; rq 4pV Aei㑲$X\=>UhY M.j6V+_&N33Сyi鸩2)na naL[]9Cߏ~s46ț-fN(f(zՃat,k|0AY_i[>cA*\ְ_ɘ~Ƚqc[L/ HVv~i&t?V<`zS2mb 1ǯO_!Xx04.5mßT01K~v.>GWFZWwN d/`}a mՏǰCA*7Gnoyg t L(ԇAQ$ ~^bXe2R;&˰ctα #PfӁ{mNyPQByq )^RupW8-<˞;4Lmc\`,]{<:k[;#߁ӥۓ`cK1WLW`l/4}wBvs!dQo{y6T\ICg:a,_p<fٗ ZKQ_l\/wK&_!-Ԇ549}1&! fvAO9=-B%kF8K12ak P~~uAB= QZrg|j8Uek/_;dgkq5зFG :ha눔2isN*jͿc9ҦzAħ hGzì 0{'5a [z)gMWc8It"UTѳ ]\UI}"2H(`V`#Meau4Zhm4ВvaV9ZlR@jP,0V^TT}HkcQ.8mޟkb [kHT",FY<͑qL _9xkz[13}_~_$lrt)b&}M7gĩ_Ӈ? ^J,>78G'pZ*o4j^ɂҔrFC!]PG%*z)mťuN6-+pϋg` s4*T@<مN7}H TFyؒ"&CVЪB5}h 3T'LeK@O]< [䦉åqzl-҉p( b'׋h.uY)ܣ3wD p6M5tSwyԊq:A0,#>'G^~N!;ZA/0{hczO ^!@j P!AwI0o͞,Ֆq8ѿ3;ٸ}9,O&3 yEm%Rɯ`aB=LV\P8sohod8Ttzdb.\o prmdZ?~YA{$8.e/~< MAܿ¤!5r&ɔs@%aMm"ðF8X,(rx :s<c>Y_\/L@݉/,c yX.?A?oy`6|6qIp.3q2r#pyl7ȌZ_Rmy{.4rܠ:yzSutvFK`ૺC__ݣg ,CU(WJO4n>lB@(:ХːjT4tX2l,nw-+kMt#X&AF̚cKt]ph4/!F }M&9cHE\% dUQTL&B7s^o Bl2 EC<y3V`@d]+w֥gN(16X"D@#Qo-"g>6f2QYû\mʢh :\X aej-cd$nBkG[Z5{p[7;ܴG8t8h dbX>$v~ob."_sT輿bmŽA5i2.$ˤl1٨#xW UJ,M9'9B)L}4e_5yF(hPq\y-я'ߡtT<k[0nma,mA+DFnTNaY,_f .8'ѓj{ae <Ī׷y}NH2Yh )v} _^%@CHQF]˥?Ɛ; f`շ?[3*Cꨃ9Sq|MnqJ wqcv_`u8iB@ɢbIۑNnB.ϋ0` REnq-qx@Wl)mX-{wW^>=8w3;sx鈁ui lv;<v|g :he01x6Br tLEqރkw(%xRPiN (Z%j9xqUC?;s|gڦuX3?j٬G&Rx+uec 1~pn x穅2{,LzdJ5ōBKY,H1Oٜ|AdlR%Pq"tiI{F웙|o"ey(2կv8ʃe:?kk.ˣe vgfBR![8upm c״_m#Pɽ\ݥ(V^07|s\*mJOjX+:XhLBb?$?mO&s37,r#cpuyʢON?Pn(ci[L!mVȔ jqX @0 ,.[,d–۹fge~~?m TJ,Q另VP _4XRܵjk)37ƾYw-[z1围}SNp AuR{ 1=]#&>+JE :w5%=(B#Km ͧAlqlUAYšיuk wJgV'B̐KE]S8$P @)d5ڷ-P\FzSdH! lʈR`{X8Q~ָ %Uc)T-4-EvzmtF#^4L>Z-ore/-z#O?Pl89f6/P$T0vt%jSRls,KNo: eT;m ̙Ppy jp9+1CM%caz_;Ň[u%A׃}K>Seژ18lڂSi82ػ{u 2ϴgO C66T{0m{-A厑vS)4 U5˘~xcx?#O3Wt>Y'f!X\$CoLzSj;dҽ{T9 s;|x:*$bvjыcFq#Vrz0zOp05ԕ=/ SGmݏλO^i"9!fxBX>܉ZXlEyIȁ>= $1-b/@WnY.Fn"ݎb=ع!*Cy8.~2Ks.?M`,|2\ݐ&'f!BRod1'.ט ٽAʹ2z"Nb4rT;0y><z?L%oXmN<fc9\Fows8^Y{ bC.ö].^"Z`RB5H^ͶEW?<ɫ\bIhfúO{{(JFpV$(깡<آEu0OrFI̺pyT>T7se_jOjZܽ)w/I9ύ8jnT`=)?guT7w Ws}i/d]K7ҁLpY!ԛ7 UGkPW ]8jˀ{ z G pj2L^Ngޢ'G#ȉ3ePH9[6g^֢{F/bPYi4IgpI)p<«`"˒Bwt {UjGM#A:#*vBMGNv^&C=&Io,?7e~ IWYvn Ϛ3aau_ZbfW$#sk{t+X!tk 6 ._-Na@=O ͡з?Z۞s ?o&sXv2x YvUsK棌7V]z%%p}]- ˜iWwAi/΄2@ՒQ 4{Y%`- Ńusp\2W(c WƯbAIYn?ߔ^Va;n<0 6h%Kvg>y۵,r WU.c`Κ}|~΄e5Z` Kr#5+ov.Fi4FC ]}uC($D >/к(u}:a_(u!f%V3ƃQI+yBQ팩@<5T{Zt6\V25%ڻ ` ^qלov'Ͻ^]COpBU=ἡ^}^z"8# 53<7 nhN.9Yuqo$Dcd*r?x3Ǡ2'tT[-!k32 T_w&q \v>qⶪU1X_c) Lֈm$N"Rd 'bHA- @َ:"1"S^%, ׆'RwlynP1jA tuE'.xW(G+m h !!N)C{h,b(-9@]tjj# _۬ 8)ݮD'<_# _$8YoΠy«[m@dPf޼= vF'̉_:_e QѤ!p7}PW+wUC_ .Aϰ:qWD.Lbo3, eY'GC`sttBblXM4@_Y5KGkS!7(=2(6=A3Ri??ʴs? fn1yzzE%)6!7πf̢j#9ꁈGhM5 n}lvSͰcdKҾZe{x$bJv8$Ca(iQmVlT7ޥg9ќ`o~H XwPAE]ܢnY|z`}7,䞦 ǀjz4׷ CIJ |s|9Nvv,,CGIK`O.>I/qy9w<4vOȈzRTF seYe >(sƬ~ %U6e09fYx~g5M[as3E͔a!Emm ua.c8)ߎ)Cq㮔J+#޳q4[c G|x{iF@9ESew|TξÁzAFj;ՖU vsգ3KCIr8X^NEK& +>9/8Ei%+wF7Wf^}/BIb}<z녧tő|oA|U_W3aT8e{?b;'*B= lѨ}a)#'h >-F S1bn9OcM(>~"} ^ab,/N/ ŁU |7LNs*ov;g)%h#Bgp 4[k.@kX+k'l@1C}z沲Zb<Me[j U_oW86ɣ</ \4 Z.UiN/CFI2cP+Zz52w^);8ycq+పsK1ޝۧؼj% Q}XϵQMǯt߽W$ҷ V顋.B}RB["\Wyxki`F]=#0b}Lu,] t;{e/Zќs3新uxU U\XAʤMq5:YfHZkm}! JnV[(?z}W3dYC]C!Oqg;0zNQ.;%qnL?0Bғ ͅL@3YLeRj+$Nl:bgy8HKw݀lFv樌ƨ9]tKh xěүxSP4>UDJ&MhUDXm?\[[#̝ڹW_ܲ5 +:? - HWB蟦#N:{?10fdz1ꈝn8D54K,`Iq9Y$,=O+ s*R[_Ƕn&$'|ӐEMDGaX)9 ;nG, CY{ p_әu K}o.) Bqc!TZkt!|>ajqj8y>zcf}C3_O@B @+/}~g Cc*Y@{Xۙ5D!nK"ō@l9l~ z!aIg j:OFN>_T.`tG~NcuX!ycZ1|M&K$o0Jg*)QEO\Ra'nFs켝(B#&e24b/mD9OHLρ&h>ֱ$l+)\7r|ձU-^r݅Brt#1˨|yF`ї#ifuj*hL=2MXHTD`ntom\ y^ڈ]7r\ꇲcïB7'5"|bG/?|˯FW]Ֆ7Kϳn'e%@V,";a9sZȍ׻3CvTt F'GҘ W|A@&vQ!y0J@= r2ߤ[ši$( :v.s2F?qB*5Bćun;ԏ8x|F6}*Y>?yS u&}wĺ| B ڥ҅3hY*G ^.GA?k2E ~@Б)˴|R:{!59"C^?@e֓ CkX2Tb@GKN*ip? g64K˟!ēD7Y֦Nt;,D+}or)֬vlO7@\Ήtxw;is3S-u5h!kxy\$uK0t:N&8I3_K\"G dߩ†B|ŞRQA1%X_uy`a"0 OfYM;#D4kAKq@lH; dkxI9,g%ffK0`x{嗬7LN#PKJKywXC#956>B,P r䣻aoRgA͛-qP_ 1yXaL %p', ~K$ ϹgE;u$l-(&;y8wU@NhX43b+9xg33 `qS8^ J~ a y"<:$Hृ2+n ;AWoi$\_-US $ ͠'s]mGwW#X@vvKC0زXp,oʾp aqD),~>/7J3@R5 Xy4[V@#盂릶0|j6/JyH'?2#a^`n)[ ; `6YtP&.)'c9,f\x|ԇ_?3DrO@fp,`S~z#xl yAވ$SC`n" X?'w}o*OKU#_Jopk,A.%GzhQbQ2RpDiө(U1aQfeD>S]{㷍,]e5.6Oq(DPꑳ<4*049-Q}? ;P~ N*)}.PU# ձ;k@pK ɦE?M)ku8?xTBO sRB_ezf?lbzel͸U<.HǗKwnA6Q] %)"[ȱ hA֣l̨5zf`=-EdtVvczgNR&TfGK{&Xf| 5+t55^bW>ӈ[eDnk: jo%_Nx" *˔϶ ]B#f#Wc,aH[c^D[/~_+TW̊آ  !H4SP| /fo3% 2޽dk`)c*DejGwX{XGk9R=IxJE.`<]蝇hn u eU&d ]w;ՀkL5K*ѺgFet5dLG8My3.7D#U${Sxm6O%48!]A^g@qѾ){'/ ;l>da%)2Oee쑐eMVv5_{d-)u\ >ޚw{¾3R9guX5Y~Nè, D;Vc'@Ms&4\!5SrUFfI&'F1qؤ\a%'VڎD^3 9-F4rJ=@/}PA]Bej/ LGs~ l ޕ9x%@_Gٺ+̸ Tc"}n ;,}K`c=gi:~6^vvڮ$BIOuaWS6'k5(rt{0eϳ?=3%Sgư@2$vx CͰ~޸F^k~YL$GΐRT!"6_]0LͩtP 1pa 5{@dĪU!x7Xܡ BBk1eiCФG? T21SFcŠ`ܽ׻ +h؆9֗zϝV1]7jMcq2#ϡ) mTK]4CNXJ~K+j3z4uV}p`{G4׃zes(udߗ2_CXpח}zRےdp(m^ :8/ {$!SXj4~V!qNrh$}L+ĉRJpנ*xA| kjX/{u:,ev_.a{"ʅWD*y P>^Ge?#N Om+9prst^XA?j=,.#Zz$psIhs4L}snBAP_KGB?6zC(59< \|vTY}‘:(+;da4z3(˼?9)9;q ̝ǁA8\o8qRc0>Tzw JbۇCA2ð(p3=&Kxa^yF[:Dج q,jnpSN膘c{05{TFrxRy:|$vyzWP̉ݖVJ'iYpTԃQ\%C992x@ȸD).piWW -Q}q p&M\!%}}JOPm$]24K<^Dq]%nܖjU Ikh;ҘϾV9D9o?ԅ?ޔjH=g>|A^H u3wr|ߺEN e ; 'Sq;PK+UTlѤ"# (!&qYG0|J&<Ǽ_̯B^z1*j{>`S,Uuw? nxqB 640 uS0'zTe6]K:7Ngo(zJWuƒ;H۠+TˑW*Џ7M@f8[WN W؍ϩۇ?0^o~f郂ZJv>^Qrp@65Qa˔[=1ੇ*|ͬzp3 ҧC.h+hگnV:Kʯ'*JH62Kl*gz2-:a.& ar&Jn ezփP3 {ғ~1C~CK@oF&:wb ?KLO>cex!O\ E]c=`3h+ ~2<#wæ^29EGx{^h)e9Xf/hrPaXgxZ@e3U `k8(C0 (m\ڝ+s`$G ?VR CVٕpsGo3$]3Dw +V[!ն{x87m҅#"yƻ+|`}wB/+KO"|!wQOnd)_Q=,eSEl5BҬA6 WRߦASX:prBJ)|Ay§ݒB}R"q׮[x.lN.^zൃu̕b:/t}HMjy$ 2rbmj*R ZDU&~,dUDc 7Icomd(WAoaFmX(٪ KKZkW+'gRN<|JvEF{@m}ײ`3r jƘlgeUK5sdhlmՕL=Nίb`Z$:Rת Gu a5lIi-&_`-_4i9h}VS ȭ櫪+n.@^UAy.2|Mt;FM[ JbA=cؿڤyXb~ȇ:xp'G#Ԣʌ6i @5 ]3ӷA&DBkoaرďnẃwUN_LiL̊DWCxz3- 2/5ƨj,1"]SPx#P8:aUn^7+5$eބ[@sF I_(SV2c`9V(]sz,^Cf'"1K8r?  B~|1qRu%}/̕R9x35ˀG8F5!ި%obyIkI`@_zr(\tPxԒE7=MFQ`=!WX.S9p5LNp6N安@l+ kDv( /kRVҸ{uf [Մu'<;>v%3Ǣz@bFQoHJIrBۣ@-V׏ĮA!jt~O nםǻ!tUu̝!6s S=l}`څMW^ w>iS>;vp&VcbreOnOJ>3[a6I~GۖUC1F = Fٜ7Z`@أ^Y*🨸zx3f.Lڂ\1s8[dxNO%"42Ac*aIa$H&)%}wֳs  AB~Uj4O ,y}Au )\:П n?C~QQB̷}q5,p דq̫s*k`^ۊV%_B:S^>տ@Tk^wG>&Ss~fDfb~xq/:J2j)!zY6 fk\"@QL2) m. -VB92H ]{޸`X)TwzzpDs]J>U)\Gu\¡Ng3bĖd%J Tׁ |xcya\.0U ` 5ELHDuw VVˇ~NupEV42SrAd}Ms4xn.W1z _Hjφ'z;p#e4޻\.4Ypҍo^ޞdL$c ѰN|:bۭZ%_8-7~w#W?TqC+1\mϜ nCeUjL$I[oR\=gf LPC`\dEHav_i7e5+' L44 lc j.>#j M[`ӈ澧`"{4-թs2Ir-(Rc3.ʃ坓e h?ts- 򞰕p\`oΤod(asiIh-J"~A\{eO^X-a?~=ށZ'#$ۄQ9Vԅ({G)f٬2+@TQo \7NŘaw2:f>G> 3"<箩bM!H8Z7v͐2v7v;xVX[2MIb,&^C?b~ݽ0/;9APҌvz\Nɛ-_lְQKW\ukK`B KWo. r*KVcφSYR*#ew2H +*C% G+SZ [K+}. qΆ_v=Hibyi0oj)EƗ7c~y["\ΓpG!s'ZC/m\:<؈^Ӻ m(SHL%6c뒢GRZ:r{e;q^}a޳׋-KvgK=^eǂBd6ZJhP;iwD2RqӜ<*WS1caUئ݌Uc9h87ہ*k!Ph=_9^xR OHl[vᚿ w Qap8><#p< %y}t~}^(SH!(-d={SѠrrY69+\2ei( V> g8|BE("D?{gWfe$#DH6){=1cY(d4(:\:o(2CF솆|\ZdzsKk3/\Y*Eg:JY]}5yX9uš3psWT5?7k{ȷg&<7pոr!x |w[I}:=$e8,lM4EtsD >ԸCg)jdW*_$ ^aIg_-V⾤Y{oXZ¦ Dx%[5~@臨Xs\ |I yxmH(1 Jzt,_M9 1_p6ig%ǂMXtAp> ݘtEq Inr5-~b8=!OTϢR $5,Q.Yhe1 ߉S>'=oF 9H?ʝ^QI>%$3U&yI?ÉƦ$lڊrU'ϧ3+2Tڙ% 񐿧£4Q i~R+]QԭڱS2{/:&u 3JqPvv+ NQE vJy(nBDbޭAF&ousȇ+T;r_#6ku|G(3d?D/;\Av$NZ]~8KxCʪ9pqh}jhR##wogBj۟!HFtu9?J܊zT"Z1r 9|5\HF fnqyhטּ[tzj=!rvI/B;x[^"TǼ$}OHDB}TkMep%ž/IVp"`"1e$y]kz;]-=͉ 9R jSZՆiD{DŪb[YmUU+׎𽙓H UB aIEoڀp:V3]ZԂXWe,P}+~ʪİGk)%aɿ Ս6px?a_t#m'V10B'tBzWi2b<+mX pכ>Hg,SĒ@PS\x9th<.`7[Yx>ְdoaXˉf >أMf4B|O}Lm4]; F$'}< j|]]q׈WZCKٱnVG)7M`` N0, /z3"k@9NLtlmrÄز|'u_9]ɾ}-|_Ϗ``ɘD[)̈́ N$O个AHW h~_i褮,j;cGW ҍ`4ٺ⋩СVPOc4.xˤ,OpgA֮~t)VZ{()e ~6'ďՂGz5?ɭ`u>]O P6~#v3 xna$θ!a .}PۍYBD\ tK'usAKe{2 u͡e/r_3%]iv.@˒}Q.TƤ?Zjb~/\&Pg"ہ+^"XYFV"*pP/Cjs~"1TXܚn`u1wkonmu( Q@W=X!Y2,yud'VGKIx?3 _:kWW0#”. },nl@闳QHh)3ifVߩGSYȫ~/oD%ǣ7 ^"#%85z:ɫ0$Qrwsٯ>F Zl;-MJ0R$R^fx0V0*3ck?k5Q 䴮wTuDh'5Ao!1 g}.0)IKoC7,T;7z]Tl~l,\mGA؈918P?ۀd_f|!S̮}}. 6-+=fSqP:vCٶ Xr^) k75< ̇ 3`N93 klnFnG? —֫=`Ka!2;ʫepE3>X־H߄9,8<=3'Dp'&rl)amv&{ XDL0F}UbǷ63ƿj9&Mo׋xHC|o| ԓ/OٽEr4w; ҖMLP[; ϶W5柅@Q m<r/H 9qj?vfwzhķ֌օ3O-u{QO< 򟋈mCPaqۿ tT׶w'=ztg&i.;x9Ь~.r|Sj R P2+ϴbJVr5ܫЛ|`鱅td-L<&!ё$]r=W8 L/|4-3ȑ$,nA+dra8Ӏ: 4D։pQ˄Am&h]Yp*z1䞗ƢZtpApdB}T:0ca$;) Z8 dp'Nv)9&ō~r(I-Wx]S. Ebkgr!'>0U^ٙ+$ >n6–jBOTJ\9KSc҈N$jO2y[KSTCWo{\U^"UJ}P=Q8ƜZVk/JfaM" 2o|dU@%t@\ue髺:cCv n![nNЊR<ռkd[ui݀A~+";# Bv&Op.(kq LHV: =1AxQ8&A]YxZ'I<+"syт4fmV$횅fp9Y KˊKl'` 4 FHߟqHЖDRmE` Skb&pz$ / o!*) SI>cꡝ}:9o7+уk[pf]%ud oX&@Y8h0:;jK''~3KiFIa&jܝ4냠!Bzq)eࡻY׭z^H>6 a7 xz)5DIxH6|Ѷ%w;cNC{G77vq|G袆O/Ds~Ãbƽ>X9]Lv\jqeS?E~@ } nEL-J/e}ZIr y3 )Xj[!2&` lnH6>\xolWΏg#w\Fj1@st"8yu*Tu:mf嚮@l{(-;E^Ծ25tz3P)xGG p g m0ã胱Â9k>G<C2~:T]珛>PS0H~3ȔRJi4&t.рSKpIps%~ `} glţǺG[yFs,v/͹4)淾55y#r%\5* S@q| g2X# хb5̾ 1k#@7 ;{ t^`y= yY6{k@'"]ubOȫlUXs-{ YHzG;uJ[ E WG4 eaH=%=D0?-ԢOy!*뗻-S%@'k mNG.EGmP.!'0q*pDd^o#\YѮ_yl,MY=4B~e"ڿw0D+_HDkMWĪG^ʳԫ`Q0"r3a](?|{"(E{d A4#tXtgE\\KG6?ofC>cR.,fZ7#GkM+aJr*x7U$nH|hu&#:C7zF? 4ci<W*󔎀˝'pɣ3J+zU)f !2=wv&Xq xNx\cb;Ӧq8mX%/LiץAopYL7gig=gB"Le?we' VWY,x\|8 9NCӢ[4>}5sFQB<&2q ]ܙG$3Kj !-iw+2@AY+atK!10;k!my>K"9◦ӓ7.`ȥ$%xS/K`}vh|x'zWAd0Ɯ0 J? ǜ@'di ^QvNwr0dNr!rֺO;_2|,QY&HY0K`zv@+t ̹NkM&m d4Ow/knҚ Cq8G h]#>>p!_L&xG'\Hr :àΒIսx h{G 9v*'}tLI"M5@J?UҾA$p|YmS?,*wAQe8^OUG1Nx\`j |L (ݟsps#ϳq6(;2R o3y!vKy(]Yu,\WI׻~KdKA?U~1H)a#jݱޓ(`yy+F2e~I.6nҪ_flP-@Y{[!ܨws<@5 p5G ;k?9 ]Dg/eVti{UGv&9Qˬh"~ H06ەC0_% Eת (Nsq8L?*ǭF ;11rnH BO4 Zy:o[[G*ȚnHg};w"[\D8£ۼ,x,ѡ, Y/kBy)a0(zf>%H)ܳ%}SQHE&E & rWt0ҜIeM+]%Qczrrc*-9nFՠ_|G0$/7bQ VkEZOR0(ECb3x,"N`e1SKl#5e \ jS1#>ZlU`-i|7ʜ&GiB)-i!d@RvWu4'zf/iuNw%~0Z[7nM@_q(s5U6H[&QZcvW/<ѝ:a|)Vlٝ9^l5 {pGxdڇVqwYxi$BW.e2` fy}yvȖƖ@`6E~=&\ w8UǑ-Y!e%(d-ʖ-{MLdDdDPVdoq;T9{|_WҶc].boSW<~wd r\µ* XH•S>XN(;Bp]u?._jfcþM] q9,Ri N.CǿLzx_{툃+*b\xx-5~k oaV!MhcV["H^}Sϕė@ ?*I,+c>]'v\X"z98m#^3"Er1]!|8Ι70\LnS7'c Uk/ph%#>de"4Q3g%sz-4 0Sp!3 ,z`KVʙ5]Sb2I"+w0 #0v6=m(\#;x6MB ˞^xu&!8pƄArj>2Suv(|鉗9 b!0]70Qu!,0[?(0Eu6^ b07 TvNhu2]'}{cUn,TFPFȲ;>{[cu:R<_rA)?։ubF9̸̓wP~L4dV;غf|/69P*j oc_BSn&Lw]H:Dp :޼k>m&ceAzڮkxgMLXODk$̣HTd1Az LO&+yVmp.kGix5W.؃@ ې,0zfS5ΨY,TW|/IN+BW/ \ twr\ NHc3Dtr2ڜ*/*+6(!Fʿi7f5^-jgm8y}᫪g2w|| j{^Hgbw> `ϛK^Xzp2_|` eԊax4|xѹrTQ"5+Z1.zITϼWNtiy m3l1` 8ֵ:H`zDqtQ!׶ 䖓88G֩e :n\Dm='B\/1J&'/Z?/@Bo,ǙSEN@}#`knOEû]#pKG )}+HH-5L@aj֔֏:ⵀ)|2 $Ptw _5 ɻL5+=Cuw$ֹ}Oכ ӝxԄd 2*i"4v_l=|~c ", !ňY)L(4n2} fRFR.řj 33X=gqzÂq .ĈfX1U Żfhy%[4K5?tp+OadBm%)@ss,gE:VgBac0tpr-ESYV @Nkk*>]?f'4 &@LN$KJu3n&f4"X(QTV=3JY@EGІ ΰ p4={t%[yy#Ot-@W-sɁ½űYĂRK\.쳧>B<4ugc݇7#wmMٸdZ Wxߠ_*<.y2p1"N>EVeФӄ\lw=[Ꮽf$Oh'j'ꐧPҬb7o vi\k\}Th* ti1S M-SrK-0wI Hj湰"0KK0a)/]~#BRp +$X̐$Ӏ-5" 5 ⸫$H#: wF'&Bs9tY+a@>@]//OgVSrU݊ p{QA7< PksAEZnԋBHX]lou.(A;3WZ7͖TREnP|o^SUxeF"$$fWI7Kx{xW2؈ SUN˵7o'ѵ [̫y,+!^R<<=XadE`??:wWugaɆfᨙ\f"4am.{.[Re3S~~'`D,]ȗզ@qEv悔c7F(D)8mb= v܋3 AozK]rqh͞df}y#?6 ~m~ᨖ&[% y;F:h+y[N>Bk'#!kA6 x'8'>6'͛gQkUO ӑd;hx~Eܒ}*~$9"c;?U|ap?Oű)2_TQDDtϩA|g߷1Tî05ʲAUt}@)bqT:¶Nn_{}P>͟;fHIr>*9~ԇ{7ګ= Q9O3h?p{gIsswOMw WU4N^e雖4.o0bT-UIWcw|u`Mhr+ܕ cNraZ~pw8?Aʹ_ң1m:ff cѧݵid<ѩMpݿ`pK3 9}s bω.̽,H*J Z/r^JCߟ̀fdtX(c@T ZIEs&H{qFwhZ=OtZץš%tQ𥐌_o-Po{IbG]qף .tt<lQ*;ޯ@{֨s}{N4]y]j';Hê 3Q']qб6qF%c_MAa9cSk5]Q|Q2ѩ JW$yj9J|3ᠡ"5zO$F1%Yj $ļ䦲a@L"(YJ@Y*VH\ mV^ԳGV\*^j+Ɵ⽢G3@{ ̂2XVCI OVBA#Sh7HUzʩ$ (b_~ %,/;z!w̧Iscfﮇ/D+4O1B1p8>?b Ls0ޞc}|3CEKH*0Ug 3Z3F!Q¿(0ĥqL|04rxOp/Ҏ|&ONbGYae_ *cpe]Vc`9B鳣_YDȵ%? ~NI>sP҃-BK;_!莦ZQcMuny?lh{xRHuE _9Ej -#̥c[ᯐ㭒B(j }jJ 4 Q°HD1"8'mH<=z=k/JoUW+Cf;R??6RHBjNc4c0A 0PᏊܲ~r/7b (#VQ7Y` {!^)SicW`O2K g2N&C)eB+&9ЛN Yۿ~‰kàe:l}s&/%+aJ?4NiC2C#04HsD2/4ZEŎ>}<ʆ/ pUlDE7o 6#QjÊF4};GY\̈DNތageJGX_l&C[AH4Ij/orGǥ/ ytn0 ]W %x$2 m>Z7 0@"VKc`O%<QDA/t!J~[1k`hx4)?]fOO@aL I.A2&Qr[2wP >A}Xnt^3O! Nz@+G $sŏԻAϼ |qtl+p0f(CoFmVI`ϨH)vn@& ʒTnQ ֟~nv; aS™ -dH`y2ŽyA &4që0︧hBmV֢?ta3]$`m2TCZ9ɊT2\.-Yސb=_m?1\P/!GWU``Bנ v.Jevd5QRZZfs2zdhZRDEebć~\`VFw(i[*iɟ_aq'$V`3 ޓAPT}_1&.գ0g;;'Ux@V )J9i _b+ָY>۬i3 ni e?n1n|ͦtdqj_gL~)FIѺJ= j^ N{m"t<5QɬiZ ` E_(a ^}&&hwvGd.uP6W:MoKX@:jV]D`wQu[KG\zC֏nv+=#wG1&,f_Lۍ e lbQ^H%ʎY`XA\zk5)JVF^:̼)n zϴ-A+&n6揔_@/n(ml ?ƓPSc>>A64nyib2)8qX*,gD{|? w<RF*!lJ'#2,̌)P}2{sKB~:zs.3xOCf[c9p^eMh =k6m61;Pla,O[;} $ 9+~"CP'->B}Xs &Aq((S"q|O 6jD0zr5' H%nЧr1rY响Mϣq7y)\9p'9;t,Яe\-腕"y(Rf?mCq/e;u2{T"@B=S2I#Jݟ|vlI`܁) ˫y< )sqm#rytSrFI"C?b `X~5&av<T\s`O%'— $8~# 9d#Ao K\ ztȊ`[꽚L9W9(a "mCW)%@!S uHV}}[eרqqe7 v۪$˫ 9Yc6h( 2aOKɒC Z_DP?EsC{ڎZ~dyu ewȠR`ڌEd(yϮ޴5,CK:$!1gX*lucws(%~5$(!,iѮ:y4=G݊H]@B*vSpVN 4iI;\$l7zCrG19Iwh23 %պPx:|u  ?I_^ ' $q;.ZJ zDl^֦ ;Ӱu0e/pjˎEݹ''fG;QNϘzKVc {&V4/66gxIHF9zfLI Ytd|a[tZg29;M^h*-f_D=Wr3d KR;;+-<䒠;Fy׃L;umJW kޫka% 2wQX/g:? 5ޟ D#e$mo)D|^!B_ݱкg@O4}Vc<SCQ.`0O>'T</.=P}vwݰ'J, Q hϾݳO8HNz9eA6/H>w L!/R^.`=gz[} lAƾQµ"k`fUsicjn@2=uk=di{3Jal2@FǦBqChf2FӤ6&/})d-0ف}e Aooʆ-$׵/KJ%Mdia)[j$*`0 x&AX ?Ծ"wf$H3L_j%B quS |̍6aq͞ʧsQl 1`K~0e1:d0Pm'CFZ,>IiYcJmH`'jAG h%ޝ!ǵ0xL /*aC+L {88E@ؼએEZjY3P-q 58yS\CqJu*7,s9dЛRyE L8smȠz: /S{WN2|R}ۺls~DRHPx5K܎;oq 帔ț~fJ¡-b8 ΰI F8H]OmI .`wd8:!B ݒ)`|vqG}!=N}TWOwj<.YǩhS9zg -  UqW`й"0]}t@F[<6_ie9P lŦ῰5ǦgI(8uqT-/aQ*xfT,@ٿof^mb[9}䚅6-w!6p墆 -89&8GA+O_@"ahxr|8$`|j]S7fm c XwMզk)0=rJ لD-9~بckײ۠ )`[׿`Mb9z{P!}d6_T/Չ0toWP/?ZVEWF~2Y^un怀{)zx|ai4[$/"tEZ5ly|u!|CvsbO̮6lMӾ|C-qJ2)UqE?ZKвPϡ:XY se[=nK]\RS-|X^ Wp_5Ї+Krh:{1=+18]L2#g܋[9) g@mGW lGxRdE43n)!5_.^:rQ .Vz^@0-oYoFTB_MЕڇ\nBYtCÙn  oY'a@4b341YJ; #qiwV?vsΞ>gK#p[1 [knͨ/E$1!_tJR ⑓^5w`œj֓Uy2~Ҳ)2y9"/Ywd+eG'.MI kԊ{|v.wPQ`ߐa|I y|f cNI/@urb,\^r1s`?TpظEK`Mƨya'kEyv!I2]Dؖ6u9"}cf6 ȧ@eR?DͳeTWrJA\$Pf s63$ 0PxE!BrAzkC)*t$pd[>ޯ&m~> Xm>&bd|Ւ|@XY8fToO`q*O/p܎AЕf*Ub gV'bAAט# DH.oġL(ȆWY91{7cYu4Ҭ$qfCxV,);ŭdpx@ w68v1 ֤BJ^ʅmJ{<6vf(S %sJ_=##W(t %<}(-֏ iES;,%7?M\8FM~dpt#JS9S)|l%K4Jq9r=[B@Eq ^`e&dH-/&MQ8uxV0\ǹTJ3r"sE^qFyrؤys+ p>dyxI5"ȇc.򞬷{"Ka/sޯPT9~o8e듮@F-=5@xW;* =lvn\8YP:Q7:rB 5|ApSEvThӑhHDg6u"irпtĈ4$&8N!nL:t6"42~<;Et/Jnk3i!E<7!AaN9r]@3:GwJS!m_A*7'R${$}oTQ)A"զqNRB9'I7: KG76Ax3w7\+pC*;'#UBOJ:FgBɛ$8~̖ۛ!:&v%tkv )!ٳo|DIf3+z)(P`t1Mn{#l@.xen;8E{p0SvW&*qB(pWILBȶiؖJJn`JU, Ep\qx&';=={!lQɛaB.WZ_cJeω.(%}g5$BUի_j?73"tS0s$,Ծ^s, tJ̨7]BD0ڼ+\jq@mw>}lDp_ƈ\jiQe LY3aT+ZDљc'*UdW]J=G"-yK=0 zQۆߦkN$0tt{&!Btƥ\ 0]w/|:%k`qi8@~ 6Wdž k 3>(TwPsO5愜.|F]̚MG٩ ~:5n65e!ݨ_6T%cۅFhDHmpPOSđэ]҇ӽZ:~Ed6Mn﨎?!{H`߂~oDcDK{Qv׈b*>+ s*@nwc`b~gC@O8Oݿc61(Flg- ?@a.*oðvc;0U> 6*ǩ[BflnX ~5D'p9=8Riud@Ocثć$h"3?aWG*ha!(|m2F#Ja@,KZ`~[ g-m|qV+8mZ?;XG]8ojd$|C=vhNVt} y&Ⴆap+rSY/A\GnYX0[::v cϖ3-a` _G&\$J(Q9TehK%4Xph{p-=R\Rqɬ奄=F{J+/91h[O+YyCn  h1X#5 {sbJ=L>JPj|xpبЄ0~,IJET`n*jI0ant-8tqSR @=OS}^8 :;?7$M, ^/@F)?\Q삤 & N>I3QDx}dƳFurXoΈϓ>Qbʸzfr~:=u:u̔ Q6dw L==*?d3T+Pq qMS_^+K@^Ej0)A]îWM'*0ަw8C%[IJ(շeFʩD%QRlRB&ed \\syݯu[Ki^q?âؐȔMga^Ƹ&cZ+p$?V@zH?( I{XК`ȉ&QFņ0"6ʤ4|E% k'՞(Ʒ[H :Kjp ?Ńxܵ9n݄ L\dkeM6v6XoH,6P_lsH[e.6dZBM>7GWwI!*SfA Q\|v|d\G~/ZP 7L'BgZί"7w 4xUg:7eG\턛lMi>rU?}@'9YTPB^Mg?߇괳vdLxX|/NLW5lL̽W92W%|xc̀q#(X?諎=;dXM$^\"N+krJ;ɟךw7Oz[t9 [Fڴ>%O[u͈ѡw|HZjWa^)MoiNƏ'![ KUeqy/~5*J Ur{ 4n";cnu;oqLma[풇RM>g KĭV2bu@.*ޯw>03h!z|=ZauY ^X lZpo]X1|wTTMC_% ;sPQls!4g]WuE%˫.#SO_1{(*s$cxKi;wQzWaZ ߣEٹNi7liŋ flU,m9$=.XV %z>歹S.n+xVy78#yCް7l(Px{#ipϽMc`~ ][zfVбbetWZ –ʋ ]tKa`;:<nU@xYV\k`"'MVTɏ L0l=uwCv 5=r *'H.Fh1@9^*3}kfzB\Xѡv llwJ$<ݪ?CLݺ9JCQy :T3|3:="ZS@YXxQF O3 nkɧ9ne[nyF8lҶѺ(46MAwg:7N{%fᗿ*&RvAGt&hX-ɯXs3 Hfas<[sƄI=&%.aB^v 4+Y9NaUm3zhC&zeL,ErlI3іh (ߩ%7Wp1qEa#IZZ&Qbl^o{Oy"YL1Kaa!?*5sLwwf6 UW֤ıqO/ٸ)2t$J]ߜB[Ȏ !^$G}OrH6IaB?a &t.rq΅gO۹{L0{5(ͿL:M͛~+y(1(8OYK;cO)"J 7>Mp׵ eV:b}+BZKru2q+(b[0L``(7bopRy["ToB(-aC 1oxh3OfD^ _厵6Ty76ĒڙyOx{\n<%Pu?LZb-H6=tָJ[e dReaT>bS1~{xsW!χ/#3kr&$miouRg>v1ܣ^ W`!6iYA[RGfF\Phy_~uΨNn&N?D5Q?%g0\wx7$ B;~Y*T(?QWME溧_F3}a?z@.͵_^+u2} <ΛvWiK lW,l&0wRԌ5kz}oRK3x>,݋SX$9Ma`At-w;? 򗹙;F0d8ʌM@y4.͞*–^QJE+zQcB]l`G1*GԞ?GG==< lɧaB:}*+p);~-'~1!̦a纍tpvM eZw;Y&엄;N='b%0ydzo1p'lc5]33b8:zg+ ί 4̇N#:o۾_fJ54Ml\9Cxiign3I& B(_|:T,VDjTt %jG}}_s|%$ ^a RtI/0Y\so1ѱy@=8q(8%b7VX0pi?sm|o-L8$pkKJ1Xxn+ƶy,\Wgʰ8 f Y,<-ӑcdl(G=-c#@YnsSY6"jN09gX_S{K ظ^l$䴹|ukXxXkTpM◠ ?a'#yí*p)B]geveC㨛?ÆջrU>ΕぢQ3qn3hY?? r3/j"%!7/;'Y/{L7z`}Op`?O`S6=S c$ slׇwߺ } ڍ%Cvc?oMv#j&F2Ot٤4ϸ]D;#w~E=ùI֞3*n-\"1tdߍlP1'VՉLs UWBDl4&b d"H}qY G'h/q"@b>Mv)qHi@kd>''.nmw5{hȜH;).?{Q)7tZz moYWV.Y7rmqb[$lrW%E+mo6j! {e wɩ$rsËOɁRyZL%wIm`vI#] Cձ3(oY㱜V^Pt%w%ݮoc03^奐N|\~8myg#?('}WK }nrOXzlT 5FJGֽEg> ɀƦȟS /nR˩kꋮ[3 mؕ@c":>0ÎS9%i&VVy-pg##g9y7s]_$bK8:n$1r7|'OsB݆(LmԱO3۳VOQp3V75zR47rl x|d RJvfMONE Vr9zMI4YP F"IS*ƌG(gx{'} QDB:c=gk%(/\M TyUi`6RI࣯Qn j Ry#(47pOy^b2մUk8>z=Wed"&=ZVK΃3HI1%?C,Lzo$6z^X~oMԋeNfEq. MW)mQϿ@{yȞ쭁Le!W+D[qe1r5y0yDMo+ Lt#d4-F$/J՜$-{m&DWZfb{.>#pt^诉oõ|:msToYƳ 8B2ګ4S*uNTVy&[^GGyݕ=V%oAbMZRtLl:7XQavտI9K1u\[ZTI~2F@ğC$;l^L5Ocİl 9={7⏻:aݱRqZɯnӘTB,̥Njo8\6 J/슏ĿPO"b洶zjo?f\%MS]Gc$`n0j%E>_ybȚe[|HAEk!#-IhCU'H@.-׎|wZF l΋.  ؤ["\sR(x"n=UM-X_;"n|Hgz;$"^QVy`ϧOqכûųBοae%ԧGp2t`t5'oӭi(Ov}[Wk dqB/7fvy;NݖG n4Co?"3cfE.8yAvճXe5;Ik HY;޶LG^ * 1nnkzkk)*syG^63q(kSf"9X]Y!gm/BDZ6m'Hc.eo;pǸy:mtō?]I-xOEu{ hRQӫ!D/7g:ompȗ-L1+i{E(d"tHذ KNda7T[z;$/326GRFY$T9|6oN88oA 5ccNe˜$^OTmvI$ ObA:I< ̫prW̷n6Z[ Fxpn}6Xb"6l;r frm%IoD,$?΍䝂:c%SP6<;wS9>8Ѩt.q:eF#&l"6Hy)kM]u1v?/-ERS-W ftѷaI^ǣj){|I5px5oN j:Iʅ?Uqg}r:٧ w RB5]hJ j!UJدFb j=$I;Fr#qB@-_6q6d~ݽ .G_%^%LZ9uňM2nB`#Tv=v6mRށ.oO{RD,zJjY7txp'ޒK+vA 4yc0 CcxLbˎObr_04x|hN'S'A4pDzr83qw%iqae?"gFl5mw1=Q{9myN{'h.i/0u xҭJNT7?w(JzWX=c9Xl ; dư/Qy|eV R(oGc%5؍ Qpt4 a;#H}8~[CbWGVCCmϯcۏa ++'yN;WPpo A`|r O] ,^̚`MمYhSEfnЉ} 86ǃ̡Pv 2L~ETT26{T8,65$΀cxNȞ,6*.Sqi/ OjҩHnKEMmGwFwZ[BwBXpӾ9m1w4DӾ]|T(ڴXN*"$:AQ_4 ~ҰИ rͧ hx.&lϠO-|wQ4PR,uQqv*V|VAoM{Q[9.IąNO*7M@ûqanԏ[Gz5D'fb;'Zĭ`9(^y6nj=rIqԀe7jh'>`J$H*Фi⟢r-CXrk81F${  "Nhh)[uMXԭQxH$7+^vGf^_Sqpn.,FP9n:[[J_WkGN0kJbkPS{kRPEjQ%TߚFEE'"7Qۘ`cO™&Dj\]=P[lu⫏_9?;фΪ>H,j SЕO/g'Lj|PFa2υ9ȏi6K*)oLH+*@ܛ 7a&^}M¯ū-'1Kn &7ã|v[ݴG`2b.GP%%'g&o@zQw"PV?|勣0fBB_ڎb3k55O$0}C﵌&r (3~`a& ) %,{c/vL;P҇FC95w"j3ɸJ޴c "Fqut&1ܷqzo eYgio'}y /LdSvs,j֟BKcfs-B/>l"cL|[^ ǻ"uVI#u:IA5HaX+8;!^O"iVL$rsZ:5P h#tg[e c-1a̼A _h}.̬,:eK撖nX/_ vC`3mu^ۡd\ |gUv#`.hJtHPu#ۛ{Q0'_6W% ͛ o92zKzl A0S*մW) "*WwduJ_FhQRn5|CH%QW+`6%2'<@MԼs +fM%H>6`L)z=fk~E Èvy'*Uua7 Mo\HjOiQ,\|mGk6&BAPFg)` x'b8W籲wIDm>k%%L4^;= VOgRvi믫q|I\ҁ64 ',9VIU۳V5YD9Zѹ-q`/h}=13w1ȳo ݺiHu.y5K\&:}z4|W"~]N|Tp֟CEbUt$}_Q&=?%Et. Upe:pXA} \i"V>T b瓡TS 6RQ(AcI8x45[ҹH5\/:WsIXS pd(}ՋpƌzQs%Q&ذ>yPТ221"#KS.JOli"^FS*~ugaB#$l_37o<![yw}BItw 4K'=EUvEE3oտVT#:ݟlo2iHNV;J!"<O| b%g—Jmp#u47QϭYpcqoAZ!mŒsyP0_eU 8,wcL7a=ۨLY h6Lzْ^L<:׉(bVp 3^?aEkY߶m6DuB 3+!zaytO}A45d=@Ѭ'J8g [ $*%ށP*Zit:Ė{aGc`HxQ 9"ECfrj: R+^"REHZdmeEnYJc"B~f[U԰OZ;ε?E?>J*eпpa\yMVÛ ~ Av*.^^]"cھ*|$$T/(J'X)LsO^Mܾ<񞣈Jh{ &@q~.GƗԆcGd=zƠ &7HR= e}>/; *k+OdԌ 2kMкS٪{% |FftbF)Ndc&Blg& [\G9N \S0gm^<5-I>r!}:dϾܠC('a]دcP}7Ok%I? t-,~gևCIIk2AO=$<}#!8>,IFn'q2%U^!!w:ϼwaVȠ9E+MƧ--=ؾ~dx2 '7Vsg!c|v` ĊبZ]N ;I<ޘ|?;ԴMY`˼|=$+nr )w7~1SoIgga,,"*v1͒M㒱TV? cA&I39 i[M_ {!Z2>>5ƪF h) FfU@bo* 1NX?Ywӈ6NE7Ѡ#8LdX 7-n:HC-tOtZ?JÁ;v5"FOS 3L4~ӘƾHӸCd?8׏VF!2.0]H߁>#x9Z?t%daCVEU\_Ў͌[P] nkw TnRP⸾<%W(TE;'_M4;1_63B+ |:R|Ɖt&埼uYEWD٣߀bO.a$NLe~ +5ģ۲Yk)p3i_ 49=K>_ˉyS_pg-l+B ZOqc. FnK$/G!fdsĚ ߢZ}[l^Ci&/Ő_gWN0~zrY \ fCG]f}g‚xRMu"Mf8bPzw9G"}/&G[\DIxwŲG,ٓ([5$,OϘ$քUg4?UEiJwQF>ҋ{'^*:|@HϰdY{DHd* z=DvzzY ^xS ?k@U+ ˈzxqC"콣I)_Dwm] ];g$"aA o< OC ¹VHau=ۏqxkWmW-xo:\Ae`U_bܳN?H o{^d\0f!%93KBSjYy*ymOCM1;k>$#}?U  bAyCb?9G6kz&\U;Zo^LnDžnaT^0ׇ G\ưp;q6~7,gw8Zt ?xw{a Iz'>'~m4-gai'MNOu:)3vD w`TҷV8a}YW 0a=tJ n5|E}o>މe]0jAg܏%uJ0,gu8]SʷT@qD)%V|$=>T09Ap\lkq2OdТ6]؉Vʪӟܸ5㼹mPQ^q`ɱI6ހgMT߄˶_z [bZK 8Z|1lţwkN^ߍ? e=p.a7D2VMHxAAhYOgdd= /s=|G|0wo FKR%L`?+ \w=5jӈ>tn3sľOە)l5:pnkLgƷ,w l͇R3_8 +V%9S4!M* 7isR(1?ip=+!S  D4`ON4uRrL9OOc_42Ӥsϓ~|<\ho= HsTn3ڢUA4|GMAci,k=:72;I5gք&O;BSJdxLIQu~r''r긹K'1'$ALv0hrʃ qEBe v[$a5N!t&fa<ȾIOZ!Lsog 7tH8O"gdT-'A?M uDl|H 1DTP "7CX[=?8ց;og12F̯ml%V2~#83z,tA$~dw,]yH3Vx{jƓsN^.5\K;&Mڂ5#R !nY4C"yqR}7aLtWo{tpF;-]kwbIܘojX˶_&"_{"\JNQT.ŎHoa҃!A#(6ƻf*1ۆl-Gl‡k~{RzOGlp1QL=Ng ?cW)otFqG{Vz?5`,`ssk 5*jwׅKt!#nNJJ(T܁-,Hv4o 0:یifpUfFZ?*x:I!͈ynVj/kkso2|-bߴ͵&ũڡڎbPwsxI o('>Nt rwN[2zc-]aۅ~S\HbPSr­8\:B!lVuLŠFx!9}'s5O)wVDjqR"Hȭ+F Y@vipaȼKձ_L_!%p+S YauihaMm8 ]r(ש/2TH+pfz= isixKEtmy}I43k M!ǰI>ܡBX|,"pTY(?@ #:oMf~ar^nZxF_y55DCyFi( K4\tIk|8GLC g ^qEHZJJKBuHD ydD$ٲG6Y#2-콷ǫ\o9;f;S)P6ZDntSm?3 JE5uD*͗SgsOx\@fO%U >?7Z879}hƴ^- 2&0|Iݥ̞0]3ԩďcAsD ?!`W!h&T#ك׃ Ë]P?p  ܭBZ-џ,cgs  r\bS"Ϲ\kdm"EVTõ$*kՎއk׷"sw}HTm.SەX,i iEl_Q x YleLѷuɆ(5oSN$KMs,r= *|ktཧ5Rdr"ռ̘aV;Gm*(;hjw DUKΡD$,ʫoyF%9=NnPn-Q#17QTl[V}^85]7}VYT%k碿*tO~T%e~mS+ yǐ{[i1I OuR{QDdmAb!s]v~3'w٘uqL9-;`;C99IHT0\}Q39yY} #]űeMeIWqb+ݿ?]֍a3da&,bS<2hH xń㉡[q_IErYZl2:ۿ/YF$!$ZEf4țs3lD-z]ŵme qƏ>T62Ӿ;eEGJ |b9 ~";28%\see~ kAG'r|8L.i@[՚UG ꏹ@e+>(Fv~7bFlda}6~b Ҭ "-U%w6sfA }R|:6"8N<ս=;Ӄhތ:vpm20o# Fj?[}.MFAMH~l ѯ۩x4<_ ^s~tϤ>m+IfU6!vl#,Rp6bWRt|*fD)bQzJ .X/TH#̉yF%Nl*$i6UwHgN7"P`)N$WCsk{ BMp={@d'\Yƥ_Y2UtsdLmF}ժZ|q%?pnf9/\4 ʼ;zf#GkȐZ [T$`lsD ī")7ʳxcp_Ne^Y㕫TDM{}?DgG؛5x' ZQQBqP8u4}, ;71L\g/_ $8PM8)vH=KX6`J0aAލo' $=e~k-J}Y8zz͓񊆪z^Ncpcqj3P!zٚ*,[oyypo@xs o캪==_gI|9 U/Iixw}1&`y52FqejW huNjM} Yjљ_Z)HfӼ@v>\3k/g/yF5ȼ0`fWR9Py1yqGd0*u2ѳ D?i nB[HFy=H tos]hLmwwh<3r4}@ԗ82V ~obnuLm!]N_Sv!)T֞V+s{ł >yB2ɡޜsrTrؚˡMOas6s?Md4'XUXwm7q*5-K,P'mf=M-^ڥA=-M.h~)= 'z4HQemX>vFIei}(Q!hO gMI7'S0x+r_P5k{~, \u@&' - kP~y;7r#?;?/o T+Ϯpw%T v.֍4ô]xQ}L_{1θ]&H+5YG<~}[~=O՜LwjMת^lid (+O=ߧ+WvEvw"Cp3qqy)bfrkQ%go\G(}.m:^oi: 3f:!i38p\f7 G{ޛo{{&Y 1?W/,A]2m9Dz)ɓaVWZ oGָBo0w2 Ì{qۣ-^T& oV}IƆA~p9:}M p*XgKNabW4ޟZY>]ᡢ¼sm=Lڽ3+LɔҚR+TSX3|5&|^͹'+n^&eW(lԾo݊eqd1 .#+`x57&xpM!պҍ]K5Q?U҃ع/w^kcE*{U-eR6-XnUT̤}FzhC;}6I4/%f' 2R?]۫gD Ԩ>1y?"H @j#0x!Zݟw2t=_qVG. W BN2[OD?W\Q+[d fR JEA8,LH φzL}v(O]?uFMA mՑHOS}9|T&O^IeZeYGa37v^ݷ?`ӱRzBySUN.;: 1l,JcDyQ7:zzPpLr;qy{x5<~K@D-޲w< 7z`MsmpA.o܃c'*c^#!r'S 'q}(*ئ[йe.s^)qU^٨X֝(b7v[ ',"E#έslFP3CD8>7DVt_1h<\QfYJW$®;Gw%RTWP+$GkƩx2q|_DN+?J #]b71F-%Ou5DӮOMzB|3FHn4 /֡߆\1H{4ɵ݇ڸ_MI$|X;9h$?,F3q˨eilT VHB\dx:Tޛ iEVWqa>hbS7auϙ>r]^Nh3ݟ,G{:` [dq~B+O[ ~ =o`B@1vTm\$20Z$,b|Ŋv*8[+jEd .TmĊѡD@n iӦ<5 77Cd)`KaRxNbˁ=BTh]A[;\)`)O6ׇF)PPM OAcH~94#<@q#smbD~užUξ* vtVm]MKvtX]R_-9Ev9w^@j\NܶET[KQ1c>˷ +Ű[),Љr3Ǣ֟gG=Gj.؏o՝bWf!"hem7͜+\,/`4>۫x|"UC?Yu”Զv)s ӒһZ|~C3Z 3qͮH ξcQiCOdqnf inr Z]V4J!$ (zCQht-$^qKMPg.arp։xVurz5+Cʇxq[&}[I9`,Iϫ8ebA6^0 ⊵ mHR 6"2 IƢFXq=G˘k|fr[XxVD>ls#VP:b-[$&5eɝlPvTz<>a\d<=B?zdYf*Z"{\_4WrHń0pN)~wxJ9 =Q[)czwZgGd̹Wb[gu81ց IO}a̳]V= #H~@7Ag;2-$^k4NKgZ3 EsRv3FOERq3Q $ZPP/,|#g.. #C߉o{0y͍3`lu /.8k>$bkбC+LMg2E / OpIav}ޓ]ZF4-m/e" r[GX44B&toDe2ᤗ喉uJYL /XggH[]}I솤,_b1 j2`LujVמ ;S& 6W9˛0EF:"+*%9 =e }y`WA8xM|(͉'UH5)hmgο`'j"GC+;F)XC^e6vTXPZ/J;x8iōd sCxEč6[ظF/5:XXj^0C3@wX'DR;J45[?n['6[ӳhu?%FOG`M[3OjFdZd4P],f (oDf/pQ/eIQqا1ƍڱmQÍsÈM4 g<|JTt*2K*Be,dcdy]ڛ{IQ</os7(vZ0FQ؏{z{W{jY ,X h.}~Ư]rhzAۮ"3sS7Ox=kJEHlXވ: f1y t)V1wȧ{K% |=4?%$,F>GcᆣBmhN7]ʓxp=Oέ1'ï7?O}(ƍGюvn3ͿQZ`Œ=R4G0uЛ² Uяi2ukvm*vc3O{l֊mn3Wڂ8VI6`lZsX@oӖEdx:k l{ mnwyir`X鮯F S*+/T*rX0*OYڸ/5!- EV@[ij0boIT'')~ի^p0D db?U C}\rt?H-plemJ~pX no@vr>0Z$+]P77 SL`yζZ149ʲ~ @U=gA]Tixkۿw}IhzsW jRK*+F]"G¥8BUȰWs'j9b O7MΤ`H}_2oqdC !uar%fى2m5J?6"yZI{ )<;K[qʬŨk|$bn3vGmwbaӡ1m2'fٟ?McX#c)wiQ@~ 4GfR\Dmtet ɶΗN/\OȽ,-Œkr^cQzLWߤ`qi5 n hPP3Ma鄶1Kt48{7r8 H`b4 1qGN#6XⴟEo gл2/%ReĴ4oF 5)m Xi{yv0rvM#3s-Z1^-O*]1 xzVhS' xN1B#((0\†RԻbyϧ8+WVw+OW?&Rd%k>Fp Tup^GfOнՆvN4`ĬZ])UBr ׻tX+ ,-M@W!'? f3$V{)Z$-e%hž- wT|N%=9a}W!E֘;tP _;ػ-nOTd R}ה 7"$=8qΖWiCV YP)l6Y&*'׊?\^D'Fo=aByl$Ku`W>h_Ro=,u筆 )/ϾN4'K^O \z;t*%xNn=?`rߍeB8 $W,È5g ʾ쌫w>iw?c_WjynXeX7FڂuK=w#C E`7PA62Ep%Kƶ \LW:Jxs$q} e26遲g1czo?T=R~qx!X򶏭a+o)ȯzūx Ƌ(@A"zoBƲƤΠΕ}nUDyL̺ٳHBkqQx'; *J0ٖ0O` 1n`H-S7?K# 0WYō^}Bj1ygڿl`ۅtvxz$mžE/fMb;1#tg,{U` {"[;Z|ЁC}QZc{k9V_vu[QU70ּe6,x= pRp`$8!"KB,үwT [etYEE]8btw;kV51ZpzĻrlt[fb`uv*o3#Ɩ47b$ږO@y.x;?\:?bme;R ¯2WmHt1N cNxq >?Lo.s=pMKRׄ {a5>M,#n|4- r;Mf S\ۤC"ch0.02Bk .N>')yϨIc͇fX蹪FzR3|. x(? j]Ç#!Xjhڎ v8{d8כ-6FgQ /]~ jBNady2zA^H0耬q+D_:U e+g/䨄d)`B.~Q cZǝt!GT<>rWwĹ^Ɠ&u 8~ޓ1H 6rAkA t!|:On#n܂27ڐЈG?sMI"5uNCxq?CßoNצCcb߇hh!Gv|T2՘ӄF%1?aE;H盃`^ ^켰szy[*WeCLaEYаw;' 8>z՛+e0Awu8VlAd[uQ9`# >uZ/6UCF-wBȓep9حOwpq{iGg2Y"Աtrv=OJh~|#sI $ }Zv$PP%}eq`UQE%=᜸q(i 2y}/ϗO ԻMc I0Le|au"fܣpL S,h%raMOgaйNIѴD"U;hgDzpFyF?اU]B6t9ѫtޕW!I878m7< ~+7ٗK;yx2t}3 $o{nk3<+k+s5(R,t-%kmF`].g=o?J~A1QTZ5sAᇵ= Xf82| x>N0}g=՝Fo"Ɠ<ӸikqU]^9l xНR :6t>èZKQ R#hdI[Y _Y?K|}Q5^` ! *8 zXKOTSHxht۪{M U,e]} KzY?v,٥(|_C$mBW ofӄ "'iHKgê̾Id$;'ia2/QBge'miك<7f >#]jlimIGc2n7{ Q=WBP{uzU ManBg qQ4e@ cNޖnB~pL n ,>O78j~p)r鋰7AZd1HHqn;-~:NLS@ET&a8\.l]o{p`];qNt  {ք3ۭ"ZKho醖|'!"9p,Αp~ ;4\𾑒G3Bcs̿u妀#l#nIg ?ځ圱3[\M&'8VOsuzsgED<'Q,>txbK;Oе D*=M)OVŧ=^p磊pg窒PPb(vNo xPw֓= XPc(]~,o0R5'55XD1qh7LX .hr5LR3-FBBgT^PG+BG=J;",Ad˷N:@ DmiPl7b[FOdv+İ2"ĩuhҀ,L@ ^S"Vn-GkCz;- ^yS4x{PFB/ Me Ynl8Ka[K|u:oFԏSSծFk7|ib7+ߟH6 ¡Rd.D4ӊ{BV5:nvj$Ҋ7mؚQ=QXY59kPGƇtIPUƖq~cZ.UKāʅi2`w]ˑ[IeuKYug{UYE ;~k$XNw<=qQ0`D<= |xTI퓽HpAC@*M=LH˗R3ѓ?o '`ȾCc36qHgYԈ6U?67єP^},6V["ͩuPjЌp`~Ӹ#|5:ʹMv@0nZ [ZZ T<^ gn^Zv-*KJ뿁ɉ;J ruh՘=yf)_w]d]!馦^SoGʊ>W =Ss2AMEDi-5 kWR-b:Y~Ţ}xYNzoZ+'֎]I[#8p7yr # HlT$AdTVHBYe$EHfɬGd}uq)Y= |6/dh>>3tf s#)1"ZqgLac<;zc3أݯO ֙oz_[!(x}gn8FÈM&G~tSԋ~ŦXͨ&fzӨMgƅYq7€U9I <,hkԻn줰FNf$glny- !CzJ[* WGxBP29<Ē#]>Ba1}aH3(bޔp tcAߘ:R*fxp:nИy֠UKBC-Hl 6|O񧫡!r|`Y@##vq@ʔ ;XRw&BjY^uӏ\)#$h|q͇_ `꾶UdE+DWb;PKuh/׾|6 6D KxRGs]?$$=|]S0h<щTڔ"&j\SYHk!*CH"W ğ9:]" ~-xW&3 $,NG%#dLp{DDs_ AܽU6P'mh!^<,ݨ*blӽxW'4:bojW\=i 'ݓZ˜ri5}c7hzr/vW /%[)[&^\koZibvuxvGhWjX/#EmpuTXdM~x`-9rl/׋a8]q@ߥӮF~b@6^XN?g~c-~Ɔc AZDq?e E̫xG5Yf8Xҥ#_~s@W[I=Q=zƵIrIV٨zz/!GI=Jj_˫{hjX1dXOLV6m}4K5瑇teSCU5pDCW=YքzXI#;pR>  }(}1w:FJ$oF"a@K|a$:nMB+[',XTp{ѝ{*/Fѫ_5k19ym="e3O񉊃Fc'3fq 3lDwϣskH*}+ߺVyftxa ƴXM=!?gpWiZ;P"*IAf Ū*>.v?%YX@N)~%924N|l\Ip8OEBa#sA{BQ03֎͒ *M3j"N glMVAA9*E˚}z}}kгfKo]WcQۥ \Kn=Jm*3qWg{5JQ;O JEbZTJo#aT_.Twr6a@Ͱ_0~> m?34]qMG*@x{/3>.Cou@7ai$qd^tj̏\@b hz.O!Wi?>6.OR- %BưњC|uIA^YA.E״<{QAnӾynX(+Κ~75#kŝsRMrBG=}`,w|LD'%Exp:2ou%1j,CCEw^Z{Y?^9_^;HB=(,7]V_ӏ:x= {;Z1]R`>fr \-#?`"-]~YNAU1\e6XY5m ˋ Dk>He\h_o0*Տ12 Q)<?gx$ =n 2) z)ÃSp%W! sE 4d(: <)4|֓ y ꧧm% vҾ XE=;xvSO<ߠ9B22̟}n@'? Q0PG%A7{PVy O+dBBBZ^hV(*ll%"WQP&é"1k&JTL7~/>pUrGBYK#xa ע/靮$#׎]d˜nbGw c.ȭ(5kr}m+nV%} a#r wjN\= Yw#oվd~ZLp_m1-O (J@5__cLsI{QCcG6sɻq;#'/31a0K6;bW}|{/|ilFv ToT9>~R*HfqfҪbj pIfNPgGZ;Z#id!)_JrmYjPZg-}4[+uزnДxN;> LC!)d=?=aǁ`+ON^]}zm}Q+' HZ^"f{^ FJ۱JlT{T^Ω?4Y0PSV*zzP 482sEyu^e>9oe-9pirW~`+i:} U/) \kĦQБIs8yww2⨫_;0d*-j{0L$PG7^LӁ42Me\lov{M_M1`J@3~_4`߄nT)bŢu@}8o&'ŷ8`3^]{Q:zbrpau,^sc EQ4`9Ԝ_+HI:q_?XN~j,ATޤ Qh,}?GۿpZ %$"߹s%m~A` GwSJˁ.`=>Q}3o9U"nK*2$8z.σM.s#u| .\gO]H<JΊaMM܈$*8$Zz9 kX );ZduEoYے@ArV2Q!B?̐6g`4i iYӧٍ:c*|;3Zt xvy0 aJɠaa3CSrcp>YkVbǻ飽0-P\Ty hc* 2샧 u;.w~F-g'I^z0U|Lt4Լ/pn}:'m trOvg*p\Z}':;x`RmɩvSvOFG)a,FDlؿe3'ח|q)a4e0Đջ,iόc s[c* _;{nA@?D8XQv`S 6^~I\>_)|-3iY'*[27d P)a[" 9)gOQQ 릠3͑gp~v(* _O˸扌uئq&4F]0,痴ԷE^Lh 9}6jSg10~85\B-*{A4ϘZ=b=p*>ֺ6c)=9|4Na*vIt}m& PjFT#'g@:?ur]& kmsP=|QD0{}TQ('nz~Nĝgr0ph5 Ͼ f. .ǑU*O_JGEU<N^ydKXu7}FΦǒJP\=4e2A@o@V:HYNY`:5:xh;Y]m#qՠQZZ>Q9ye'8Vwj5\;JNOpyQ~ubt,]֋G]Q, lp'y:Z6#h|Z 9b缺oi;mfT~쬣7 Y{ݓ8] .{3MpKm?_K1Pr:MpYQ)fzG{ y9;Һ z nt(N0I{ M[eqX? U]C ߈0VWjۈbt?RJݠq!cQ?* ٿaV)X`I*h '4 QN*Wb|rT(Eai:o,)]8d,BMn Wã9(5.J4_P\BHS}ɏ P$C#?AIWu 7-x'1ǢSos\xҖ| v*Ŵi?!ZضX dM#8yw$7W80Pw/G\,\Eq?p!w&4[A.3$̴X83\jo~dوhd 7 >&RQW'dUlhh:zewԿwuu:;<#B/N!o rO&dϣެy;M5BCnxRw҂bhė },[v|qiT#@֓Mu4[,wO{cRR$d#+ 9u=<8<. 9*Z ֥C,C2xc뭫 ہ:>%n_\Qt_"k➌6{yAFϗ9Cu~X/=z1|'ޥzUckKt O.7QqEcRN@mK&;C꯯d6PnI7v,=O}}V|CwdlxӾrtkZGQBs51ɏVOq}_[񑶗W*w?> ypdi N[Qэ7Ƴ0Y>*ͫ'"Jp3&`0^pTKq9HP;/q*&+IF>+A8L8L s`Ɓwdpw>ͧ%}Y0J4BW?;6K.IEc2Yp?&k^UP\;vN]8?!'SØIvٍkjmxm7o-lyXD[]u6ʵ}j*qKٷX3V!Jlu FU<B9go⨚T,,}= zd$i:`Q1kk$Wfbt+ЖKx*nd|3 ϕ۾BV‹'b|#`W7)4^cL T<%Ѭ>Ht9{V}E!CHqǜH&b 0a>ᢅoX 70ޝ)x+(ջ*A ;R=Ϥ]}3݁ N"W? #  %J=*R'!{fMNHбwӫv?h_AP@ cd}3 4cȠ7oiDG]^E[Y c7 Ng+`K0q%A,ٶTHtӤB>%)9P6Q{'M7yFCI%9>'+n]I~ҨyNcF X}楁kZ?$90f\PI-TPx|K,\1YMolh`pWLte™MmG+#I(Q ['INaAa'gU4֦2m;_:d"M/$u@=&aJqo`8+YˏQʡ eͥYǠ^fXvP2޴c#]zWs;viF;sUyLJ/IAQ/KqQ~7;&Kb.7 ?܎gp=ϕTi3(a IWOwHX .%!93 /33Ld uq :=! ֟_0`X7 -$DǓ5ʩ"2TMD3U) 2Np3)TQ0N!S^3dsFc)xiG3!\7&%5*F>蟏ʒwW㰑I L> +$|S3(wq^L@M9_qWFp6a"k/`[,]>SƩPuqc<+u7Gw&ssCq;-¡resF,)L$vޒ>9f~9{P؜h=cJ5=,I?^4c{A^,pB%g\."sMhs>F <'j\vق| FloO&;d>[lvh&p.ٙ#?5v{@K5!$(AAڤ#XbyE1&2܆凞m.;kb~ca7Cȩzl ΃'uA/W%]ܝ_ZnXzVXTc4ij"!_Z vnLᗯk\e45mӭ<پ۟ocȋ۟ b$4Ͻ|h;t.wxZCOͯj*S˱{p\aBSx."hƏ|~CV?nGSϘY tTm hLȓ-g49Zsܽ/N c4?cZ ӓ A(o?s+RxPCrUXyxF42jK;DIf5fF3Jj62z y€5:z9s(UԥGy_= j_-vrځYtLnԾ >5X!P=씩K[p)ӅBnx2!##`d9qH}Z㞄[H+N퍝B#\"ԩĨ)&vF sKd(\%P J̬nRno!6Rix΃c^<ű'k`5dHuiH8)DrׇQasQxV8kúFrnJ[$'C]}*tl.@Te: 8I;ר18# C0ֲ9`Yy}aջrm" 2>X{o88oX,Asd%(ݲ@o ѿ=_($4ƤrC~v7<%>:jr0e~ڞ t\nO_A)Nɪ<=&vp[?gj~HU-㽘I%a57Yït 59gg<_1;9Z2t25b3 kxOU1 ~Y $ k]z;4ZV:qFY`.co *'Bry}q`,M, oIjG(-ݨbUb2׶3 5V:]c9lr?ڏW($?5}Yw '~.b2.շ{FQrz?>]])38P%+2RdLnMDW"3"$:1wUWIۢ3[-*)mT.71 ˼4''tŌbfO0!ܸ;PDWV’XͨNߐ!eiЉrzy|1Lt'LS*W/{^Z?! UaD8k4fFwxYMarڗ^d# -Is[^ =I2 Ԣ5kY'&H[@pjk=gbɎ̹q[>Ld5NN1]T110@g8f8Hz{AN9W09}^+WzY#Iۙ4 kPҷk֖Y)6? kikf*yjc 2:oL0|a 4w q1<]c޸蓬*;L<54@nmp,vӆ׈@ݷ1+a-SHxr.) j B%̃6PzxCL1a Dg_&.s?N듨-/(P2R Olg$@`h;{ql}׏vA9xW&45+1wcSbd+ kje&r!wD+%0QʷGyfOƠ/(Rv> Q}ݾ3Oui[\3}ޏwOM{<`&@_)03ۜ3L 8I_|{dty#6]qW@ZZ#"lRk(I?edrH.g`h+`) cn_;1Bj9q0rp&V%KEhi隦&-W`,[̒& !턠I.AQW+tP~b_~t)Bx׷t,tOM1"AzMtrے98qx'J})l4^< E}7OAbD3^I}g4<_SYSFe*L퀼Wu@KR΂kopxuRzCV8 ؿ wIFR󣡳}b.z ,=xA"r-^9Pc[ RVi캓R'~t(D[ߒq$#^o5E|.w oXH 'iW/Kajr\)\|r8(rq$X9 NNc$0*'Oco{ mo,:sEo%cSb-'2{}< 2 ;vNQl[i13 b".&bC=m:>Sf2dPōߜ oc7%;MB__IHVyrI]?9TAӘslen?33FSy{ߎ s|q@ ^:~3 9l ?럽hv.8:(eÒ$cgY2.,U}&\]Y&NCL'OBzeUmZ!n ÜӕH-T}2+G)BVFp=;'O1AyLW+r?||9SZ~ !ϑIwXttLӚRg²y*LPAkMN;8y$!mh\%`m[z,n-rp e> mݻ {ڹ9?]<@Nr;'h9K 5BmBfFGjBa!+W2SAwDK Y*A&v_c+J i9GE[ {gAQ=esVfTW,SYayq759U.aM uz(@^gp@Cx˞:덁I331o(tzë/6a+e#M^ZtG-WubainDډ41vԨnJD<GezWE,`u܂]qq?ux,誘R3zkRb%h9jp V.2RF#H-X:4vd]aƄWp7m7a h]y 1Iة[l2q,ZCc>o4oMQAJdq/[L7nơw{/)`Ęf: E^e< n?~#AqקUtȜ ]^drl>Qg=n:[B_T5o[<:D{.G.nǟ.ܸ%'Wa|%x yﯕt 1wΝh|d\Z-D.2\lUpj \sI2[+6\z{WjnsbŽ _a<"L 7W_2˗ARh]Xχ;[mj^]zmp>їpU(ev\x_8&dnHji?Z$%F&_; Q"C= |9wԞP{筒}\ \?u $Pa9H;]gO|>7u= џ0%Q;l'^q @}WJ#hw!yՂj/y 41y@̌8Y.nf;>fiJVJٯy=_~<ԄlLϑ0ӻLisv٨.}K-B-ɶTԷ1ٍYFu=8FShї"8fl;/L3m; |J|1n'1׽tQ~UQ~Sx~RK=]:^rk-V|#{RZ:WaqZTZ˭X"0}( =a{3a~V Z@j鰙byন;PaZyv1#@ dYo[|$,|咗; (Զn֑"Ճo2%&@]:Dx{.GGgn }ŦIrZ)Lw](q% L@y-y 5jNF?^0 \}bd&w-Oo&TuOw%ugR\tq(]+tq|:245}7orm΋'Ou[w./N" ElBv1 zt_:MjT[ax,l`Tu"0L0Ԉ sE5!bhYDW}̇i*YpzHQkb&Ųɬ_P(ȩ>).'? dߟ'pC:`F".d۫ W!|Cbpe0^NCCPT|@E(t#hb@L B4a"iG,q'o7]7q^Q™ϻTi5HrMBQT8o΍y^ueըԎPPN: w1 >?}N ĴroL?Ҁ' UU[zGh5{҄jt jd)G1>jR6=A'L8ó{=yܙ۝sG0jpI>jۀQ^iZ1b{l'Z;D'lGCz42u@hX;aKS޾JElq&<H'(kx곤uH(R$* nVDOĶREمkd-!I^\}ʧ<{ԢE [m{l3?wަ! \_Z61.hbuV"$G19-(I_X-^wDYq9)&/Z2~kns^ЙRp`zJdͲ5 MdsX/B~R$LS.jzX9 X%T>_C58nyã C߉cpH=ƇW-i ۘ"4r'^<Շ??p[p +cec⼟d")ff籂 $}t08ϱv@nl(؅zwBle=*"Z}Q&7Kv&'=ݻ4f~aRnO1w>"V1&39HݳU'^d(t;X+r7iRpޝL`n=upv/prYmUӱ FxNm`qu~S4Ze&rJ7^P2[&ҸQ9Eb$$xcwo2A-]J_qquf oS]'3fs$"O ~֥2N{Aef/gδ42Qm&Nߞ+ B@f&M.+ulazsG6-9ʾ&v|R ̃"U5*1ZeҠ}dEΏ {S=okfP֮tnK$!>>ZN|L^w,3O|}-pފeE9vp bM Ҡǡ: Y.45 ދ̶kkq%DD_W{Xb]TkNm]&s`~GxR01yEy%3–3[VMfɶj&ګf t| ^lO}B{~C%c`E g#ng\e;_2${a1<[cZ0 G;-a(e"(UI77n,}/_u=Ig 0p(^ / ąp:@~+ _&#t/rL}=ZVíkdcp.J#G5# tw+={}i, qQeljQjX۰w]H%4܁±V=h麓r_ل11߇C-:_4N¹\ dܞRoKD`w())uV;S vk|nivS"r=לV\D|eoBCM4 ?Il RohGV5"j$ī4>{#t[5> l%  K~QO@]]^ rg(x0kXc`Ȳ›3qo6߉"~wWs;]gT&|p3^e*9gx⼯3MKhZGJ'^K,fRȲS&IN"ޟJGۅ֊G@skWÈl[1ew('5 7{aR!@:i3emUYnF7o{›];K91l<T?>S_ef¤Ms8^7j % ;}?I=rv&ò|M׆Y .18 d>\1L.^Ně ^ף{v`暌AK+ulf70>rc?Alr ˳)>}9v6= -%¦*8|]V\jӇ^(6/şB~fpa2 xD"hPVGVk;QN;O/PCP|fE@׭S2!l%+8{ "]pyjvwn/]ؚ ĽFy@I?iXDa*Ok&i_ŧa5FJV!\&Lo QO͑H~Lr P3fQC1y& Pu&| K^?.>Jodȿ$;HanupG{]HWϙ\.7T['nixvcY9R*:hmZF΃A $.[x\)&@ڏ  $mCVL0:zc%ŕakC48vi]ϊ-晊|jI%Ɵs4j`1AEe'.ӡԳz%X1Dg 8 %^@zbYN\)AFBD?9*UU3S _rkn rn"(tn20\=VciRh3l n-[(`fpvk#v {Hڒ`r2k C4<${RзB*풋I%+c{Jl rL3AψH)oEK'(0k`Ya΢S^/!yF~? ZδmۿmSn#iݛ[9wwyGT)p:OSl:jag[a$ϟ`Pa?4 %& uRD (H?Cų x?bՔf> z,[NnNA M/n&ak{dLր-$VW}n%t7(d47Ӊs?g{s;$оÙMa%\?yNjMQ/Di.0rRT\IXsKt@Ƈ D|vGtKFo~x҈ZǍI S&d =:$2OߴؒqMdq~Lz !U-$P<5Ǩ}.z?`,Nk Hɣ_$xϨ/GHvF]%n|OpYɬ?pK)~p}T_m y[Ա}ui!оA۪.ʅ+#dKM,cç@Hh8\&ܨWr c C[ hX- |=N` wt7ss_0rE>BVv E,nq+g Y=F1ѝBG{1ʬ6ua=z c<Or7y|zs&Vbz ]h˯:ZC[pL`n^wۿǨE/Nxq+lN;$88$?s:N%~p5IkEm8#?vwy;C3LI锔nMם#zq;"Te4_G@0&2 GT;\ƹeTK8X$r}>&?}{jOŒŒ$0ʺɍC s!1 ;_cTH3s֨`OΉ>IyP1Y" hZg0 Ӊs3u]f.s6y%PAJZˁjݳa/}Z:skf-Kzto05ࢃIP>Qw ڹy۴i Qqd`_A!U*m4| < e'W)b`c@MSPfH1_~aّ SOad^Q7܈EA4B.7cDZxa7_֛FOnU#rv}ӓ>\yhr~ p_mǦ4֤`jlO &(>؜ Zms3S#mkA2<ybϏP!rNg=:l: fI0:{-8NYݽE 3)TiBܛuElTc0t%ʫOq:v >r;l9Ϻ⢨Ηq ^u=1 BA?f.Inl"+7»gLʭ kR Y jHB) ps ACn8 a4jձ)T T|178YŧRfOMK͋"l[LDb}ڣ#ryc0w OJ Fش GauԞ+W*栶Կאm> rM${SHn?Ρ3>l*S0q9,J ~&@u)mzՕ zL8SVz> UR/7 ^UNi W\&`o];>"i\iaE|}Atn@kv/)<U*6a1Tk8|t8acZ`SnaP$0OܸtuGzV[9Q M+@8t̺W Ya>G-5>g }&S>]^CT/I#8xS[iC6cwv/a+HP@QZ> nbŊY2kP\ODsih9-_Ԛn)E2Ku۾e8LaA 8, 0nsK['fOoP3wG+ 5 zXtk'&Bﳤg%X{}k8I{_%ʅwԢ NҖC0|ak/i7|ΰƭƍojc䔰E6sR6zX`/-HXP2Qj6KK^=E3>f76Y9a֘g|ؓϨ"J;[9lt/K܃߿7h]`wa1}-TH P3?bo.>Dح-,s^ll2.IK,ݯWtt~35"Ơ+K&|"ّBB궔Q`}nE\'X3>pgIc]!tV¶}m)ycS3{ᱲö˯aXk}h2闡.5b[;7vS7=##ta2q H_UP!i8ˈk^6RD/Dsz,Fa_CwJ=q ]ƠGI&5Z[x#\Cُs7<. ՂF[WǍ%%]|6r)K7A$xQgp{c'@]Wۅ DOw'@KyGTg h=H3V!3h\P)í#^Xt:wYr8l|dHp>+~zs tv$˹ς;g8V)M_=ڧip$+ ]/_CGp"{-BWsXI'Uj$ˍ9o7C58~FzaDEG<ڋ`Șg <7~%lqz7 tG'`t 3Pzt'K P*0L99YÐ׹ $F.%nN`4ֲCsîכ_6`o0[ٝU,w֐xG J0<e<5|t^E~vIIl}xl*X'O{(Z׏{{r?:EU*z!`4 q.d3wuVܨS[fKG=0M[>XL4>F<4N4kj0Zp'f;2FXh̏QȡJT\~ i=(kCE+ڧHƋo[%THrA>Jb?Og\tM6+"䳞#?`xϡsK"~h'Ƕ!C+b"K OjX_HAΦLwZHAĻR#ttLv>F^dcƿQyĿl,=9. fL捓(1 u 8Eȑ!`n|^1EVwP8y'AōMeZl:Ғ,Du7>ѝy6BmO w)Ii}qv4gb8u`vJK>}#bOZ]H?p]d' HSPń1kjW2ދL8) :'Nù_ в9dw?<~D(hk'HB&_o#x-g˖ַIe&{Rͺftp95&i;.k+1wz8V䂏גS$.E*{fmJBJ+ju-H-OtisȜcVrU 2TH&_lZe]viA ^ \/쀄%Qaߵ81%Y0&< G'sr7Itloŕ b|=K}WNWåTX0kJqY+ hXQЉ 5qa$ix~>y̾.UN%OB&2 3χ^ /˜Em`hFٱ3sMҎכGA,BC4Ë@smE@y2<)dˎͣ,y @=czOXsK@< NʚQ V6 j,hyJ`?(AZZVVa4k#i6+RWwQsD%RnӮK𮂺 Q}Tn/IEKМx٩%()k"ܞVT{dIGA;NS@L8De[N&SO8-tJBoX7| &w︒ҋC M6XIk|zaGVcu]/[ =lAzl^0dw8sLR)gZ Ns#: " y}Qmqpm}cB(ϐkdH8V㝄_{EUNCٿ E@Ob3NZ<"T(U2kqʋ7'@χIq^y(jp3]<.|XgҶ1j/ZnHTEfϺJ $FgW|Y`{Ѻ*ES+F˶-Xڝ\Df:ϗG՞?[@\S9^l9?BP=2s2 W q>f%IEn~<huL.1]h^$NFL>=LgP;WDZPDF|qܓۧ(@CX>S Ϟ$~YԵ W 7WAOnPuPW*Z2L y|a>%$aKN$hk =D#x/*|;cb1X*PL $c_KHOQ;h8P% UdPX]7[.5(JIķi8 .Vܷ6ϤG{۰dz֡y;$ ^Ӷ\vKת 6ds~ NA*Ŀ6%2Zcɟ2~a)FؽoN:B<]FmHH*ot*@.bJZ|r<,^UPi8 ˙,x.ށymLPvjS5AejQZg-`Ba'tٺKyA{N}BFJo;ck$x yaXNi926Jtvt s/o/Y/o{=wP#[{70_h`bJ'+ hP\]T>h= Q`K2on좀I \P "5W;v5bڮ٦!^hvW۲=ga+Ղ^t UWGQ[GU3)pY'NcžpWKN')ہ͊#}v4jC`^{vN'2x.wO%q` BkӖaYѰ2\V/B9Dw"0|ygD0/T."  ZE9i^9'Hm~R*FI6uDyB#ZqD:Hj>4md <MW]Sj8ͨ9sx\/dFE CL"ʳtapfLNm&/]s0֝^sq ?R\# Po˖S> KBfngu6VrNY0شNɊ^i麦0*giDԊJK V^Y#NxѲ$o藃& oude«׮U#lu6;׊R[.m~ʇUw*@;OJkVƅcAY4kX 9g\u5v[VSk N[(Lې,v1<zh$/+3J֏K{Cp:E?F"J[6tu&f8W  =m6 U1ࣩ!}+@UL<"HI&lyAN) t[ERRDt]й.nv?9u+":oҐvhCKY_x⩙DWpvk?_JGo".A܄j>O<G[zѫ>'f!y4U(ޱ ~ʼn{A7M(Y.tuI/ .?9cǩEtI}b7DG0R{/e󼎃n:8mܗ:'NCНCmwea *CF'RʗkN-CsE*KH0m2ԿPwm$Z };X:+0rՄ qb0Rnb sϒ~``%0[ACheQ_T氞[6$@|C"+0A 2F2|(sk Cy)^ 1=d[ Ng(7hR_3 u8cv`qH? ~cWqcTJ>1| yOP&3^5N:(StS=KxBS2<]e&èm %2,&RkJOj:Cۍ≲> ^.ҹ?pٮ%\n@>mzi|j|GJouǞR,hj׋A3N "G \`w12̎Wo ʏe'+0:"|O!g^+KGzFQ&AMfM`Am4EML=q"$<: K!%xd  nL-xm~4$/@\Z9lWg%ˌ0]ٙlpwAwܩM Z1P/dK` 7tbXm=mpu2:|6d;#`h]B`owlgZ.su^ΓK9V#Nw~ ZHhCޗMv{ =y% Ah ]I ,?C7Oq A=4Ych2 #1;qH>TWbj,%U=T΢u,xұ 3>#CqlGoAgCCS5=z.6^e`NW%0> p[0C%tj~D[~+0 r_xOlE!Z̯ {2JZ9X ؒf|OgG}rrˠ7e6g) =8r=3sHώ7QnNFǓˑވIr?8KpDIB&nhdP')8F'VGG@Sbz<(>{\-PxVo`akv% AKz? ]リ?ڌ_JJ$!5֞/AKdfE8,K;=[ 4e.:}!P#s*:=r7S ݉I08zCPϫːJx'm掉Cbhz=\xX:U#`E SN^}jBSPz7 c<3ai Kʓa(+[znpkS*u8Z;/d9׷(. }B[C^bm7m,ذFB܋gm rj J#Wjm2S Н~oi[{/_2AGlœű㙔9|CۧG_0F݄>_M{wQ;T[:{I'4ՖњTʹjxEŵx'j YX8@F(mZ~;FOCToiLn [BFNv>F9 P'0*ʵu鞢> R}VW¬9L(boG? Q@`ӶnvTyXw}~y(nm^>cRv""u3 S[{ILOk֙Pβɚ -p~#*wW eiS6BIr)"+I.+w/\,vC th2D٘qUJvqQ*W. _]ϼKgV, LQ~l/sq)̃ W:b9uk2Zib 6Ұ<ⶄCKP?2{?G.@}qs?=3qYi|]Fg "5t͓#QV!] }|u|ـQǮ Ռ)_o(|qQfϭCO<7M7԰ӌemJŸMk؆P))uQf+[YRAf-@S tQHFv]HWERE7}48X[ʦZqLI)m@ oZ4¼ۼ o, ǣz6ylvcz췘u |ڨ9 14sǠ/K)iqSU1 4B1!fZ_9tH[ @z?9P8s] xxFOp1 < {'CA{$ю^"̳P :iR8>P'}2kb2s[M02x?şDҟ-\OŃ%T^]@oЍ-*gJm Fz S9D0p`'`h*/hQ9<藎"Cx8 w1W=,Ɛ }QyN+~ok?% N6fPdZ h3 %CC d*^$.ܡN+!!d$Ɣ }udK2b#E{ņ_6Q.bM}0 W2 9=ŋ7K it4/ 7L[hwH<Ru08sKwS s1rȬ ʣ6(dwT>̊Q{sE,)VK(]*Ϗ.k5+k*+]z;էydѧgZpEd錗mCMjyଙFbw+q_rm-sW(4kZ-),AQS {j-2j*|"ܙ3:O][U" w4^%l()Q="#ddY {l^{S_sϽ>91.0~| })繪=1W  XLCbil(yQT0MP(M|셂>.p+ӭPxVhݟ/ _d!Dw~ws+^ڬCf%_ ?9 O҇yE64Aŋo:;0b ;'2͢ Z"*f3a!Υ TK\ GBnӈuEx_-8KL 3f`*6Z|g^!_i(g4:!cs6WۘR8!ʱ! U\Q?=kxߏIFj.GS/a07U|ݬ߉K4)S zL |¢$fysiuy$غN(> Xߎ(_'_ I]z"*F  B7D9I0!]rCƴ=mN*r!™i{춞 #yx&BY#_ i3_yG!pKt8brҶE L 9e i" 4A:Wp(*Lp/鉩0G~ @\gt{0,TyLvpqRl*<: O$ A<IΡ8"M|cl?Иw V/Y!t+ aCNy4 >':Sw! Z7rIPx? 6N=!q!$X}~3~T$.`=&x p!?=&"<ݷ#"6S$@0U0 17!1x'H,^v`zWb[F7qp/*"&܈D"Wjʗ[ϱG>wD`Ak\FBrmādZ_,>x8 M pn_:H 58_7gnrfѤPd_6eoit]MEp=eH(ó?^3Yx-uUlZØ'qPnی!w?-9>R6z TI0bcn1ܝ_xٙҥdg:MC+°#ΗvCڸQtԜcXr]QLĠִGϨ\QqYH3m|~x=̌%1WvNű󈡳K<6ЊS4g^ɦӉRIbHx̝lBUm2(߲JMe-hۿ.p~̈ ˆ8HԲ=) L4J@dmʾ }!G_[Y*A\YGj80js'[т"{|Y2^>( b: 5k9p 2 iWU_)4ah[1 Ѹm(T ٍlI9O+Q QFo٨ZIU;)!N+x.zIav 2o;2&rQ7p_](^l/ lWeϏ 5C]{s9qsP 6G!|!Ea@}( 5_*ujiUchr:*Ғ,uE}LtNi52S^5^7WׯÀA8q¶V`.N9)re{Q(#kV3r}k']qrtiV7 {fԥM<ZO BKͅt͔bo HPB8 J n୼#}Mt#)^1ĻzaH;ݾ$V@FsyMtl0]4of4u>DBtP_թ:@fS%DU$΁[ /@I*0]H]3281&ѩ/.Jl!ZA["0=Z&s஖Y4 l03m.n9;H.Zp AaQy*ޗbHj$֘H."UzI_%Pw$ "] &'`px#v1࿿%`7+ǝU=x:_+]2ǎ_uCGs'X<& zJ\Mh`ۅxa}r43xxAAi|PBC%V\*K.8XS[x[c%l#„=t gŃL[\>vʖu3fT$I w;n7g,xI)%7C'=>fqX$ ]EHWH՟U"l%S;jd"߈ B2'$`0ȟIdTAP'R?伣SIS1C/kaMIs,FnJy#jm\C*NG4smQ.vcƂi{h_o416_:h\8Kp䭿*[>5W`r%U[['1"yrNG~RS=ǹ j(P!{HiUz5 -B #p}srw0M`Dshg78(F0i ~ݞrQD69Br/2 ![F՞` G bn3|]4yp#v][3 ᣬoOǑ'CcQᯣ]jsk=fsHyVLn+6E4_Y$eRic wH?$_Dy fyI\TFHZ[v5hY;ď:mX(" &)B]N4)D@̺wLL`fc5mMsPpcl1f/} _#DG \.?Mڕs3D*ZdGeG0hnv8.;03tODHIvq2=PN"CX-FeT C"$}!?kX gΏǐ*3}7"E,STYx=)nA9R(9^?A,-=cmdU@H*z7-GrS*jǂG;5\Wvv &%@Ie ep!BF^P]A'=0L'eߋppz ۣlXc\R3G8xenQĉf;qP}M|(18@jjIz%}`lnUC ,Tqs}ԛ\!$mxI"ٗ|&wV}d^d @ d&7 &T>c67:.ʟJ&>FxB'D)3 9Dkqr7wAVh\O|^ړ:L~kxhva ]åG)pk"E/`aCK^5q=>8& Uh 9@#A|Gp&Y _^:?&sUYؚ}F0uRՇih̿G4}{r}R @wC`\|+, oJԭwv#„mc"Xo/+;5An , peP# +46l;7OCI-q1z4K`е0&i6ϡ d%2.41Lp'\r4. >ӄʌ2hs[[v3jWZln 3>ҪmVG4"0"[%[ A.cQ 3OtjTmvff(}6Ƿײ.! G?>{g6٣&t!{3~`nYU{pI$ZaޜQH|Ov"?p5pNGe|Zr9ˀ ["4?m7& i&"pr[X!wzAڐTm3 `^'Ps,Ё{c?s?O!sb7I]x:S$9:LJD`A6n{Et\+v 2T/*sIq,X5owCT .7ʶ]!|/,p0$ddX|`ڳ |Ću >!TK,Ǎ7֬u+~\Z۷7̦47ෆP: Ceu@mSBd>p~ʕdnVP=(9?,!C]d{,`AclOxֈa\m-b{C%]&xp8t2k$u:ȼ09ktd|WJfy VqUIOf#:9GC|"[7&@m.20ːAivJ"ܲah l!mJ}8pdr 灙Q?M+^߀ƫ׏\@H2:Fݝ[Ղi.O޹I.H%Ϧ]4#+a`ve˟tP_>mm1f%\< j)}2F2ӌUa0h,H聄]# #ښ%#N/'KtWP]jB]:[| n+VY"8**X3hǐeV8zV23d02ۿEm'zM'ި^VKt;:<?'ThoSݱ3OZS7+omKQ^5YaK9zЗ4W96:2:V)rH%SIG*vǗz iNfnL|.Q ; }dNfy FSFj#@ؔVdhb_ P}i`vː0 BQz]aɁ>U@4Nj̟2 tSfܺ}ClSMHoQ-`Xj7ʤ+><@P<78$扔{:%MfhHiv6"^EBnW|ph҆J\eujZJg~BmNY%KKa80͏ zwFՙM(cG,G*ôbܞ߽iLOW@5[ Xy^5- wX]+D$IBd׊MQ* ihʪA) H4՛Qs]~~0ÀMk1Ֆ9+槒F'F)qewF{=;KHtBt|7^%q؂:4U*͊884Ғ\dXb$g|3;6| xוּ=`=!a-GEs^h7oK_l+M )6T*assh6|g+.Amwㄵ98h?|vgc,Tk1ظp" \.W0MKf[3aטx.;{[Pyy,:6:𒎽JӋpi2La{Um[&NW[m&0f~nËl q^F2!5[ 2JTZr$=Dz3KrqYs,.Pk85xxlp!ȥ=z) >tAX1t;qUtxvI|æֹZXR'm?6ݶIecs6igoMϰa9#Ƃ7f,tZ}]nFEրLSjd20cDۃk(je5s2·Zw #×$m{7<Гs#] = Y`s[()1%:1ۼcQ1gkm$6Eu^n_I;Z6|&q G @uM>JYM2{xN,NXםT{å^<"5'^Mw ՏdQ0KwUEUwlUf 9ug[~ %$=Rs[xNdqڽ]wō15B杵OJ[ j+tԬn'a%n ;uAE:wew n=-dԬV1fK͕̜!^8ωwia#O>E؍Q0nx<0` "Blw"X_sQ4&$E ]fk|%s92.B[gxχN\6<2_GK 1 J oi .x$rzX]kFv _X!aV(oϡ(%rD<<;)r^rZT]:+PФˆ_rڼ\g~+Jǒ fG U.O(߯Y΄XYԫElGǂ9l\+a١`>'&`lSv"GV G#}. Խ2qc#/t ˪%eظۏ,NW!'<"z>}k|w? '1F]uZ/]+/I蝙 OIKV4tu:qUdt~ "=Eѷ$_Wz9G[E242w7J7ZDSqʂQ\+Ůc0ͶH%+V./nɞx3g]CY=I%[ߑH_HtW+YI@a|<~tw٩uC`}U:Y㤑NŭTMvk01>LBk)J1[#a3M\.=?ZHšT|TK*ψ"IJ{P29OD# VrrkZEh9ĞfZg;=N3#]nmћ8bMx⺟[91)s5El 9*⾵5SsgY۴AfuH`hm R5d13 2tP1zqd02&o_<7Ar _0Uөdsǩ)~f1"ǜ?eM+OwxKcoϩ5 3Q"Y[z,%'{ήfvX\(*ZPb&sPQ#+ɩnsIͷ.C#Oqf ,Ueq\2ysB_!sK4DϜhAR`a䴞>%f2nGMe|9C3mu 'JC3[.%:&:b^Eſ`T^V ) #h=KxR|eWV/o hMJhB4*V\yq%HJGn98*rDNfxuK!'y ilXD9p=BazK1>tY5yyVy2?V+аOI-0 ]ǹQ-7Lfi\n!Lzp?.s\X.wbr0mn{"FO6u.=j 8*e0gG\d@Rz>%@ S5:_)O:_<̀ƧxQ:X+Le=J3-L0a{ܟT:xOEDz{ Hvô[O5(ا. *Q4osL:C;d~cm_xuA4\(ܴNydH×'—|0 v_}"ftȗы)idg3;T  ܷQ:fJyD}ӡws.Kߝ`+ӱU^? tnaa1&޸o,F)3އ/FΖ|N?ҷNw ]W[sYwh:!DJ2@?(BGqcB(y#c;N1kd毘8[ǿٻtM9hDMR:%? :u6c]߱b}6M CJ|/c~/ba'帧:Ϫo-;욊jG~u#ћDQ*n@\jG:HfkjKmԜ rٻ05Kv]9xC59rR*)=`ՈFԙ>rc_bCa*T[nr:ȑ|7iLm" SNeøjџq(hw P1w X +<IfBS2[9{1t8K K {W y=EC(f8Ɖ{|>9(vC[9]?zFKIU|6?;Ł_X ;=7!ԯ}0xtg 7aάxl?a0ݸ^)תJF1%׮JUq?w-w{Hc<*qZNq(C~ՂT[ r&,Bm9_[gc}ԧa,={wS$ʪKZ,dqNlU lf?HmՅ L,4SKs;c:agG lRsm( TO]`t~=o=8iOhgL9 ҕs|huOip˚yb! AƒIiuب;GEd}|&[E=4z!љƞ '%q UGa߼fCl zm3@O?) ?=c uo`AoWSAq}^[|",|+|~F9 !VqMّohutL^ aQU|;+lmnb46dѱٓ4\^^O[WK.(iҠj_-z ;OGX*bRMӳZ/'b]~S'2(_ >Wԯ٥g`w_ʏeXHTq@AW,Yh#Q‚Bs!!|e[F6D2,,~6}oCXNm=s c0'o]P[&q)f gJMt:urߧYC!˄?бxIߪg4c~.[v|??a Wlo5Όť~ؾGjoPO7vBopyԕ܂Tabg~hwDe F9jK?۴U'r*/fkfT~uB2WqNJAǹ&-*}%VWkCˏ:! %<$6*Y}ܯP X2+۩8C >lP 4hMQ$sY5eZ֓nD/3zAb5Xj?(vG!. 㿎?EgD=&4=[6ǐ-\DnaQsSbH07]{ Ud|Ɇ|‰?^x1D̓8tܱ:F] rfҶ\: t%y6'\lȉT.Z{ <7s 7WlvG*KoᅝvX?DH`݊켲K5-Ư# ծjrI9|\uUT}zYZG-\}Am;|ۺxPn7(\ʇCS}ߵ黎Ga cMdz$qM2'zcPlK,mˆ'7EfScKPniV:=/m=3܉}tdAvrߌb DQ:grWTu]%Eǟ.d!߰dJ'(Qm oE.ei*t_g "cq3MMQQ=Ϯ_: ~νX8/^ ,\̟#|g ._?`ū#1핾\xTEym+wp},G4FOGaj+8d1.Q)O:>}X~$IfN|T?]IʬC|?c QanASE Fp@Ob6HB,} \T).z~`@.M~O fj9|d*j!U2%cK_iNAAC*-:#(pUZ(C?^Sӛ6 ByBTss5R٤y 7RAn\P. G<󔵭fkjjPr|O_oNT.]^3eDruژ_rOiJ(Љ)Z:n(,LMÒݳ/@Bo8tS?c;0eQlw^2F &X, ɄK'8mPgF52afN.;w xpHcEb Gt1i(4daBDU(ї zLd8[,[ļT vi90M/"Ujmvg%2"ɝ diȦ~pe1 f CGwQF%`!Tz~)7^dPua/3uM7SlmCAZF˜Z3ym?qXw^'<gv1%VFࡎw8WU(%4$"J62٤aMIݷB%;e I)"{s~'fcA2+tU/7nBM,O$oX=b4kID,K4e²Bv"Ӌ{FlC/Fه*VrW%j;ţ_f <7Wlj'&bSzʸ7ڟccV;yS8J.՜;UͲ-:Q:͂̉̌ yi]2EVd띙PkEοfCƳSAgAl["XU;u|2k;RQi=W~Dm0$ߜyz#Ov"Xoxl&kG4byf#]z_70! 5/9~ }=QaOO,]]*ަe.11D \ur$zI#t9+V ZŽ{{[lIM~7T$W En>jUg{ "Cn+ni{Dr5$|=mIW=%_(%:VK%U^=7QyT64L"zdWl3M * Y Q*oЋ9Q×z`aOJ(aDJ*aDS& G8eqPYc6U"'Dɋ-d*C\=4F_R{Z L3> ܞ09ezovs´)9`Nesa^iaj='t$}57$ c[_CX1#Sƒ^;Yy9VCHP w 3Kj#Z*ƕCZ` a\V W4PD WX8ȵ[Qź/k;w~<6vm)Av, PU\U~2~,e땝fEV`Ό3! Kh*K:TTa RƝ |ub}j 3^Ѡo :vD m(N5vO+``MtqJ+zv3 54ȥG>" &d3Qc?o';z! U w.7rLLi8vUlu6ixL6>1@rHiT< swH"5LՊ٩4'1X2%HAM4Taiuv30{>>&3"ఠB,s%-s:O={旔Iݔ?q-v=K2͝+zVxAQp1i?..D"' (1Kν]FBj~,pG95qOΰzok|N=ϾGx>w#ҡ]l⬭A37aD5fL2yNT=}B:]DVG;(q+,ExsJ?F\nK-/zov F~n*hXu k- Ld%}{ý[^ZQ˄kׯJy=6Ƚę}Ag>DyתD~O*|Ki4:b[!V1 * 6vo <Ƃ냎Hܫɵ/NЇaVvІLn(ϧߞooُLMaa;Ѕv,һ#ĸH3tޢyU% n0Ct sm"\j f"T_w׮q>",kb_Y䷣ǀD4 Ly2LjȂM)Eǵ49^w ']g#,+D|}tԍ1`lWZ3R~]GA<:+GѱrCC:ΥcZ*6/0#Fx 6 8Oۨx5|' a=h5fn bqh6k4\뗦bC(]V.+&|ǩ)IÎ9p+'7ܳ(xt8~>Mq=ݘ8JK X髵kq-%c? Gw< { ꢧKػi4z:GǬ0̧|r/_@SsyQIynl- W<zNiy= 4%\O@e$ }T֓i*&mx21;ka tbi^ul] s-X ܡpXqGL5$}{N ͙m;NngA/ߧRWޣ!bnDZ.we dn{ߞHKURMZzCLoßm\_DI<}:?FۺѴj1Q۱3]d~ЄDS_8EXI}qј^}F|9 bq! e1kB;S`4Of0* & ²J De؉QzH &4]\LG-Xĭv09)T0&/R7թ X[2 ]i*M$֬U55שj1%A]Dz<]s$V+Ori#K/u3wF{RMh/ik'*.b*02ɾ'|NT~ϟ%i/Y(^B^&sᠬH}mK翧]ZAJ )鉇n@j+.&V. J +"j'[0:55W^`a(Թ1'. 9yc1*_'jEFj<{=>=9Xu"Cl~("ŁE+Ϳ'05>FQy,>r`08{X8e[ zN ovǀ&(?d2^w̄;є.'4$|=ބi~ܪ~ٷPD7uЫgRaRѰi0_шTYq1ӛ SvS1a(8R?>+n5~A'k{~l; tO'%.C{A}P6/un͔C=^Y÷ݩ#ub*qfz4X:e@l;1!vI^`K,,gnM.IcIj׻~. '.^meGH·,ީeiF6s_~_/[/ E׶):ߤpq"{~6JBՇ*\dqp-1 =4.gABrS\S7Z*`UuR,3WiItBÞQ#~> \{(8f4ẗ́0m6Atߥxvv[g h=u=H9N>Lgl>jyqTK}_4JI";5NM9Y| <_[ʋ<%c &X˾zǹB`_fo33~AKyuFR n_:u m:s.A/Q-yVAx)0r+8 FhaoBxqf|IϢ'Aiw#˞؛BfNݯ1gR#r^ؓ9&ga: kwD^so;ŊY"O FŖnD9Cv^6%+󦝌M4bd2&+q{a-ġȨ4iP94^70'fs~ߴ"R˭ZM:XIH"_TRz 1so iUB)xfGz%1G0LV#=EۦN _ D0gdȜH. GSsI8I| _7~ieii1 륽}GLۗ5k' JR<J(Ņ'ÊUбT޳<*XE.oݤp ˗Zߖb9/~{ݶ#7ԽV- ̐=ߡŪH# %L:nFSq(͗ Ⴉm\>}XӐxa OG >r4RQ_+vz*bct{\3>Ui9 ~+|=rm),h{l.wI˘ TDly9lHAK8Vp? p5?>+TD!l|+R/q5`6˹T G}3 UyeX!a?&YTSљ]*L}O218auge(lc!vCasuqy,1$L4tXXYv8Gr/ 8d~`5ALM1 hy]?.<-th<V[0lb.PU,EҒ5^J3qgz_Vn:}9@~މ Led?jq܎UtI죏b%Iڋ[œ:8?Hd-sϩT|:yl/g'=(`.*D-eDǧ5Rt[i(aJcS]KG&Q B?Lm|?ߖq4v;5z" WrQ&*5A{*6BҝL " Dyc  ]{oyr`n:O,Ĺ xPHIPƅ:1{[a|t|06tW F_m93xI!7m=4+ÃPЙpňiVZr.a`KH׌ڧ92 [B>k&Ng =?D~S~ƨ3njaHo9Z-oi/(;;o b $YWŸ*ȀץUDfϟnuq$̄d{Wd B9H=B+/?:iaԷ#o역 F%?umoh)+ZkPqi~ t۱T0ZFM0%1}MvrGO=y顫Vg?[;Hks\cUh/klx&&C/Nu'VSn7d+Y9n&LVXd+:AKi`#O/3mp['Ǐ_Ck?mLJ^k݋v1UugkXs0_#&愸w=Þ89,K swG]1/0dу'*1EOlZut2x ΂ d7CMd?I ǸyݹAM>PP/I|p(eA"fre'$-z+CToCNz(|sPeR-?;&@5"klu_gRq>as6]+`kol4iw+y !=Kd)2RN׼p"^7|{! $F (W:sަ\78)  :I,&o}7MMo1; >i\prD8+bbZήb AGT9Eʦdo 7eb ;3[oPa: وob蠺MH7RYa :„Y(L]8ۮ\d"FLʱÙ.s1Zz t_Wa 9/> %l3}\SճABC'H9W' _4A5oCk;P VAsvQj,GrX!\Ბ0†k IT6?2Y+Ru<άب!G㣦@ 7?O>?cb;?-ou{ʰƅ,Of@"L=Uq"6zw,lb`L90 gqɋ>,͋WP!1w>Go2q^ȖtˮZ. ՌT'l4\iA@^mtK(_$q⎷4dwC^8Co'>Ƅ]+ioSjQPǚ:~Xg`#Mޯ촒coPKK,pxN#:7|Uʄ&̆'K:BhugalB↟2+Yh]VDr4M[T&~{,7LѐU5&ʘoIB)U~nA[Jp:D2|G$|4<7 eagsGDst?_i:J5{_4rQu{q6Νܣ, KPpeiww\&MC?C޴ Mx;JCD4/#kv^LļZV,/'j/ G(5|bkJSx\l]tΞ#¹3 Y[Ȝ␮ؘFS8|""_S s_q&o@ gYEJUruO#C7ՙDWk I/Dx7P:Wb'6ҘIVL;DًYYЇMijD;j9i|r1ټ)SگK,ʒwxޫاݾaAF->o&i#`Br} Cn/w=q?'a$I.w8-kK2\zbs?]|^v+^:TY`'ҘAg3B{\{Gnbv+9!2e 1w[;V ˓:,Ti0&`ZM^!+Y 3;ul~-Cty51ξP츯;땭K쮳Ӹ@ ~_w3!D+'+گ{x]73J]j˄DB%W,]Drk -TMG!^:Js`*:Y H4 )-+PTxO՚籡W*ZsaVlZgeWC0j8Ĩ}ªomzH[)WN7l c#ru *?"1"aFN%hQZ736?6uGȏA=dɿ/⥯^׍z(CPc*/&~=buttWރN3 Tu|H"MT?h,F}6!7#ړQIdZaE5Ogw*|`0u\3/9Lx 0|uPj6} SF -b=h8ԋUy/v10vσݒrg$u{hi*?VGp78>=Nz]Jl:w[3Wճ< 3ϛ¾y8aPiwmƀO Ca =:&'>;PA6sfb-z>]x{/į~a!rgcNE|M+E7!g{JT>nM#PL7vP~7tEۗ=$#A.mB*SfvXvήKhW)p Yv-kmzV|\m2Z&뉺ٞDQf;XH(:k$:k9LۇWG~Җ=RҺS+j_~`]xH9bTQ/)J`YlRhCFF4RNzM||}G%ɖ V jvZ#w"sF )H{Y'IfQO&D k?m: _YNVjȺ!ߋ>\ɿͷ*cpA&!&.DmqKgm͛L(D&9=_Z''`,Op6  VR s$3#:WXiH:#S`[KnGal __}-Q'G^Xw~F4[Oea@yZ<$YUcI'8@g(c DHT8xԅgdzF\8 ndB{:̩-ԏ[\m{`nV>?d=KMm> t(ܲ=$HGԽ;4LnNe7fhZ[:3):ݰhwm;Dii 9tT X;BV[I,[}ju^>FU]pU-كz~wN~QzM8wc6³M<ڦ݃~ރ;"^̺{ymAаqS=9ˌ _{D#*Z"n⋙٫xy˷3B}H/lZ4"^ޛ"ִe2 2qng&]o9)^.=HY>>r̍ưcy^=9t:RA v>d[+pLىyEOK .+j'tXp&K?]U.^7) aItY\{5rcO .ˆ7.Q_sǎ94xnG4J >[~ǬOYnTPA[;s`m.X( Go`O~rHm:_[0 șŢږO.҆;Gb9^Óp'xJQ3di֒őퟅgg`ulYt3=jʂ+[C؞zogոCm{2(KJ: .جbXC/*Om$3IiyxjT%/.L^{uswg^%sUDÑꎙ &yS26s+qu'ǙjEc̹9%gIt3 ʝ 'zNJB}?RXf,cb-uݯݵezћ:{~O0k܍gN|t,aMi^rRM+:-.khKW=3A4+g/I,!W< OeE|D1TY?w,_D߫jT]Ż׺ɭ[%џ.6y\zhMmԙwMȢ$ǣt,Dᏼ7dK@d_H4GȩP^+ne"r-v}eWR_hCx8_9/9pYՋp³f-NJfE~?2mŅK~@R::%JNJVeaYX5A 2}7M~Q1Fp@73#Qc=Γs@iWO?ars3Jͷ>0SbSe 6yl5o| {h5.fy#Mݟh.gaCDmNx|*x73|CSt4UVRaG&M)̻?35*޽f@3,>Ѡ6n3ޏem2utXY0hRHENwG;?!"ɪսNv*zS+}pRv%X<z;mCprCMnn+UoUUnKqIp/tyEm{, -R,S`0;oFv/8/ի#6GETzTtt>l 9䋐Hvikvឯ[hBt7TR)~=WډRVu`rw#{arij/v™5}#n|ϑw{hЋR$v̻PeK720:r>5FU6m %{~uȚB벿C͘_"[gg #Gрb$%crq\m^ ̛[+ Cœs+U#Y(IRΙ׽1>7'w?-K<_+Ϸ~ڭCTZ/b_=W{?xF]L.HuudO$sV붛6}$'wBnnakŎ뷰ze5 uU/ 6dU.";Uk|Ciim$N]Zĉi'*q(hs>nC>1EW"%F9z|/G;9 0.)囩-NVЌJ%:y2uTou:oNʿ"w8I) GnB eBY eDF2"Ye="EFDZs;*\y_un(Y0'*ZPd\f<ۤw۞_Fe!Ndy.+vzOV/?FNS# R6:w6q#t47$b?#hܣ7%+|n]5v XJ4`rJPM0 Ď:B\fC-钷$*!7**/P:kˆp݊0״<# lPH+fo'5[?[օ9}J7}+էMONTUpSiNA˥.OuvϧbB'ޢ[ڪU%1eB[i{(``䗊ٟkGD%kMʯ]|b4Pɤ:a=m8#\].=1%N`…-_Pg!${1KJ֖ucD^c'_ &v_Žadss%_YR?ywW`"X; }` [`W/aΔp$j$j\ eQ"_zPFGQ"٘46Y#X^/p*3L(-7_y彡>%? bUD_Q#>–O; aCߊA ()Tk0DxX?5 ,/ǀ{ǯJVohڇ|:k W8uj/˷@!P;@f cAK^.t"c[7tA}ܛ&^q-oh*9dS ye:moD4':N WQvɌ95ԁTٟ{#ނa4fl̔΢ olL:5{{+S#aVmmA*@iE+gj6ߥAPUvã58ZMVr!Iw[`8.Ϳ 5JaNAّ_ͻv"% ]'`JrĞF?FF@c⼢J@}Ձ>QEZ'x{qݾGfU= [.uW郞0P Ct$KIXFgPF\#:Pmt.;y@AV66Q/ fK?nHO1 6l ̎qX׋^Dbq; |Wە-cٝ֜Lh6F:YۏS"72Xq鞞ȡjF t Wt|V 6g޹jo~k&΂DfԿb2 T6̣Y?Yv΂B`<>vXp}xṪIjgO ߯~jeD7~(wIX=s>};R.B/CB|aY_d`_ؖF)bYz#GpV+ד8#Dx`£&/"p|%?ŵ{Ij Ao0&kVk}.y~ Ӈ#"e%}H=qBoRsX_l|&pD0h[oT7}J }[ LcgȦc*ѩ=lj_rp׆)yGZUVׇ=UtNS̻uװ)Y[Kq]ޜ6'[чg(OkF^'og/(D].=Uph= X13/76 Cȸ81eǑY\ Wp{b^"TlsjƐ:{((2Uc\3{?QѲׁ?fGc|:;V \#uFZ'nS ^hqK1PהX.A"w ?df/6)I.!%?rg7LUFclw:K`ߎ]Qfr2սyޟ?ۯZuLe 2%XVFMfqb& I%"ʹ ѧ^Ͷ'5Y6pHGPvH4mMs lJ նZ^2~q[:F]yt}* Lu"Shk7޹/-_ՅLF+w_`o'ƞu q0Ӂ :2hjiëP:ݾ w@E;]+tvEv"VQFսξѴW۞'«9H"o`g=J{ 5|y$rV)Q̀Y +zX>T޹E]˃)PPᖎp ilMb2nAbg Ȟ EZсjznx[i؉(v<.On5f+=JV8;;MSj&}G6/n7^zs#k|gi:xԼ[݋i]lrvO - }K.4FH sI`PP|8>+|]86l~)S2I,T7tNA\:BcҘҎ-%׳}EIu]?#T#!1ymZm9OYsE|vݒ+׋}(tf]-r+cޗӥcSgqe4{VtgoPvքHmꣶ=4RvBIet;痰BV[ѷIv+aEMO6Hq,"L8x%OQ8ZNlOIG ^揺&YjK mO_uDwrD׃hUɨH]\ڮ5VAKfc7*l=#j/{֔oj; {.ri@MkOs>anE/e㻟wBq]G{*K2q⦩bh/FplGDwlVth?B6a6U`ogi {?^Ev˩jЎ-?Ƭ^t.im`Λ9{ɗ1&&rcO2AbwО"Ŗقy.=-#e!!3ӣ}qoNy >HfO2_f}c[Rsla^x=> oOCU|\Lx]nxraQB+[2uGw>0aa"V2pGl?EdUsf'wVsT+Ӥƌo8svaH}^sCe$Pqq^ama/Y-jzՎʊ8k4oƫkAM3Z,P5OSk͠g8fpU[}~j~d->Ru&X?+YdISTيځhlAiuEn3\R\!ߊWcRiS༌US+t4MEn{izgVi鶊"ZVrVF^3&onV.ƺ~ Vs]zKt"ҾcVК#uZ6 VwhxmMSIw7&Z>:`yM :⒅.[Z]Mm+VrPC:.IkR敷TxeHQp# q ֮\` ^6^oiZKs.CfkGWIY}ATΎo/ZGaܪQ׌H{qn^ЗE6ٜZFLie@C^m{zd(qNw<:._RCۅF z_=ʶcboOnPCѹi ޞh[|?&WU͞)^h*P`PF|զr.rU1-mY^㝸r^ԬjZgLL8xf׀9=ЏKN܃\q6z7R:>5byD9//]ׁ%q.iP gENSD+XNΡk[ .g@s=2>Վ|QhHk.巷6ҍxTa L ܕ58v.4?m#}QuYĵB+&_:3YQ aN&_=긾"4g`Tu3V68yV]qFdjLj́ÜTTHwrߨ]淶׊ Q */Ro›GNCZ~ b^Xw;3|+ՈgR0&ΩvxHގ#5u {KkGOj}mN\Ov_ǦVŨr vsHt a8}BzgmWXh*?'~ľWk(` GW vJ ,_ׇCϻ1@C|5T,kՌZAM`noզl]\_e7̄' ?,dRPu7X(R,'gh\d¥g(}sUߏw~6pb}a,D7G1}.%Q¦drb*.J*$!>6)@n ʚ z2V` *+}EJ}k[F]oݷBd=s-zcQI3fJy=[I-<!.%Pd)BߎkԳdp`D3]ʻ㡡=n:{F?meDowJNuJ%eK#Y͝H.I]@ֶDl1hN͊HM\<e ͎.tja` `#)C_ 5⏈^Q!!(Z_9-߬Ϝ:N?sv>f$S,wwy3ۄ(pXNcb&Ĭl`>e#d{] dK4!Qο3e(iKYE[%-#7x溘XS̉I/%Y#UXO}wn#{ŜuY`$N^ NN"u\<f]inOKEb.h9 :ǐ5Ya=G&T[k^ׇ7W<+WQc3rJm\0lKL}iF;ÿ۾4;@}ݨ,EϬV ?.5> } =5ӿl, ݣ(np&ZٞW[F(:~jGUƫ7{!,X_2Ncakb}y(Qgᵗ߮:: u\7ȟ8 Euro ֎LsY&BVE& ީiae5nwCXf`aDu Uڛ bLhʴ4Ob/t[CYYv-*۞~nC ==dj㻂>6,͐gB&j!$nf@?]XK-;"oOC4Ԓ"U4h ꫊"=b;LiCc֣k^{7)L{!1f4;q~;T=NCj:?Yr zSq *R끏ƴ`\Nf^} :w -DplZ%65_"p2ϻyiZ g8|3RBEF)R(:(魔dfo)e%DdB${ϿiJ^;gu]Jm@.Vjg0nHFUUb7Y(F5xMWgm0w[o-ojyFQ:᩽ڄT MȾm* +|h *e(t_qL5p~Xg#y nȩ{bjD6JŹf/ X>LkGP>V>ܮ y!#c ɤ M`tiP]e~߫G^>/@Z5'w &5Zzy5 կ/Dw+t0zFDc`ڸVJiRpNl;M3anI/t ewT9xy~ӳ7;nƱl?M j  ӹ@JG7ځSH^_i;BX@cjp\lE>u9AA=$us"(cI a^UWӔ{8ޘޣ':6Y'Io9I /Ӱ {b!U|R./RJW8kՇ:'j'Wi)p"Uhok-7[ 1NJ8gocrdEazyn<O߅O+Ư~#n]WΫl.&4 C u~X h61AD vhY 75P$[U'ʅj>.#;]E:WJ~IVcɤO#8BVߘ|~l_< g$w@?2Fʧ#+W?Vbx:m\|K:p™jh8|jO5зEX).(?l)Gj-,2آk=TV|_֤`NQX6&U@xS37 QqC Hݩj߂oXEow,.hphwdQtUy'8|=qXHEP'Rق7Sah.(R>=ҽHO c{}[|]KfD]oҁMfDPX :FΗP]\vq'I|E?7m&D~oKv'"-RiznYLkYqpvm[qܰG- z]Hь|S1H Z1<=D~܊pT3&`9n/gB'd ZW?=+6R̹ho!w-"f2~V&*i`m'UȖ{/Tka"W8Qc$fUпDѻnٗP)K)Wu^P%gSФؒ*1z{tT|?aWR-;5\,wb[hWnV #^eE!ʢ %h%yߌT*Iwa`I xsvh= H.$I*%)?.I^{;ɡCˢZإXXhqKe 76&~ BK4Gτx`cH://>B-mSСbeNg2\*J>]/QKG{<+2w%.tx0.,ǣHgSψ0X} v<542^_5"+g*w^XoLtSrU69(s_Z̅jRd\t3P9'k܆#3f06餾e޿7̼ܗa7ktoBP_8d|Yws0N_--u=mٶ]i0 MŠw%Sȋ[NmCZE$~|MFq93t-Fd::)%C81OGwLV]i7<Q%fLo[֯Xw]ַ5P #9muN#_`RyVlߵӂN#*-Ws ։.مVcٵ~tV-hT1L⭌-8u%V7k&~br/R6dt8J0+0~Sج E5KbUbиn\@~FZ_9v>*/rClUpݶκ"d-Al=|B.+nm{9Ro%5nsL\|4reZًelQ 6[KL}0No[+ `sޒs&SX3PR\5 ֺEͪi\-AN* (GGKŇʆϛARg=bRx`fe%SI[k#υ9~@'.'FW4AOŇ!֊wPrgq33©W>fS~:yn(T~weM4iJRչf=~0|߳g:'@H̿Kbk842gpNsO$Ⱥn)h׭$:)qĨr +^l?ԤF`dswvQq2zOZ:2OD=Ѱ#CXGT]Ӊx$=ըwv۷I깕z;Ds3>="\s*ţNFw 񩋁g_Ɣm8CJGn-#6\Q GJ^6Iͥ05 Sǧ׳9rN/0_5*} Pc  C KAy zV&5= m]}ݩ#y;_ LC}oL@4~pLB(KUyvo (0yq x)&0˱Un Aq{PLa]Q*ЏNJ3; / 1h5ip*6cfwA;/wiQ wͽIJOC^՘x%֍Yna5Ε>poO iIlƍbцVl 7^d M[0xC7fL̵Sq*8hHr3QWQh#\\CrϬ&F ^9h߻fߢՊ#6N&/jVYͶO_4֯mDuhěu8;Lfr2rO^>3 RK>8øVg7Jޚ@G~R1i)Bl{N+Y(c[L 2go/*Tyt 3,Sm2}="]T#y;wY:vaoy9C!hϩ5}tb4y4 Mɫ,lE< ɕkUt^vX`}aK)RUl,},CVwm%v\{.n\TLLEp֘^*q%sm)2N ;]+8uV "o?-Fj*`PO%ҫek:ȴA:b7r%n+?k+"USSq\ڷ) ˕XS5صT-Zn vG]e|5,<)ʓ :z,U: eÈw/8^jAҀm:z=e&Z 8!,5)pAaU43ܟ %aa LdH6}#;Pj@v] t|DK[{9~L60wؐ;wPPZن=o[Mu!!Am;y~Ö,| kˉMCQq%P9ֱY:1XB_kfqM3d  {2ɵ CL):I(f3|(hF\zN t[HG BX ֥HGG)I;y8B)=~bG8S2?jR{<;l#"#8=ğn\ {YtIR!OY4LSAW)qX{z~?ޱ"mNXkiB' [ҭ3󖄓b֦}3.[r+7 3qmAxd^wS|irn,L6:MVGX84RbaG9@9M۱6&'1tFwh˨ckEկzh!tҎ uZ$)Y+!豦cTA`}Iɇfc˖Lm8R'lK2u ^Fd"w2_zi\{)yசE&e봳7E۫'7I0^ɚ\c]S~d\5Y} " U[ҟ"1M:haI.T8` 9{-sh || ׮DΙVpGs"$sB%Ҹ#4Ymf~tUI'uu7q#:WU;É.*aP*/ . bv"3mY>ܘc4z?Ր_L?2$$s#Diݶɼ+dm>N}©.Gv({< rTZ 7|i/DlI2 H"eSFfV]"{Bps>O6蓐ޟ!F-g⼑Bkп{ Ed>&h}׽%3gn(5}aO1 7-rqy7r'}t!\ع|l&~^xA|~oJGB¼}4Nj=Gvсd.YK~r0Huv$4:; _<7Cqc>(N@iMa8!d:#7:$82}=/04cÈ9yg׽ڿCnJ8t"X&ZD=[tCiWϹA *lGKY Z:1( sOh)QJϮz'0+gD>c:kTzzƐb8Ø$_3rjd!eY_U 6Bl)+mZiA읠xok/G繺1ߜ L=EI v?hav^vJQjv C `ֻ#؂ZY~{m)q 'IcUu+X?}u;ijl(܊ږƇp(|}e;\L *StiZ& 4N =GQպ6ʏU3 ֟ i*]FdJS[{YZFq J|ßp^M!!^QT?jqa9sgl hUf}svեR\dJO-MD c*LWk|hVKo[\(Ƕ,IN\NPg tưA/YϬm\'NV\\~Q@UOk;?XM3]"'L&%\ #345?&= ә!?UseA4Y}az&ץa;b<~R}yө~kbBG[f`dvuGְxV`ƌOC!;RݥJB=2L6),SP J} })%CB7&lϣd2D*S1ێp.5ї='#fKX~Cd%^1q$Ʈ5weqvd' \~atP#Hxh .bB )-8^iTNxurגQ:Q7+~cR"+r5icLHWd|NgsŁL΄gd5ﻞR[p!O?x25{P{P[>I봙ߛGL;3ܷUw:4 gl$u[uL;wHYW)eï.FcR\gڟ//v+UATwH^U[Л:>kϬLƻ47e(AhNDM祃.>yr[gN,f&:;h)cW^C6?׉xQbw+ .!q~SMMbeIY06kS^V#%m)qNł6&vY ]n}n:$SDk%yʢ<₌IޱMN0~]i$eLsc~D"w8VX?$JnZ,뺁¦-HtR|C\9&UfMҸ_!%ѝZQ9$vm]baDɃgwD_;,w+4?hঁߦSCP}m}U;<++7_*ưϴxZc$GElڈ%m寞:tvCTPýo"n3"xߞݿ\h O{/Q*\F,BoO$G.*e2tem._*j1쟔 >y9 tCaוF8t(akZU"g!,"4VFn糍Yą2>}m)){eyj~CQez1-I.+}).9P!Q.zaCmRL٣:~?0۞QXqѝ?1gG!e6jb4۟5l=xM҄Eq Сޞ?d'i %\9.Ugk;.?ҩ_wi^ ~}QD8 %U<2kl7v,dTj6=Qt4 D]Yl -[C!jVÔJ>~||Pv ,JWT }a)YiZ/n1r6+^gifKPeޕ8I`v聓0VWdpm pңrY!Rryo/RT֗2mXoZic栿OǯST< 'kӵ@̼o0w˃.j5MI!2j0R.}r#UQ$xu\Qeyj fr |bOaax}ڌˉ/_ @H+NEK0LbG^i52ZS&Ni,0A?*eޞoEN]B[$KUBﱜ{qYt(] d$ͭoxT`vQWNxz_I|Keq˃b 7Yf"ؤ KYҢ p,R+T^ʒu V9Te8SKRʓkH߯@zf̽i?5cZpL0Ɲb,Q]ҍZj}{Ōoj~޻SYVT])rITD uI& .=vc ʛh`ŚmJ楎k# jdgb"UDIjSC28rE_ԣ,=—C{V4|*}e )nǙ6q.g"WT(vpb-3-2^zZi$D2X9o]3濾U[~׵/v̬asClB}|E 'p,e݇UkHM"V{]ٯ&"ft֡VІQC~ij.H30q/GbL6-8%>: ֆɧwx}߄] >~>T"wjxcj&R4Ug*/t>c{f}~7<>3 ϒY`&ҐՉ5qkApQ~>*|ak1U-Jf\?.^aKQ7>O)cFz%j}ջ0H\H>ѫ+};+ܱyeoH\sf$\Q0ǡ,W;1E ]Ј׊"7U=KZ1B-wO7xQ:y߭7rօ9[oxw^:{Ȳ-͐]2,U#ɂhmi-9WCrmdyBFXlOQ[L*׽Q]Oд->Gt niB*^΋^Z6ba=Iأ_J[-cd.8z;~ k8GX6 +^?&]uʚbS:qdJ\)h/?qs;/i(wf[+tXlI:6ŒVzI[7'o\ 8_#FˮRI,:CVG@V]*hT坐TuG%G c~7SynٰKQ39Ì־ZXXEK9s=t1'J1?c0V+P᭝W (k,s`[H:y\~!sL7v!'Qb.?庻z@ ;%|-0wae!F6+O zǘ7S'9 /ϵG8}V?Dt 5JWR~{Ӿ02rSNN:+q-XM7"Ocb(LԹ^7b/k?Z:LAvRXⲰűm9x/\Zӎc+'(Iv[3\ͨJ+Se{.3I>}Z#<nNd0ڻO>jvJT=#$m;Mə-LzL?] \Iw.ݾyѾ V6L`7GB8fd %r$- OҲOR3`Th ZF>['mǁc0b3q?ڦ~hzV?E1cX/==q;aʇ0EMac0\RElq8̝{0Bc)(ۋ[_c@n[(r1ȔF==},2{ՎU6Xө/6:lbކ2i&*7ށtB/l4,~&Gz@9vM+lN*_@JbQ +;753;}+7 \}r2bǴrQǷEVc0q3jޝp ;gnmAhK%}}Iީ:qUnBn r;c)`FUH}bjq-|йfY1|J`6-["KWd8>G40!9[ş`E>k>w r,7w0]ŕ)~=Rl;B*]@v?ީYo('+<]9w8R ҵ#d].>=D7)t·rBEJ)Fsu!jk6&"r Roeq0Foe|Ph+C ^蟊wGtU8^+᫛D2+L 0[ph. +=)X-|mwR$17K=H~eÝL=O>KW(vgLuExϜ~m3ϑ}((r\ ڨν9A5>AFғreT̟q &|M+僽dv]_7\yY!h}3xUGpqr$)rYj˟IMw#@!w(6a'z;ƶɋ`MYv3Bؐ)ȑG^G|Щ!#qoWwG7ϩ?*Ugf u]R+Pl3ko[8# odD'j+V[:`GۅCӞx$(fǎ\WA|T8Zaթ.rJ^ }AIJ͒vT㯜Zt}vm1V݅8(ΐ@ zCn{iRUVX~`+=hkAC~-՛ ˬImg6^Z5jC̲M3µM' ©TuՈ0ڂ]˴M n yBݗjNS i:IzhE}VTa8HjuNy/-Ogh9$6rpf`W5ܹx1E-ƺXSH\;;*qRl:n*x+ay2\|39KZP8_֏_f"²3j+?-м ݀ ,('B{į^H\LGfŔqЬp^VF=l i^m#? g |J*"#ڲGfJ6!# eQVx=Az}:srnڬUNP wPN3}zwUW)ݰ8Y.>h_sctbD#"n$z((Fv?=38Qu El*ۣmUe;अ_js1tY:h nU #<덪|h"[]>BL;w6D0iz6+$8WPuYQ$jV?u„ e$4FnRֹMnϥM^C θUF1o̡7AdZUU ZC.SRA5I SCE'|M!(3o8Vox;}B5 /.|]< pA ]D߭P01ySxBј. q jC'8 Ei0*pX'(*k"&"ߪ$0 Hb#ϩ> %3rR nȟ*LOPsfU8jIkWC_'}栗ZjBJs,-|uѺ{i=NJ[uWzde(XcHC^\2hj2AtҫO#g xT4MzGԣ Ɋ"+$)ld Cb&h^JGZ4~?tBSfࢴ0.ug}ywh/; ' O]K&j|8sAljͨ;$M,}JP BU/&r( "h*mO*`DY6 ΁Now3' XQyQV)4jUjB<Qǣve=pKNy/ ɗ.He(:ic,4<`x3p]+z/;fG~uYd Yz?!Z_0n<W%_I?`k,KNKv37M` O`[$$Ґ7RiD Eyr4g} }PA8סܠZEͯ[<3 :ixA 5 V ѷJ쪈d]{v. x Z@kQj8?]UkaFDt^S.ysœS ҩ*BzK|ȕIO%B._޶nk Qkr~ .OY?p7 }cpqHa}|uT԰og 8Oq.Ǘﬕ-| Os#lυ_mp `0k S^*G^$} `"yK'8奏C鯚$C L0w/B/yJevkx"" %a/ܘ 3wT==рj d~Cܴ"xZ%!.դ=^~ԻѨG~[81Xw4o0OC燫KPq gۡuNPזlC818)_C5ZysLSꇴ±'ʋcx$CQ'\o1.P45v+HXwVYkPĿj.;ل!:%0 xmB󇚖(Íq0_z 8'/Q7];Lݬf(eN ]ǎd&ER>օ*O6"~^lsm%}N 즔"3I."{mD{KA6uyd.|T`U ^_~sKUt,6tUGsTᗶ:`Q j$1::\%L@-|O,Kz:: {R ,mV}{h5:~Ld rDwkɌQ=<4QBߒ3˞[JoϠʲPP5 i[ D"S8h%:PpI pF=4.SxSu{~>mCxw[wm/ m5z%Ei ,9!/\.O^ (ۚW+&S cqh@: Q+wY[ӡ,N>I,{,aP=+ot!َ5~&uAuKvv&![Xvc5{&4 Y~8[=1ax"-I:O&f 2'C,}y:pA9*g{ A%_,Y'g{*Y vYFR== 6{̫-p/6bdަEVkOgrzfG`0ʋ R>NcH%2|rs8bl @AVpR`R !IV:0x^-yDBE P *?,6ev<%c{6 Y{zejᑌJE6V t$y-oI4~ޅ+X v˜^n,zCEzNu 8ĬA)-rbÛkS3 pk俯S+r^\O[)ڀ'I|ɣ&Hn0m_5 er诫YܦG7rـqQ.?({ʹ)0>R\O-Vz!4hMW: k!Pis"v;a蚽i 2PP A^} t+Ǫl>c|Z \=6Y0sN*i;ykBB-XߝnyX^|ek, lr-I$\tL>7Q7}Mfl6U GK2zPhkZڍ㈭+3-N9 I)-Wi'q%rra300_g2P]"bL1d4CǻnaZ"} V)<& UR"h$7C~^?RB7h\ȵ 5\yU фr1uyF}Vqc%d@vSzȫ8QhԦPeh_(~9!NsL;Iww3<p_ 9dlv^PT&<z7+ @p=d` it#kaqV'ی:F&ߑ G=}Ŋo4fe3bUu24z02>5*1wr;dlJ[c6p p8Z֠r{ aDo@. i}5j&YdtA0I=lqgLdL"[EwAK%oƯY rL(vD ,OJ"a?So5 [ җ\[ܕ~̓y> ,1U ,$t~ub釻3GnNEYBiLq[ Đ{́{d/rVM3X˦c#qݕ90546}=BJ{k`PsMn9k8HaSCH? WD3OW }5 8PV̗nUx0@6X%:,9Kw>0lKif Ö9>W2ǽE{.~;gg\}sN4bn!q+*|>^ثi}R(h*d7ă~%߳<+c&]O_Dx;ͼVkc:`/'z+^]O-hev,m(&kRWCL|5 ~g Cb<̈Y t#Ϙ%Wkj'HpE> 7zdq0lV\2͑4OZ`c.edhŸ.%8|g"!ԽmHb8y()44Th22[adhaW;ni7E垿FH:ntܸFݸ*߫ .qw+#¨nߕlU.G|;Raҁ _zS3)[7~) p.Vč3?Q0=)ub HjNb~%(]s;\xF{4ahSL8E댊UbőMZPtVkXE;ic|@arW?2I!p㘞DN _ !geN }2{xS}F!tcquܯ18~Ѡjr@uo;gBuXRYR1zKb4Ɛ#RtQ,L]aݳ̅}c0cu?#'Yɴ7NSmÜhd.u3 BX8ynS1$+&@Q *- 8N.pPYp4 n wA9:lkC&,zFO'`݆2 Svq]7 zDW`Cε6wVph &{k[OրA?A7opHaNC)Ǯf"x@NTTUk;bDs?}p}|A3N-'P۾.вr7Jf ]^N[%9yF|ly-6ԻM*@VH(e[jDP51rDHܻ CR;e @3R{ m] %R)Yhw(4zZ:Am 6^V hon6Xo(z "wjw] p>ix!a# B6?`ex~̬7wŏ/КSӦ5 z=hCw[@lx2v!ٝ%nd}iɠ4 TYB{u4#M$i>?aBBҲ/*ljm](C4! P xo$= k(Dr0G==o:8=2\VG 7W4 }$W^-H z--ʟm]{['{?zIS)]%>G/TYۄ-ctsf8WX9 P:~DRH}W%"N3~ 8!u$O˳c(SGL ٟǛLqW6op94E[/կ>%T:"5ˆLC5@ yW g>vѿjϘpw#R6\T|aݡZ.1o* hҵ<)zD{^Pw+TbAЈ!9 m$ K|%1ZP#PKMimYFN[(yGNMF<) ||,b$T@͝  g# F[HI(%)2*%"Jf"##;![B<$#QphPLW"1W=V!zrG~sIw^&XTqWdM*4wH_ȻVǣ`hAz8gKKG!Zg?O 026 ZחNtNA7>?i8egOF) 2/+;7 uu' eQo>yLTIRܛ>NƄkNLPtSWdgݪe[%t) F$hqtlNU2U6o* h5\fE7kFƥ N8,sƀqi]04:c*zhdf R.LV/ @i bnhu=>0zZVa}mkgH*M~w; ,!Cm+r1_Ni TY tٝ*@MOrAq\ b}r_5_HO,~)һ:ylEq`?4>VɊq>W|!8`!l'IKi+u43ϡ8W['LY뼅Htqd'oA6EuIKЕ/JE2SUTR&~ >.Y/3>@= qBW_ A;J,r8Tۭ "iA i&MR;ώ`o4 ] yT?{}g(qw%\8]j{Z= ػo˧Nf\Zr`}d@|* ;on ŒcCy)_ nAxk&ɱ3BSWmB4l[i)O~俧0r{m08kJzToǎ^h5 mjyl#̠xK.7)?mr' [xp໺># 0IZK.J-S~iEQGAv^nQWHc%FzipxqP啪 d.S]eaEEKZ)fN9lY)n [ {{w+y-//ݲ|1HDs?H .ށZ+ Zw[A ]_: WhԳ45A^&n dڨ2b ><&1y(bu|@B9ǎ&>hfo UT`D8k=}GI&1;=C 6ܺa #[joBT+ חD;|ǹ) ĈPT\>>}Q-'ECU^%O1rN +3'tV-N?Sm gLN4osvl[{b#i#11apnqUѠbT؍ϭ;?{U)U0kmcU˯py*B6)TK@pUwy $:W?i's`= 00釞kgz᜜2<+a"7pj@,`ҜSÂ,[Rk`^ c3lF@_hALH^tkώdĦ_-P[E,*!E6,3 0!`5?ggsQy4Ho)i{k0P1 <.S0Ags$4=y`*1 Ujk `A,@7*Ű}"ʭ`bU6 y׌'{ӣ,kp=f#dQ;o5k+8Tf4I.xxxZ7.9'ٯY@u|l>W*'Wx0u'?maޣ{*,>G8 @͖H|Hb9^#x֑_P LAwKw-2:Ɇ`OCdx7j> n}~[F|B$M!v_Rfx=ct.n{l!gQr*b?/gj<#luXrMX::Ttw+87=m묋^hosFߠ-e6/_ hN0 颱t)dtwQwáPaBL"lP RW*uF2j] _L+/G=>9չo=.,2RݔrE=+fz_WB,AQv*hk"[G^$=ȏa@]G)aIV5G7e~Ҩk; e9_qC^-\ӆ_T m6J+FsB VLJܰ谫 _*d܃[dp("*3 oxQw.U`eyEshǎPyo99#5vc<6\'JOnǧ5elaԮ)>$Q#7\"{r%wB)KjѼyD?Tֺs9J /t{jcofƈlry 9 ?y[ W6W,U.](k{VC0B#F /Q~5l!ð')4C[ Il{b—IJT6×4+͗tD<0ϥ  zH oY_ Vi*16[@е>x]?ͻFWH')7^TkAl􌕕05WDQHԈK4 DI0)} J8 L;ܯ }aYA"S coLo29ۓPI| 5g&W*vnZLe?ѵ Pߗ8 ,-)ѓ0A\fId%m@XuRo5O~1%A; ˁ-x̱i|.ox iQ{W  ]e7Pc t`'z1άtvDkY8tsrr+„?UKSA:lwn_=X>0Aik\3zl=iI~Rx,zB45&(+2GJ _dQI :m}%sA884q%n=jT^ŎNsf<mhxt7G ~,^.d|f׶L) \r{$>e`~!G6bo?띒tykj h&CvU렠o 9~Bv}<(ɯ^:bL]ctEhyEHIO`w: ff(gAi=b?C6!o: νϏ u<#44zIc,P.wTտ2Qyٹu!QZֿ)RG3ЇG+/̟PD-?WoG]ſ:籋"NSWZ(KS$41 im )# J(/ aOJl4I G`!l\Q1D̄E@CްQ;2d96 >Ʀlڗ !y湝no+sKzp_qOSM_S.by 0I.y3>Z^WUoK:h0~I{2)CC}hS5R#JЊJCaJ5 ^]!-YG5L^[u`jT̥pleD`M2y >'̾M0 H_Df`}cD}B*etS Y5e3*^UM *AJ, 1T[(~*9݀z4t}Jhb5QI# ,WRH-B6{XdQ F|-|9qvmx$`sr#R<08~l_|ňdok?8ltn2X̓=GoS5^˓@f*?UYLAn"PԘ9߿;{EPwQ0Vziok\3E.0r֮\t}osg>t`&$\ĴC͠PTn»S$Z䩵eBY.x3&hktYn (F[VA PxU CɫbpHnrh WUzAߐ^Dg8v;Hu5_Լ|ٜ|FZD(sr|p f65a1 Aюg~)9kaWw !)"Y@ψ/hU]}IVCOEw¿^FXr5zz"Z d.2Z=sb(Y]7k|Q[!T27+8m-wp>8K}ٻ͋wqA[%]OۗR HLY*nHX*..u6=:c<}D+(&3dN !=ͻFԵ5ýغlQQIm3a*.`6Z"ܒf`0bKK'Z_޵"@K¿h$Z<%F2k@rg)&_`SM0@Weorgߥ@gݓ/``ᮏ.c$@6wf>wЕn,YV H]YrYwo5pRB'Ǡ~`3dݽ5zqF}V찿sLH}0 *xl+48Sew݀hr岒{[G{aA(p# ?]g\$ǪL9LZN@m?"ͳ^-C: j?.Stj]PS *Flߥ&FTS1Rݯfln9[9 T Բ}.|h?O{DQe HUd=aQŝn~+cF)o% ߸kRsM>&*:=ZG%PZӉ  '#i]0$y?y+bG`R7]l`"&Wa=x51;[eJ%{\-}Y^N= ?nK '`\w92|F+8Ug,'5īLid/#䕞9Y:9WxisVT;q1FG;޴zcʢޒ]RJԼ?6\ ѮOё&R;?>j$aAoS-ISSd\^1Hj4.ɫ&L0$W8= j3'\мIrh?g*>]ail_O 1OiI1\:!ɓW9۬D2U;_;a -aeWB^qog`@|L$W bF)r5 PJ+bCV&1?8&hK r㞀!K̝b`>kNT"Xȼ?>S C][F 1;hЃ]])KDhA]Le [isz *aiɸ0bޜfB1-p`<(1[ BQ*s݂?8(阊?eΐ2B7*StbC`/zlTMR8Vxz t"HLY _ hhg&*ZTj(MwJ{4ӞDpTi~@/ƣ,_3A%i$0bG_A˹^w4;r-.Ap4IX _q0FY`2)JX,˚"| E#c`7tu!I}[ vyjFᬯp_l2 `mw张T7 vqe=G(RZ pZ_ԎPcj9Sb߂{|DZsqZ#!{>="dr | A!V]No[uߵڸ]?lJ)^Ut0d96aki%[@gn0,MEi C2d77< J&**P;>#'2`ݘ=yG)D-d)zjCb9}o&\sH3 oII or|7JY: "0ܭ<ѽ FM~naϬY8%l{7X>=(3W)bPPxM%'!šjxvd,x6˕ӏx#| Lx?혍V.p+7G3d2o:F yfI-"]+맙,秽 NSyeBEYh$ ܇S#%o] 1C"CW'qJ`>pmpn1]ʳƇJ>#_{[wpuul@px1MݛyD!ݒF[ՐҠ&ՎԵV^Bw_àT#ڊ8>U+MʵZ 7w!ݚ\3t'[`y-N%n=HMx4jes,qX3%hbgRȌCx44KO̧2vugΓPv \+ȂAFֽT"i$o<C^|zD(I*^z"l^y? RB&5%8C}Co  f³Wa~l3NV}#=u$ڿ]o!W?^w(߯!-Q)]Md}6*~ -Sq+TJ42-~w4p-]/[XZmt03 2Ovgw@I.(n٥"o`ޤR)'\nSN)?|TE xS_%L>Ip(e#papf*qT U^݆6ԥͭσ^iulsyd£NcS,:C(TO>8%Ru!vc6Ԇ߻+kx@_t]zk(9jch܌0WPxfU奝¾5j8*qY!Ph,QeQ#8*s>]e,g`0lY1@.=6?dzɵ%&NGCftr r,kbR,wQ]2v4KqpVisI}Fp޼헭\i+ϙbB3 &x*e̫H(t oFrگtAx& cwU0 Q;|x w#ۡ-rD<, Q0++\5)=6p_<^b+l *wem_LٻTYG)0)^*[k`K6tlHZc7myMQ3 zTiR0IGq<VZ'OĂjήLZl[o {sssZ~] BUDӠ~s%^MUGUO@ 9C͍ (> `xRYe<.ǜTRb͗*dch|dyW;/Ӫo]B|7S?Y/Og4Qam:9ȋ(I%qk>XFdSǕ< dBK(&wGHeIe/PП k)Ed[DgdZ 5hjCMN7 S."ևٲ c+0Wo {?/;T{U&ϴmƥls,h戽;m[y EL>˃897 TX#:F_&9n&Z<à#$NhNWeY*Aj i=)^󋓍7 ]EO=Q-JlYд2J!v.l_%*է{׆a?Gg#"/wH}SV<[[![p.&gK9(ji8'1W{:@bxf^ti̓g,]B|r"0<czh!/f'93{Q|Su0R_ Cza(}eR=u32TFͥrA~7Lw@@\XZ q~صCxrL_qꡫv&}ߵ-{ )ԛ(C`/A~x2Z>.ꩊwm} M񠞍ָ,v5WB gˡA;pl_k94+~[Te|AjHW~f.=\e}O^.z To/Alrѝ׃j;~2=;B#Ң< fJy5}8&xB{"]?.?wч:U#\X[0T=TE)+ +75,Sh̊iBTCnUm\ҁBW'=#Tf5⎶1,`6moz ҅cG Hmq~҉~ mW-N~%0nCypW~vxo'w,Pw1J߂ܧLzR&X5yⅫRw܄"L{+zO8 NwzUāvu 8j$'R i؏h` L}/O1|[KpzvGևUpc[1HQ0MoIWx#9Q{y^wexToR1& [JtцE&dTi*C2ʂj18k]Z 4䑤@' ꇎnI1#44`8|$.D2<.< 6\OsMn o?^a Ԓlvu: upE>>JyQHY9=Jt]MQ;0]]ʙ wH\ 2:;)>+*ڨg)0ɃE٣&0TQS>_p.mbiCޔ>tDڗ\Md[Ʉ"roI{V )TdT;AML cVĄe(E4V)(&S˂m2J1ySKgŪtGbgyQ/~( E g+^\*_j9( 9b?jֶAnd{,c0 7SGawq@ by5L 1SW\n\=|2qu]fS2.>zhQw"f JiH|[ 0]Yω>Lj<}1WdH`gV@E{@` vv+qh=τ( •BgjOz;.xWh5^9'-cxdYfJ>.͐桔@_e>7x"=gF Rt뷗UO+8!Sz[9`;?c3gY9?A)wӐ6z]o>B,ݸ@8+1L9%߱DP_>9F)3*p|a\hϴoFD0oKDHdߛ*6[k[-yO@ϴI*|xM6= u "Åǹi{Q"P=P&‘^{5@+2H/Gy/;3;X#itBFMս8(^nԞ5zjhs6tX[d. &x9u‡7u?߶S>`[~ ^Y{ԗ\<#ҏ K`D#iurNXV:vdɀ,EA48lzCpqdJE5))(Pi{|%E@:8,lXˋy//v3^8##y#1P_<5 Y"auKt$N; ם V`Ll:G\`҉4?KݐI#leDI sxJ]ӾݕNإ󎥼J$ylv P!egb]71C4[dG K4qfh)kǖ}Ζ@cQCDp?m?AcM=8!V-`WmS 3::mp$=MyŪKA$~ݣxJZ]Cݪdg 85z U{)ɼkqTUkOu㲪uAzHD %X\')E12(['+dO ƥcaz(ϐ޳ ]sk%]@b:9+0`ȠPL%+C/@`I~L?{XtN>Ֆz~eA1X+l> wC֫ g к3|Kh0n9^R'Sj؛y]y){^(yn7Z%2|)?x@b # ?96 ;vKt hrQGY57tatMY["J~dqo ˟^IdNYG5\Co\NῊPIS=/;$CtdHRtI<5t90<&p&X[V^z)s"<ѿG!d[nZ97z @PIzJsE;S[ M8XS ]̩b <~iN@峉! DȮg Yo~'vJ` 7q5@ "lIcQg daZ=g8 v_ǡOAXwXL=]_u)K#.]lTb++O^;/@{6%.<d=/ nTor01%dMum!{Ѱ();2"BF}%~*B?s# q7~@t'@eq܋nw5uBdJ A;m"Xm!îrn>axfurCS8zUGCSKl}ѫ|7 bVSM'x  %;B ٙπ2cF=wT=$I9Zp2`$CWdL~L8B}2p-Oj|OHp< hLlAo[2xVIxkn,2ERk`5wьZ6d( g}Bcj3PA BOLsoig3&ynB 0>yw x W3PEq:oe h< h' Fio#Շ{aiݱgۉoORBSX) Gn2?Y̶lznd1up`bvcµՑFZ ʱ ,\nlt9܋DّDa(dx OfO mP|;y3#&KXuy䴟$4ы8q6țFݴ_;R"IŹ$at_X7}o,2{DHk+T>%<+ =7^@7҇-aGgwGyS{MO'>\;9%#ADX`V{/i&N%?w`wf29P>": s]fV3vv 8|bĠުzmkLhKpΣpK-6dPТ+Vv޲Q,NTԻ' \ Bc͚jV( 7=%B 8n~;*pBl# ePBCkTHCzؖ{yFUݙ(t9vit} X/cÎ]ή6pi͸II} {iѪ$}LĔq* j~gd4_Ѿ_5pz( iz̯0 sfAd1P $DT>#ÿuF % kTP@)\q~g뼢.X̂ܥM ?ʫ}y%NCxk33 Јyg h6u_:cMG.Y!R~v_]\٤L o&g U򘅽"ZLܹ(?^L ԏ^ run/{C`$>Il "mp.P}=m~* Nn[$I2#U#A Cwa Nt#ٹf C3š ZL4'ϘƊmu:,tPm?cxnx0Nۚ#)~3 TD[ l=͛'} !46yysN \3: {9b(Na6ǻ7j zp8sGwjEM=mu10i>;f_))^G!!?XKe|mq/-߽s}*OrԣA엕\PO!m6g}|U%[^bhM;iɩ[}Ͽm[ h3e4"oN;KuVU%凥&S*gcG6~~v*kfna77[0 6>Ɵ|4^_n^d,Hh"kt:-8;<uh"W@}!g S8Ieu7+^d\'x7&DpzL}4u1@.2¼O]:p Mj#]4Mn{ruj3^(I٤?9槦%Rut3iz_"k0|ʪS2Kf/Jz:T}3T[|[p iQ2ECdW"ǒ48$H (wIgT=!' -%H5J"TrJ;E? |A۽Jn'1Q q[Yp2)B?0s - +[`EW P~"vu~oP[_Ԏȸ?œC:MV4>tR*qÐ OꀛgKa{H0|єe?9.ycyu`h`-]xT =P0ǁ[RP)0OmixD<'d'K+5+ $ϳ$D+v(7Pyq:\CskUD0|It+h.W"oInWN-jm;= vi-] LV o;#27S$’;_cRR_P? ԞA M/an8Nx (_NV}˜W~{A^>#6^X,VL_F-YϊN/t$}MO(eqSJaf{C?%a(_ƄE:W'L|^e,~ &Z`'ʭ|5 A9WEo:>AGh5?5!g74Izgjy3r{γ gg>},z\m tmynoR"C$(ԶL M Gm hΜ8gړ)-%FOC?&!iJ{_4r;_\ m)ʶ*鴨y8g_bo=3Z|H4ZPg}с'$`xh MMCFJ 3 r bgaѰ$ ֕Xt.Qt HIؗ6WN 4EwO"nfJM,X{AU+_z |nԈ_, ^3';jueIȿW bR?&uWr6w1_Շ"zq=uH uggC/!n)C|`a0v6dc0xb? t5>z8;hN?~>ϘT!ѯ*9 2 De[Rեqݵ5j CSN`D} MyBGJMASv״0$ ܒwAPm c0s S!SZPpxsU? yZ/I_$P6j.KI[6WʁZNxƢlGY,8$9f)]oH^.0oĴsngG)طK#1XGf `T? z8*b2VM.)n-r> Cb-E߇L,x GQ 'GuAKs1Z-E.W!Vz_|H` 6_r]&PEbN/drx$"$+& }^C%xXW]sKܡvW*DF X[ìV`~an!Zh= 1[㊼5\&xU.s^5Zl女A 'mZx,[M0`sȵ4䇋-EbD'F5@_8ktj;]'9m-mW MlbGVMVpHN3!OlCzF'`?=tV~^t ]uCݩ1_:4Q"3#3ԈFvqfxDC35܌Hș.#hhM\P$BƉsWdZ݆D@ RCZ ;,'t}Aw[߁υ2A~uԾhvV=Ż;n$+f| W/o4ͧ ]2_A!k@K-2bP{b-=fR J|*= kD68jy|DFx0u]y Dߐy2 bzuyծ+~?>{?A!ˣQ?~EO 0ymFQ`l Ty!<.4AIOj ˘}xۧ3 xTgmOՒHQ(?~m{D6͎AN0 zs'@Wn2|P4v-MЛ;J/iN 3Ud8b!okkHtpY;h/X+_A 㾟I7rUA^+Z.j0ɘ#(7v.fh_>(CQ .&vMA[ p+F&KL-+QW_K<ԵYX&Y)3V",h"ͮlD+|'z,#1KLV[Fv.X!޼rd0o2JVj+0!K.8캢p^ׁ>U^m\IK $۷zrZrU8=WtRa}uv'N>>`.B@@b⫮9x:^t^ /%?Uo"TD+gc}!w>13PA|F8#JǗdϴ$-~엓-ܱǀ\KݚxVOS%(ʮ=)) htF/n~ $^up4e$dv>x(,Ppc{V_b`y#\by<ާ3! +AjCYcͻa<ީO2"O,0Y࿾8) 5az|#*_=RJ vJNؤJCJp)h p6IS#z}-0xm:)M26nFu{@Y&A4=/LYVv.͈=p%9Y{j+΋&Ώ7_Ұ̪=v>xGƃIa{ufZ<9=ׇ p=}EʙO>G#~e6.4J8Z 6oq}`:RX*x_x\OteЏqa+({bs(0~JG lQ%<{"Y'}Ouc4K}=,')`U 47I#yZ9^<E7Nz^)ǟ:(2F}߇w hw,a_QY.[\UcոdŬZiy\(} <[⺡zTo$o?y$ j/va#~#*wb5*EʌQP)kV^*FnK%R삽'ͽx"+l=&> +uFp&o=ݙRum]FgJFO^ud[Ju3>yضyr-'KlMxTvuTOJ_OBGܷ۴Q[HZOqxJU{<`8.}OvMh7BPJ\m,H[imJYRzC֩E% #T lQ s"A–j>m uA(vZ$)jM8q3ZC\0/Pv,^)]FD<}d ͉^ҕio͆XVKTZpxro9AlZ;̦$ɅVP@<]$1 u<4yㆋ3r0BLV V`,B0Vgy&*ڋWtl'[Ag]`zݩ"/HfК<臢hޕlC ec >zDj: L1F{NKNU4!RFtǤw`Kw59^G:bJ zH{c;w%Ňf0"9rwͺB@ƶ:~KnO \ٴ=Y@[fPE eponx ^X8^VX @Arm9˪۴ouG;LGNCG-/Zzh6T缬ǫM/l<iX)g=)Y'w`O-@a-XLcg6-;~ArQk>uqDX X:h[BL~RO|d$uU=u/"k\SM[rj/0@i-IUA$뛬w9WN,]b&|jh S2/0J髿J L ?$ uWvq taL .w-x ׏S*5Pr$ v=#ň%M*R]FrwGu0+\A?Ųdl@?y.㲟>_MɥPb+]V O"zGv N:_IcD^/G}ez&B/{/?7h/x#*,̿yqO;%+5E3we6SѾ=PFr]WH=  [0Y~%u'. ts`7jWKu=B)bD,ӣGXaa(L pt5XR':p "`)աAA]'-tY:7ї[)qm FQثº2)jXv1B'^A<(-ZcM .>H *lMK4 NUzɞ _؜`k_&Kp{,=hrCxz4 L[_+4n^1{CQґO3RRjnBRDΆw.m[Hr"mj;#U5 o^9xNvNw'laM~y8˽g 0+8b"c_Kcq׫AF!I Nv@`4i[]ԓ);=?dW (Os#̛ͳ= yt(4hE(@T(g]:V,^v~km}dB=gGQp g}rֿ޹$djE򿅷.ܝ˫$W9WI`ry2o&c@t`8;^5 cF;eL^8*.? G*MptaQqcPOgOX&l1 3>`[o=Oun:'`+^ExWSh3'hAH3, Q>dhxhxR"ȐąnsZ|KZTwwyHR{t#  fu)M J0|qŌv_S/]̰Y~;/Z^B@t bm#yY ډA;p5 h!)c PUl1WQhа: 'dmM[&| :9Y\ ƟגBQJm꿾, mѸۤ>mu?_`M YB9 uyb)^lY]\X|yM7Jka2-MEM s%E&;gcbIJGu!"Q HBJvwځ€073o 7e}^UK32r Z;f,aiiq$\g|} SoAci;- Xx_)ƘUK|-~KTMA28|IT@J#SՈ)S'~N$%ώ@ᢹo;9]/˿M9GY$6!^ijlfHd<j`ϧtyF?4r]N <Ɓb;JIIJCP?|7gH{cչAn/d?ɋ"m?ቒi5&y #{gt+I{ҥ=K tLQJ/xd6 4yeP3\/Bii"jwYJj b82n ܟWHWLߊ]ME0ai|Q8_YGP;y~U~PL+fVp.X%XSp ZiXI'lp+:%I̵vcK<䠼'KI-E}غDl㧛x;ChkoxZJ޿qrvAqv ($w,̟ނi[ONbqQ6đ|V3ҧhf-.1!3B 8è6w+W s3IyR8]8wz <j=EfK)74߶;qzIprLM2>r$TW*Ǻ_{!1F7\&=;<6/Z(c;pH. Ds^S{$:Í2md/iOQܽLN{ݾėb=|hpjrrov2lqYB#|;pͮA74?aFpo#}ɲOd8{e -C 7L`$T@>ӆ $ɳ_ k1jRj*>ir֝F-@5rc_'OA$r3(694CK͆@"x<єUwCn Z*Yw4IMp D`^㧦9ySx\` ыG;~yWb`%- W?"McDK&e,q~V[-t9L:r|NSN^ 8n3B\ȫs۱]s b/Ѹ|O5nCa = !'Kb^Œ^˧Q]?.&{`1Df"DO.1W .  YZr !0~1xΰT͛ZfDQʕP%{Q>qkUdAOZ(.WޕvM@DRS!48М~ ` VPu>A̋,& b3NzZ9R ]Diaǹz 6$4-noi9 8L]GcwvmCsZ$V VZ; fctMgBg؈5@2+>񙜈ɚ7$inLe'o1jG z $JNcoIϛQ(58u;l`JOW';?=clo+2[ho8B!RK[4(Y7A ;'U<MXǸg)Z[8oR++b~Z]-EVm1Ol ni:(9w% 9 w޺bAQK[,*@_${. G1ޖp{&=("]ז#Z38{#M&GS-W^u5GK'6< G|K<`Zcj6gPX;~#*{=8ynB.xTY\ļc F]~w{faOeE T|ݖcNBkq=OpcԛTGٰ9>LJJLߏv2d%r/ g  ddIٳc${k{3)WSԉlQ-*%)ս߿zuMbaTƙ8>">f H$!hv)5J7UE!DT 3ܰ ݧ *p7VO; .yE(z.j?7 ?ֶ,x}f4*/PuOE=]L)COP$#sΟp$McR!(&&O~u.]se::q׌ϸP<̢gt'E8h`kQ$k6br/ DACC) 8 u'_ ƈuJKK4}(rF}^B?)Jn8KRy}㑕_E LҨo Sx|L#d2t{qH{6 ׺,^+]CUhB6D>鹁H`w^tvdXEJDs TXj3$^ DzYb,X??g+~BoMȆG:> r@Q NLi0'"Y&!p Dp5%< _,eۿR!lOU<j ;2%<Ԛ1]$ ۡ0ʈ p{}"?: vez~,ʩ(Fa^ӣ>DCDn^`~P*z;4&xKiBXۑvܿ.qe4RLJhGx%V>Hj{<_0M ,<*AW,eQ5d_ݦE_yb`GZ ķT\3 bdVpG{6){/PRoo2\^m r|hPhvPr e{X9<J<>o)1ou'.zE4[PPX`$`4Ŗ,Hʦl; nĉWz`2 բl @9Y];<4ygL-aGOq$8d{,J"lG^>]2+N)ή%fvۥ8ѓ0i|! }}BQI[e:X[x/*܂ho |9+4cx쳕ۈX# 5$t;Um _G+A8[l~JWeKH8'{ݔ|C﮻åxuB?D{-<@JfV45obN }:v tlz&U?c`}xO5ȾFQȡV7{TeN5F}l FiBY[ kRUqqWTq|Gո|/f) wc{զs6v lx:)^p+dycy p8m5FYCIǛ0_ye80OM>!3]leLFK-F]W]~,S0fYRǾB3p{uL)x(kkCmDQ&8Z41ݑ ^w\Nd1^$ԋKq`s>z?z 6p!VqGb>h 059 ᅻUt1%]AȚ1d*I<qߚE)"r} |8uhȲ;{r?cJHqZ6\; ñvQü;_p׮FV>f7 mmoj{4jU&ïnOo &ȉVؘ̥;OS6oSG+8nz.Wu? ?6I dF&V.8xRc ׿pAgp%2KāGޘV%=x:,1azA3o\i $ȫ iȜAҪ[, lH&\͊%x_bZEOH*c'd>5zXH\uܚ•qTy0΃y3 hzUOoAL+}/˵3$ qcQLґЗl_MOssm0h!nʾAK<&{,TtV0${>K'm@ \*n1iF'A8""*g ''VF0o.!{08ٜ9v!dx`K"i)nSc?7A>ƕc*sɈ#.mXI ;P<9u\b45yfB^&Gј΋Hg@"苼 %6 +[G? ,Fighk>{GC^%b:d  @)D`]5 9&b$@Ũ_UoN6 @7њxudhP}_|6oG2JB--//O6ʭ}&e÷d#JŦ 硽nl$S t#n{{]LMT8F_g؎Ṛvc rl$Zu:лE{ dM1$ Y8IuIA"T?SHhb~o灱_9A֟þ#剭=Ӌ/#YAȤ>XZ_[j%dOV~zNlΤ`nlFHL3yRV)/u @WNSU Cecrǜ~XwgL3Zf xUEYPV,glR)ǧ)3D88J,Bz*x1aiſ/3~^cȍ$X%HUi ͵yN - 1J^]i<~ MPB'@I6K<Ir(eC4 gg 6yk+wf6ū.EF1|l<[I*m.i2W/2ggǼHNyaQB ɃWg ^YBrˑsՐ[#:8*/7=r[}=S`L,lgDbq UIXţ'&Ϳɠ5;͒o r \8r?8&)F-fK,EÀĬSn) } _ҠQR0  uw>e>'DinFgG4Y/~B1i8s伳y1 j]ls!#O)%˩^/_@9H t° Ƞ; rZC.g7_GdnE:w0hZOQ7.Yߣm+f<uGcR J Z硔˨B@9f Eˉts"#d%w{P)DX0ΫgQ5tk]ێCxC4g H dg|yOմ8ma{GXտ@o("7 ~gPjIUTkrӿaPӗJ._A^M) %@Uew|J k6gn5:MTR`{Ywς'n)9X3CMq s$.|u^V˯1be`*#Hk)2?8s6ńS~qnJه9`-=Q'Y:3 ZU:H[~:_yOlﻀOf z„T?a1OsG G^b3YEe$;srjGNOqR \#ArtcY%;8+1$<.0n NN7׽@+MlB +N3JpI\~=OEvR->d k"Be%zw^:\hKO!D:Ruc,f{[u&3m!QU]+1t:&ˇu5bqDX$vɼBN=fI8biL }xU*ˢ6E0=Q$)t_X( ȵǓSDB'$"Tu΄&W/`X LRXl)O5sR%sLAhj" }KAϩ*e]l.-_ی.Ȃy"x@3CvU2lLC=:gL"6Pz_0]]:Rq ̩>7A4Eks0ieF8B`[w(^W}H|Z1쏁D _W6(MʸMQkS?".7>>zӫ#X郞]MCu2<Ɏd ޤYc5GZp$]vi:rl$k [^Pm4ל J?ѺO_(]l Jq bt~++፯of /ItH8'֝J!tMYpΨ v '+—A%c6WϬ9k0|;>!KgxfNf>f9f܇/b h#pCV%Y$V?ޜǾ,! ߕy-ސЮJŽEh)eYU-Bp/7 /x@Y%~"_S欇| Zw!?:qP|KsK֢Jx8 fIPO<#~H͝BѵS&"Pˡ[J忧zU ?thѧt9iROmW{QmXy&*{J%Ϝ+w]ꭡLBQ~iHwĠuncgrBQJf}*ROG&߳2c'(Kם R˽[S~~LBX(T#/ֿ9evǤUcO'?ď3]W^c|0Bӓċox`}$9t] trd\ki&(.ɛ@lhvط~G|jjI\QLChdޛ<$_8QA]qZґa+4x֊r F>2H隿-_Ye?AKXkRWbnl9ljQÀreM̑b*v[]pcy%) ; dzI"dHVfq=zȼ׼*(-NRFD!(yytnPiDA3j0N'ޢ6V֤1}sIBX¨;z<eO}b{pw'ycOG(q 3}a.>V(~]5≅9TxTB[Wl ߊE=`Ad&Qh GNXР^sM)VGnтCofi2?U6cwT;8}zBp8PK# ق#Kdr 2\PWy\Umk̿%IA٤K$ I=s)[)|2Wʟ(Ha$_1ؓK扵A 5D PvtVtc82tv&kdMl`  Hhx\lݒBI5ї-ӗÙlzGT%&o*;bq )6 ~ꂲf@ .F\ ܖζQX,e1DkbrmIBĊ4t,Z+HBlwxzsd87ڽp|ƵDHf0I5,:NAP@z#ӮMׇǚIUiֲ)wKm@v@VHz H\a&ʕ0O,ڸ$Aag xTb\I+GXDFO pYǃҐݸrv_s[e%^!]0eכ&uJi0*H^* ZZE?4qj{7' S론wyD ;gByX\rm 2|yr!nH\đ9G{!skyx\}<0'FAsey Yq'V0|d}kfؙ^ֹMM*iG7g;ˎxܸܶ+ǞnaFZt>? 8;˜;XӤ7 d7,~^p|rOvkc 3v@_y})b_.L9 k 1Ӥ 5|7SXy?\̉BoM!>mT7"T<ᘬIڈ W2RUGעKՋx~ ͚?P0'iQ}RfIw%Bm#@GWtZ}ٛW@r;/u^/SAut.qn'¿X"%!҄EYb=YS VStx25]KIz5 ]vDc2(rF-Yf}*jξ  9y22^7 !gt$xF"u4rm}Ezϱ]?P觍1=ʈK@BD/i:98_tB5_|IN?ށ fc\Yt|ZB:T3lǢD,4) 'k P{I$?ņh8hO·㳻SR28=EϪRm+T-L#My @/ϴk€l|9}J;&{RP1|)f3-4? H8duѬoEv-z`>@B|0a(rϽ|e2X|:i!5iBygrN\Hs]z1;KsddrMj &qi֛jC}*&7RI4x{Ci,4$$^ո& i >(EJl뛄xe^7g]Y3A)G ?ɸ!%NdӖPzz6EyBo9}=x/p<T-ي<;|H{X 2ě'hLeWAmjt-x^S'h^uMTMag[]8zJr)-9`=~%skKA-\"vSL\_uƵQrf ]\ݩ5!ka"o*ysl2=a8M7VɳJ1j#'s GcP9#)\DbĎTaLH9UX<.ܯHNGָWxa[S̻" wN}9r'ᗷ|.{U5i3c#/oYE]h^/43,$DJ~Q/&`_^HN×~0`_#*z0%ҠR|:$Sk)[ftyGTkڸ3AGFP{AAO#\,T{JhTx1 r.Sĝcv×;܌>f}=_X{=3D/15{ǵyj|lwȼM{ȋ._l$93lfwWv+ u(F3%iEgĘZ@`k,x.6:S )JcoWN34NĞkdODZys4Kx R;l{ xk3A(Վ O91=ׯCIst]q@7mdfƒYngI*s+Fp@;C<1z^>`fnC=\a?%uģ }g_EZVhoQg}{,}* Q34xIXϔ 8W/-5}~vɮ= 擉e/`^NJ0BO=a{;1TeǴp.v'7^QI]Hh<@.PQpId|ygRXlH0hFϖi!9/csAw[(O_n v/n񨋗 lW,bv D>i n6=ncLhDîJAB&[ ga{ԟxU"ۉ"=8gMɁ+bd V;؛ f3)2Nuetbee#ަ7&Z% `w IVKaky=d~t_:b ?<=p ?pML-^ԉ j ۾3qoД/qݰ2?,(8WEMe<@˽>44|TaZ$~ 7k+J|FYt赆`;:_s_֕\-6mb0zV{ّnSm[^J!}.gyY%a: 5i:\$G,8ٰ0k5oqh hgApL`Sݎa)g\>[ 8g.c5 7\~`zOU ~cdY%! hq:J h͆^~U{xԴnI AF5/NYQAۭK[D?̄+j){K WA{]Z;R0@g>^K4fόܘK(wV1Xq{fdW\y.GKwOg$:X-E&wד纋`嶈1+|MyWvٝPmi&KYh*s11lzU"/ホܿ^уZ\Ycwhy";\m)Ȑ0?i:P9NSZ߯ylщPr޳YDuϘEFU(fJc}eF_VN+Db ڳd[F}4pq8/7*]z񼯚?p<O"o@F˚4rX`VSev`0 #V{: Ԗh?ֿ; W[r{q#1?P]'&Ϲ'L#bA?+c ڡygr!#6,cj#?O]sGMɂVg2{|߿ XC.Ϻ(J.O׷F˿$ G3/g6!aŤ$P-<땨 r\ NW(,&=m#(J~$F!l<h}s>^e+:܇\ĂI{ Ub6RE/Q~8bhu7CJ $>(:D1$'Vk.~ohl(č?8/u? }݈LO5ң{^3aJWF>Gy h&e RofF2Y1Ӹ-gXدg5 QB-f#w_vݛjGGɸ :h0Fj-(ύ.H1lA\+ bqvi}p"A⢨5{Py㠞{#Dp,SQ1 ׼X l͏⣡ґ뾸 .N l!0DLH >^UZqqۤ7$ld32Z{&ֽp&As&}\IJ kqp Գ9t} ?K{M Kha4uBNWs~~*e싲F"l;h&80GLha\AīZ I6p]j'n:>Ylk9܁֣(CW o'WoxtU c*_UYG5eNCVZi\օ8i>?>)Un;vi0@rMW[yI!UJTTzQ* V.Zaa`N'H('wtoO!͗ojqӡŀ=}<^ ۊ*9Q CݸCoӕ +yl[)fOxp3k'l 4ɯ}L\=#b=~ˆZxޛ2 FL<2supyֻR̖iϷ]$`X|[74*&73E-|{k(;/kr";ӳC] .OpW'e52@j\,|8G'w?v#'ͩ}jlgMot|"mn\f"byhOu  /ac~HS3Zi:$ vETZcg:}D'"MҨQ`34$ ܼڿOA2eJhy2Nƛ,#W]v+\ BGՄPX9IHPM"|~KSt UVGn#`vl^N̽e-¼f?cq̓YtTaN oł}߸$d7TN'żtj+z.GʆiAH91FeOG$D#ʛAF y)mX1N_e#57* R"V(n°@6J }!KSlHL37ut)XcŖg[Y9c;8r& Wfggs>e^@Eôc8LK@oP+X ʡn(:hK1| ]97C'!b[05%?ɱ{1yDx"d(&ArjG:+A]I%~ВElWO"ٕ_}P QM3J險o ~0R6%MRAg l;T пZ)b y% wb蟙n֞aMR0}!'<+\x+Ey;ʦ+{ZÛa(@vķGo< 5`4vwG/Mɋo ~;@vH vp^1M6w~< # EK5o1g6*F {.hjs"-,@X)2  ~ewPyV;x5FՏTWK^$hqƎhJ2T|ܧ@9L.Ycn{%Å:Hx xG+I rօQ^Tx9pʴX,&/qCz8i/l.X\kakaRM6+/QC_oyR1#mVzX<. 8&8%0];zfF ^۟~(G~bOڿJ+ WޮƧ}/z C[jFp 񣟼*}ƃ̾h Eךb^.x^ĉz_! #za,rq'Йw؁uL%=(ٽy'VGd^G7 O$}T'jZ{WK$tlրT~sjsh:F1,}HׂcB~eu%D4g4UAvAU c]ݺXI]r_Ű@#Gl_2ħ5Etb︠wՏ|gQ:Vpn^j7}p&g愰?,Oxlk1{D N;oZ]rɋPcu#Lkb DwJ #~` ``k8@z溒7[b}{C@XC{<뛍 1G$[[LK*f+*JA3L;o2MW!#asX'_f[=eb/ޜOLlLC`p̨ᚈm3 Rpz4TLIh {LJqeF(.<9xXNU?k!:E;֟-@j=6d`u6/+WPo'烢~MCjjKG: 㾄fW^Fl6*N*3NlJ=sSϯ4gp7l &dF>1p?tW44U :4Mڒ7,FUQ|8S7:laĽKY3 O8'5S#7练iu|f8ثI$\?-eax#w[.+d;?Ս2c/JSzmjn^{RPŬ:Ha'Ez# =E*MfKпy?~Dk2,qű+f_329$4Y#{P9rk<+Dƀ}xf8 *Byl C.zÝkg"nN10}jcOX9C'+֭!M@~T oU6;[܅x?7 dL}άkjnkPͯ E7+9K- ]tߎ=UJc.y2WtFp~$^ҝˢ7J py*&vC cp%6xQf?BS3x[FJ[Toj0 ԘA|LFW-V {{̤ڀi[I4C7]Nyη z0 7c>aQM6sW> %2wvo=HNuR@/8.9DB6%!xc=Fܕ:w.')䡤q ń(r;nn&<9'Ml p{bN7Z3$U\ЯUc5ÉԗcOrWj sopt-2.0.0/matlab/test_images/M31.fits000077500000000000000000011451001277570055300175110ustar00rootroot00000000000000SIMPLE = T / BITPIX = -32 / NAXIS = 3 / NAXIS1 = 256 / NAXIS2 = 256 / NAXIS3 = 1 / EXTEND = T / BLOCKED = T / OBJECT = 'MMA-TEST' TELESCOP= 'MMA' INSTRUME OBSERVER= 'BRAUN' DATE-OBS= ' 26/09/8' DATE-MAP= '04/05/91' BSCALE = 1.00000000000E+00 / BZERO = 0.00000000000E+00 / BUNIT = 'JY/PIXEL' EPOCH = 1.987699951E+03 / DATAMAX = 1.006458163E+00 / DATAMIN = -1.003974790E-12 / CTYPE1 = 'RA---SIN' CRVAL1 = 0.00000000000E+00 / CDELT1 = -2.777777845E-04 / CRPIX1 = 1.280000000E+02 / CROTA1 = 0.000000000E+00 / CTYPE2 = 'DEC--SIN' CRVAL2 = 3.50000000000E+01 / CDELT2 = 2.777777845E-04 / CRPIX2 = 1.280000000E+02 / CROTA2 = 0.000000000E+00 / CTYPE3 = 'FREQ' CRVAL3 = 2.30000000000E+11 / CDELT3 = 2.300000051E+10 / CRPIX3 = 1.000000000E+00 / CROTA3 = 0.000000000E+00 / ORIGIN = 'NRAO sparc1 SDE' DATE = '04/05/91' HISTORY ---- /Begin "HISTORY" information found in fits tape he HISTORY BLOCKED = T /TAPE MAY BE BLOCKE HISTORY /------------------------------------------------- HISTORY ----- /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HE HISTORY BLOCKED = T /TAPE MAY BE BLOCKE HISTORY / HISTORY OF INPUT HISTORY / HISTORY OF INPUT HISTORY /------------------------------------------------- HISTORY ----- /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HE HISTORY OBSERVAT= 'KPNO' / origin of data HISTORY CCDPICNO= 218 / original ccd pict HISTORY EXPTIME = 1200 / actual integratio HISTORY s) DARKTIME= 1200 / total elapsed tim HISTORY IMAGETYP= 'OBJECT ' / object,dark,bias, HISTORY RA = ' 00:43:35' / right ascension ( HISTORY DEC = ' 41:15:06' / declination (tele HISTORY ZD = ' 11:52:00' / zenith distance HISTORY UT = ' 07:14:19' / universal time HISTORY ST = ' 00:06:13' / sidereal time HISTORY DETECTOR= 'TEK1 ' / detector (ccd typ HISTORY ter, etcCONTINUED:) HISTORY CAMTEMP = -107.88 / camera temperatur HISTORY DEWTEMP = -180.46 / dewar temperature HISTORY FILTERS = ' 2 0 ' / filter bolt posit HISTORY OVERSCAN= 520 / overscan subtract HISTORY ZEROCOR = 100 / zero level subtra HISTORY CCDSUM = ' 1 1 ' / on chip summation HISTORY TAPENUM = 2 HISTORY LICK = 'FITS2 HISTORY CONTINUED: ' HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION HISTORY /------------------------------------------------- HISTORY ----- IMLOD OUTNAME =' ' OUTCLASS =' HISTORY IMLOD OUTSEQ = -1 INTAPE = 2 OUTDISK= 1 HISTORY IMLOD RELEASE = '15JUL88' HISTORY RENAM INNAME='x13y11.5 ' INCLASS='IMAP ' HISTORY RENAM INSEQ= 2 INDISK= 1 HISTORY RENAM OUTNAME='x13y11.5 ' OUTCLASS='HA ' HISTORY RENAM OUTSEQ= 1 OUTDISK= 1 HISTORY 11 TRANS INNAME='x13y11.5 ' INCLASS='HA ' HISTORY TRANS INSEQ= 1 INDISK= 1 HISTORY TRANS OUTNAME='X13Y11 ' OUTCLASS='HA ' HISTORY TRANS OUTSEQ= 1 OUTDISK= 2 HISTORY TRANS BLC= 1., 1., 1., 1., 1., 1., HISTORY GE TRANS TRC= 508., 508., 1., 1., 1., 1., HISTORY GE TRANS TRANCOD='21 ' / OUTPUT AXIS ORDER HISTORY PUTVALUE PIXXY= 478, 29, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= -1.000000E+00 HISTORY PUTVALUE / NEW VALUE= 4.785877E+01 HISTORY PUTVALUE PIXXY= 361, 185, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 3.358684E+00 HISTORY PUTVALUE / NEW VALUE= 5.015400E+01 HISTORY PUTVALUE / OLD VALUE= 2.030912E+01 HISTORY PUTVALUE / NEW VALUE= 4.857830E+01 HISTORY PUTVALUE PIXXY= 245, 183, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 3.532237E+01 HISTORY PUTVALUE / NEW VALUE= 6.312109E+01 HISTORY PUTVALUE PIXXY= 270, 450, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 6.264473E+00 HISTORY PUTVALUE / NEW VALUE= 5.098941E+01 HISTORY PUTVALUE PIXXY= 100, 274, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.418351E+01 HISTORY PUTVALUE / NEW VALUE= 4.643355E+01 HISTORY PUTVALUE PIXXY= 238, 267, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 3.047939E+01 HISTORY NINER RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 55 NINER INNAME='X13Y11 ' INCLASS='HA ' HISTORY NINER INSEQ= 1 INDISK= 2 HISTORY NINER OUTNAME='X13Y11 ' OUTCLASS='HA ' HISTORY NINER OUTSEQ= 3 OUTDISK= 3 HISTORY NINER BLC = 1., 1., 1., 1., 1., HISTORY NINER TRC = 508., 508., 1., 1., 1., HISTORY NINER OPCODE = 'NINE' HISTORY HGEOM RELEASE ='15JUL88 ' /********* START 07-JUL HISTORY 29 HGEOM INNAME='X13Y11 ' INCLASS='HA ' HISTORY HGEOM INSEQ= 3 INDISK= 3 HISTORY HGEOM IN2NAME='X13Y11 ' IN2CLASS='RC ' HISTORY HGEOM IN2SEQ= 3 IN2DISK= 3 HISTORY HGEOM OUTSEQ= 1 OUTDISK= 3 HISTORY HGEOM BLC = 1, 1, 1, 1, 1, 1, 1 HISTORY HGEOM TRC = 508, 508, 1, 1, 1, 1, 1 HISTORY HGEOM IMSIZE = 508, 508 / OUTPUT IMAGE HISTORY HGEOM / INTERPOLATION ORDER USED WAS BIQUINTIC HISTORY HGEOM / INDETERMINATE PIXELS FILLED WITH ZEROS HISTORY HGEOM / 2028 PIXELS BLANKED DUE TO MEMORY L HISTORY TRY HGEOM / 0 PIXELS BLANKED DUE TO INPUT BL HISTORY ADDBEAM BMAJ= 9.30556E-04 BMIN= 7.16667E-04 BPA= HISTORY PUTHEAD NITER = 0 / OLD HISTORY PUTHEAD NITER = 1 / NEW HISTORY ADDBEAM BMAJ= 9.30556E-04 BMIN= 7.16667E-04 BPA= HISTORY ADDBEAM BMAJ= 7.22111E-04 BMIN= 5.56133E-04 BPA= HISTORY 49 CONVL INNAME='X13Y11 ' INCLASS='HH ' HISTORY CONVL INSEQ= 1 INDISK= 3 HISTORY CONVL OUTNAME='X13Y11 ' OUTCLASS='HHC ' HISTORY CONVL OUTSEQ= 1 OUTDISK= 2 HISTORY CONVL BLC= 1. 1. 1. 1. 1. 1. HISTORY CONVL TRC= 508. 508. 1. 1. 1. 1. HISTORY CONVL BMAJ= 2.8100 BMIN= 2.8100 BPA= 0.0/OUTP HISTORY CONVL CVBMAJ= 1.9717 CVBMIN= 1.0669 CVBPA= 148. HISTORY CONVL FACTOR= 1.00000E+00 /UNITS SCALING FACTOR HISTORY / HISTORY OF INPUT HISTORY /------------------------------------------------- HISTORY ----- /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HE HISTORY OBSERVAT= 'KPNO' / origin of data HISTORY EXPTIME = 1200 / actual integratio HISTORY s) DARKTIME= 1200 / total elapsed tim HISTORY OTIME = 1200 / shutter open time HISTORY IMAGETYP= 'OBJECT ' / object,dark,bias, HISTORY RA = ' 00:43:35' / right ascension ( HISTORY DEC = ' 41:15:10' / declination (tele HISTORY ZD = ' 09:51:00' / zenith distance HISTORY UT = ' 07:35:14' / universal time HISTORY ST = ' 00:27:12' / sidereal time HISTORY DETECTOR= 'TEK1 ' / detector (ccd typ HISTORY ter, etcCONTINUED:) HISTORY CAMTEMP = -107.88 / camera temperatur HISTORY DEWTEMP = -180.36 / dewar temperature HISTORY OVERSCAN= 521 / overscan subtract HISTORY ZEROCOR = 100 / zero level subtra HISTORY ,bias) FLATCOR = 103 / flat field correc HISTORY CCDSUM = ' 1 1 ' / on chip summation HISTORY TAPENUM = 5 HISTORY LICK = 'FITS2 HISTORY CONTINUED: ' HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION HISTORY /------------------------------------------------- HISTORY ----- IMLOD OUTNAME =' ' OUTCLASS =' HISTORY IMLOD OUTSEQ = -1 INTAPE = 2 OUTDISK= 1 HISTORY IMLOD RELEASE = '15JUL88' HISTORY RENAM INNAME='x13y11.5 ' INCLASS='IMAP ' HISTORY RENAM OUTNAME='x13y11.5 ' OUTCLASS='HA ' HISTORY RENAM OUTSEQ= 2 OUTDISK= 1 HISTORY TRANS RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 48 TRANS INNAME='x13y11.5 ' INCLASS='HA ' HISTORY TRANS INSEQ= 2 INDISK= 1 HISTORY TRANS OUTNAME='X13Y11 ' OUTCLASS='HA ' HISTORY TRANS OUTSEQ= 2 OUTDISK= 2 HISTORY TRANS BLC= 1., 1., 1., 1., 1., 1., HISTORY GE TRANS TRC= 508., 508., 1., 1., 1., 1., HISTORY GE TRANS TRANCOD='21 ' / OUTPUT AXIS ORDER HISTORY PUTVALUE PIXXY= 245, 183, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.708539E+01 HISTORY PUTVALUE / NEW VALUE= 6.688857E+01 HISTORY PUTVALUE / OLD VALUE= 5.076327E+00 HISTORY PUTVALUE / NEW VALUE= 4.791787E+01 HISTORY PUTVALUE PIXXY= 362, 185, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 1.919535E+01 HISTORY PUTVALUE / NEW VALUE= 4.768552E+01 HISTORY PUTVALUE PIXXY= 478, 29, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 3.415265E+00 HISTORY PUTVALUE / NEW VALUE= 4.977964E+01 HISTORY PUTVALUE PIXXY= 270, 450, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 4.245796E+00 HISTORY PUTVALUE / NEW VALUE= 5.090547E+01 HISTORY PUTVALUE PIXXY= 100, 274, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.127168E+01 HISTORY NINER RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 01 NINER INNAME='X13Y11 ' INCLASS='HA ' HISTORY NINER INSEQ= 2 INDISK= 2 HISTORY NINER OUTNAME='X13Y11 ' OUTCLASS='HA ' HISTORY NINER OUTSEQ= 4 OUTDISK= 3 HISTORY NINER BLC = 1., 1., 1., 1., 1., HISTORY NINER TRC = 508., 508., 1., 1., 1., HISTORY NINER OPCODE = 'NINE' HISTORY HGEOM RELEASE ='15JUL88 ' /********* START 07-JUL HISTORY 18 HGEOM INNAME='X13Y11 ' INCLASS='HA ' HISTORY HGEOM INSEQ= 4 INDISK= 3 HISTORY HGEOM IN2NAME='X13Y11 ' IN2CLASS='RC ' HISTORY HGEOM IN2SEQ= 3 IN2DISK= 3 HISTORY HGEOM OUTSEQ= 2 OUTDISK= 3 HISTORY HGEOM BLC = 1, 1, 1, 1, 1, 1, 1 HISTORY HGEOM TRC = 508, 508, 1, 1, 1, 1, 1 HISTORY HGEOM IMSIZE = 508, 508 / OUTPUT IMAGE HISTORY HGEOM / INTERPOLATION ORDER USED WAS BIQUINTIC HISTORY HGEOM / INDETERMINATE PIXELS FILLED WITH ZEROS HISTORY HGEOM / 1522 PIXELS BLANKED DUE TO MEMORY L HISTORY TRY HGEOM / 0 PIXELS BLANKED DUE TO INPUT BL HISTORY ADDBEAM BMAJ= 1.00278E-03 BMIN= 7.77778E-04 BPA= HISTORY PUTHEAD NITER = 0 / OLD HISTORY PUTHEAD NITER = 1 / NEW HISTORY ADDBEAM BMAJ= 1.00278E-03 BMIN= 7.77778E-04 BPA= HISTORY ADDBEAM BMAJ= 7.77778E-04 BMIN= 6.02778E-04 BPA= HISTORY 51 CONVL INNAME='X13Y11 ' INCLASS='HH ' HISTORY CONVL INSEQ= 2 INDISK= 3 HISTORY CONVL OUTNAME='X13Y11 ' OUTCLASS='HHC ' HISTORY CONVL OUTSEQ= 2 OUTDISK= 2 HISTORY CONVL BLC= 1. 1. 1. 1. 1. 1. HISTORY CONVL TRC= 508. 508. 1. 1. 1. 1. HISTORY CONVL BMAJ= 2.8100 BMIN= 2.8100 BPA= 0.0/OUTP HISTORY CONVL CVBMAJ= 1.7853 CVBMIN= 0.2369 CVBPA= 147. HISTORY CONVL FACTOR= 1.00000E+00 /UNITS SCALING FACTOR HISTORY / END OF OLD HISTOR HISTORY 15L8 HISTORY COMB INNAME='X13Y11 ' INCLASS='HHC ' HISTORY COMB INSEQ= 1 INDISK= 2 HISTORY COMB IN2SEQ= 2 IN2DISK= 2 HISTORY COMB OUTNAME='X13Y11 ' OUTCLASS='H ' HISTORY COMB OUTSEQ= 1 OUTDISK= 3 HISTORY COMB USERID= 1341 HISTORY COMB CTYPE= 1 /LIN.COMB HISTORY COMB BLC= 1 1 1 1 1 1 1 / BO HISTORY ER COMB TRC= 508 508 1 1 1 1 1 / TO HISTORY COMB A( 1)= 5.0000E-01 A( 2)= 5.0000E-01 A( 3 HISTORY COMB / UNDEFINED PIXELS MAGIC-VALUE BLANKED HISTORY / HISTORY OF INPUT HISTORY / HISTORY OF INPUT HISTORY /------------------------------------------------- HISTORY ----- /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HE HISTORY CCDPICNO= 214 / original ccd pict HISTORY EXPTIME = 600 / actual integratio HISTORY s) DARKTIME= 600 / total elapsed tim HISTORY OTIME = 600 / shutter open time HISTORY IMAGETYP= 'OBJECT ' / object,dark,bias, HISTORY RA = ' 00:43:34' / right ascension ( HISTORY DEC = ' 41:15:13' / declination (tele HISTORY ZD = ' 23:21:00' / zenith distance HISTORY UT = ' 06:04:29' / universal time HISTORY ST = ' 22:56:11' / sidereal time HISTORY DETECTOR= 'TEK1 ' / detector (ccd typ HISTORY ter, etcCONTINUED:) HISTORY CAMTEMP = -107.88 / camera temperatur HISTORY FILTERS = ' 4 0 ' / filter bolt posit HISTORY OVERSCAN= 518 / overscan subtract HISTORY ZEROCOR = 100 / zero level subtra HISTORY ,bias) FLATCOR = 102 / flat field correc HISTORY CCDSUM = ' 1 1 ' / on chip summation HISTORY TAPENUM = 3 HISTORY CLIPIX = 2 HISTORY LICK = 'FITS2 HISTORY CONTINUED: ' HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION HISTORY /------------------------------------------------- HISTORY ----- IMLOD OUTNAME =' ' OUTCLASS =' HISTORY IMLOD OUTSEQ = -1 INTAPE = 2 OUTDISK= 1 HISTORY RENAM INNAME='x13y11.5 ' INCLASS='IMAP ' HISTORY RENAM INSEQ= 3 INDISK= 1 HISTORY RENAM OUTNAME='x13y11.5 ' OUTCLASS='RC ' HISTORY RENAM OUTSEQ= 1 OUTDISK= 1 HISTORY TRANS RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 45 TRANS INNAME='x13y11.5 ' INCLASS='RC ' HISTORY TRANS INSEQ= 1 INDISK= 1 HISTORY TRANS OUTNAME='X13Y11 ' OUTCLASS='RC ' HISTORY TRANS OUTSEQ= 1 OUTDISK= 2 HISTORY TRANS BLC= 1., 1., 1., 1., 1., 1., HISTORY GE TRANS TRC= 508., 508., 1., 1., 1., 1., HISTORY GE TRANS TRANCOD='21 ' / OUTPUT AXIS ORDER HISTORY PUTVALUE PIXXY= 477, 29, 1, 1, 1 HISTORY PUTVALUE / NEW VALUE= 6.212081E+01 HISTORY PUTVALUE PIXXY= 245, 183, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.227195E+01 HISTORY PUTVALUE / NEW VALUE= 5.640461E+01 HISTORY PUTVALUE PIXXY= 100, 274, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.128498E+01 HISTORY PUTVALUE / NEW VALUE= 5.084704E+01 HISTORY PUTVALUE PIXXY= 270, 450, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 7.467422E+00 HISTORY PUTVALUE / NEW VALUE= 6.360126E+01 HISTORY PUTVALUE PIXXY= 342, 330, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 4.506516E+00 HISTORY PUTVALUE / NEW VALUE= 3.210023E+04 HISTORY 16 NINER INNAME='X13Y11 ' INCLASS='RC ' HISTORY NINER INSEQ= 1 INDISK= 2 HISTORY NINER OUTNAME='X13Y11 ' OUTCLASS='RC ' HISTORY NINER OUTSEQ= 3 OUTDISK= 3 HISTORY NINER BLC = 1., 1., 1., 1., 1., HISTORY NINER TRC = 508., 508., 1., 1., 1., HISTORY NINER OPCODE = 'NINE' HISTORY ADDBEAM BMAJ= 7.02778E-04 BMIN= 6.19444E-04 BPA= HISTORY RENAM INNAME='X13Y11 ' INCLASS='RC ' HISTORY RENAM INSEQ= 3 INDISK= 3 HISTORY RENAM OUTNAME='X13Y11 ' OUTCLASS='RH ' HISTORY RENAM OUTSEQ= 1 OUTDISK= 3 HISTORY PUTHEAD NITER = 0 / OLD HISTORY ADDBEAM BMAJ= 7.02778E-04 BMIN= 6.19444E-04 BPA= HISTORY ADDBEAM BMAJ= 5.45356E-04 BMIN= 4.80689E-04 BPA= HISTORY CONVL RELEASE ='15JUL88 ' /********* START 11-JUL HISTORY 16 CONVL INNAME='X13Y11 ' INCLASS='RH ' HISTORY CONVL INSEQ= 1 INDISK= 3 HISTORY CONVL OUTNAME='X13Y11 ' OUTCLASS='RHC ' HISTORY CONVL OUTSEQ= 1 OUTDISK= 2 HISTORY CONVL BLC= 1. 1. 1. 1. 1. 1. HISTORY CONVL TRC= 508. 508. 1. 1. 1. 1. HISTORY CONVL BMAJ= 2.8100 BMIN= 2.8100 BPA= 0.0/OUTP HISTORY CONVL CVBMAJ= 2.2139 CVBMIN= 2.0104 CVBPA= 157. HISTORY CONVL FACTOR= 1.00000E+00 /UNITS SCALING FACTOR HISTORY / HISTORY OF INPUT HISTORY ----- /BEGIN "HISTORY" INFORMATION FOUND IN FITS TAPE HE HISTORY OBSERVAT= 'KPNO' / origin of data HISTORY CCDPICNO= 215 / original ccd pict HISTORY EXPTIME = 600 / actual integratio HISTORY s) DARKTIME= 600 / total elapsed tim HISTORY OTIME = 600 / shutter open time HISTORY IMAGETYP= 'OBJECT ' / object,dark,bias, HISTORY RA = ' 00:43:34' / right ascension ( HISTORY DEC = ' 41:15:11' / declination (tele HISTORY ZD = ' 21:16:00' / zenith distance HISTORY UT = ' 06:15:57' / universal time HISTORY ST = ' 23:07:41' / sidereal time HISTORY DETECTOR= 'TEK1 ' / detector (ccd typ HISTORY CAMTEMP = -107.88 / camera temperatur HISTORY DEWTEMP = -180.36 / dewar temperature HISTORY FILTERS = ' 4 0 ' / filter bolt posit HISTORY OVERSCAN= 519 / overscan subtract HISTORY ZEROCOR = 100 / zero level subtra HISTORY ,bias) FLATCOR = 102 / flat field correc HISTORY CCDSUM = ' 1 1 ' / on chip summation HISTORY TAPENUM = 6 HISTORY LICK = 'FITS2 HISTORY CONTINUED: ' HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION HISTORY /------------------------------------------------- HISTORY ----- IMLOD OUTNAME =' ' OUTCLASS =' HISTORY IMLOD RELEASE = '15JUL88' HISTORY RENAM INNAME='x13y11.5 ' INCLASS='IMAP ' HISTORY RENAM INSEQ= 6 INDISK= 1 HISTORY RENAM OUTNAME='x13y11.5 ' OUTCLASS='RC ' HISTORY RENAM OUTSEQ= 2 OUTDISK= 1 HISTORY TRANS RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 18 TRANS INNAME='x13y11.5 ' INCLASS='RC ' HISTORY TRANS INSEQ= 2 INDISK= 1 HISTORY TRANS OUTNAME='X13Y11 ' OUTCLASS='RC ' HISTORY TRANS OUTSEQ= 2 OUTDISK= 2 HISTORY TRANS BLC= 1., 1., 1., 1., 1., 1., HISTORY GE TRANS TRC= 508., 508., 1., 1., 1., 1., HISTORY GE TRANS TRANCOD='21 ' / OUTPUT AXIS ORDER HISTORY PUTVALUE / OLD VALUE= -1.000000E+00 HISTORY PUTVALUE / NEW VALUE= 6.017683E+01 HISTORY PUTVALUE PIXXY= 361, 185, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.454924E+00 HISTORY PUTVALUE / NEW VALUE= 6.025087E+01 HISTORY PUTVALUE PIXXY= 270, 450, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 6.403409E+00 HISTORY PUTVALUE / NEW VALUE= 6.173703E+01 HISTORY PUTVALUE PIXXY= 362, 185, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.812008E+01 HISTORY PUTVALUE / NEW VALUE= 5.791139E+01 HISTORY PUTVALUE PIXXY= 245, 183, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.812008E+01 HISTORY PUTVALUE PIXXY= 238, 267, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.910720E+01 HISTORY PUTVALUE / NEW VALUE= 5.522478E+01 HISTORY PUTVALUE PIXXY= 100, 274, 1, 1, 1 HISTORY PUTVALUE / OLD VALUE= 2.318447E+01 HISTORY PUTVALUE / NEW VALUE= 5.040434E+01 HISTORY NINER RELEASE ='15JUL88 ' /********* START 01-JUL HISTORY 51 NINER INNAME='X13Y11 ' INCLASS='RC ' HISTORY NINER INSEQ= 2 INDISK= 2 HISTORY NINER OUTNAME='X13Y11 ' OUTCLASS='RC ' HISTORY NINER OUTSEQ= 4 OUTDISK= 3 HISTORY NINER BLC = 1., 1., 1., 1., 1., HISTORY NINER TRC = 508., 508., 1., 1., 1., HISTORY HGEOM RELEASE ='15JUL88 ' /********* START 07-JUL HISTORY 21 HGEOM INNAME='X13Y11 ' INCLASS='RC ' HISTORY HGEOM INSEQ= 4 INDISK= 3 HISTORY HGEOM IN2NAME='X13Y11 ' IN2CLASS='RC ' HISTORY HGEOM IN2SEQ= 3 IN2DISK= 3 HISTORY HGEOM OUTNAME='X13Y11 ' OUTCLASS='RH ' HISTORY HGEOM OUTSEQ= 1 OUTDISK= 3 HISTORY HGEOM BLC = 1, 1, 1, 1, 1, 1, 1 HISTORY HGEOM TRC = 508, 508, 1, 1, 1, 1, 1 HISTORY HGEOM IMSIZE = 508, 508 / OUTPUT IMAGE HISTORY HGEOM / INTERPOLATION ORDER USED WAS BIQUINTIC HISTORY HGEOM / INDETERMINATE PIXELS FILLED WITH ZEROS HISTORY HGEOM / 1015 PIXELS BLANKED DUE TO MEMORY L HISTORY ADDBEAM BMAJ= 7.47222E-04 BMIN= 6.52778E-04 BPA= HISTORY RENAM INNAME='X13Y11 ' INCLASS='RH ' HISTORY RENAM INSEQ= 1 INDISK= 3 HISTORY RENAM OUTNAME='X13Y11 ' OUTCLASS='RH ' HISTORY RENAM OUTSEQ= 2 OUTDISK= 3 HISTORY PUTHEAD NITER = 0 / OLD HISTORY PUTHEAD NITER = 1 / NEW HISTORY ADDBEAM BMAJ= 7.47222E-04 BMIN= 6.52778E-04 BPA= HISTORY ADDBEAM BMAJ= 5.79844E-04 BMIN= 5.06556E-04 BPA= HISTORY CONVL RELEASE ='15JUL88 ' /********* START 11-JUL HISTORY 39 CONVL INNAME='X13Y11 ' INCLASS='RH ' HISTORY CONVL INSEQ= 2 INDISK= 3 HISTORY CONVL OUTNAME='X13Y11 ' OUTCLASS='RHC ' HISTORY CONVL BLC= 1. 1. 1. 1. 1. 1. HISTORY CONVL TRC= 508. 508. 1. 1. 1. 1. HISTORY CONVL BMAJ= 2.8100 BMIN= 2.8100 BPA= 0.0/OUTP HISTORY CONVL CVBMAJ= 2.1379 CVBMIN= 1.8811 CVBPA= 155. HISTORY CONVL FACTOR= 1.00000E+00 /UNITS SCALING FACTOR HISTORY / END OF OLD HISTOR HISTORY 15L8 HISTORY COMB INNAME='X13Y11 ' INCLASS='RHC ' HISTORY COMB INSEQ= 1 INDISK= 2 HISTORY COMB IN2NAME='X13Y11 ' IN2CLASS='RHC ' HISTORY COMB IN2SEQ= 2 IN2DISK= 2 HISTORY COMB OUTNAME='X13Y11 ' OUTCLASS='R ' HISTORY COMB OUTSEQ= 1 OUTDISK= 3 HISTORY COMB CTYPE= 1 /LIN.COMB HISTORY COMB BLC= 1 1 1 1 1 1 1 / BO HISTORY ER COMB TRC= 508 508 1 1 1 1 1 / TO HISTORY COMB A( 1)= 5.0000E-01 A( 2)= 5.0000E-01 A( 3 HISTORY COMB / UNDEFINED PIXELS MAGIC-VALUE BLANKED HISTORY / END OF OLD HISTOR HISTORY 15L8 HISTORY COMB INNAME='X13Y11 ' INCLASS='H ' HISTORY COMB INSEQ= 1 INDISK= 3 HISTORY COMB IN2NAME='X13Y11 ' IN2CLASS='R ' HISTORY COMB IN2SEQ= 1 IN2DISK= 3 HISTORY COMB OUTNAME='X13Y11 ' OUTCLASS='H-R ' HISTORY COMB OUTSEQ= 1 OUTDISK= 3 HISTORY COMB CTYPE= 1 /LIN.COMB HISTORY COMB BLC= 1 1 1 1 1 1 1 / BO HISTORY ER COMB TRC= 508 508 1 1 1 1 1 / TO HISTORY COMB A( 1)= 1.0000E+00 A( 2)= -6.1400E-01 A( 3 HISTORY COMB / UNDEFINED PIXELS MAGIC-VALUE BLANKED HISTORY AIPS IMNAME='X13Y11 ' IMCLASS='H-R ' IMSE HISTORY AIPS USERNO= 1341 / HISTORY AIPS CLEAN BMAJ= 7.8056E-04 BMIN= 7.8056E-04 B HISTORY AIPS CLEAN NITER= 1 PRODUCT=1 / NORMAL HISTORY /END FITS TAPE HEADER "HISTORY" INFORMATION HISTORY /------------------------------------------------- HISTORY ----- IMLOD OUTNAME =' ' OUTCLASS =' HISTORY IMLOD OUTSEQ = 0 INTAPE = 2 OUTDISK= 1 HISTORY SUBIM RELEASE ='15OCT88 ' /********* START 06-OCT HISTORY 51 SUBIM INNAME='X13Y11 ' INCLASS='H-R ' HISTORY SUBIM INSEQ= 1 INDISK= 1 HISTORY SUBIM INTYPE ='MA' USERID= 1341 HISTORY SUBIM OUTNAME='X13Y11 ' OUTCLASS='SUBIM ' HISTORY SUBIM OUTSEQ= 1 OUTDISK= 1 HISTORY SUBIM BLC = 13, 242, 1, 1, 1, 1, 1 HISTORY SUBIM TRC = 214, 449, 1, 1, 1, 1, 1 HISTORY SUBIM XINC = 1 YINC = 1 HISTORY BLANK RELEASE ='15OCT88 ' /********* START 06-OCT HISTORY 38 BLANK INNAME='X13Y11 ' INCLASS='SUBIM ' HISTORY BLANK INSEQ= 1 INDISK= 1 HISTORY BLANK OUTNAME='X13Y11 ' OUTCLASS='BLANK ' HISTORY BLANK BLC = 1., 1., 1., 1., 1., HISTORY BLANK TRC = 202., 208., 1., 1., 1., HISTORY BLANK OPCODE = 'SELC' / OP = SELF HISTORY BLANK DPARM(3) = 3.00000E+02 / KEEP F <= HISTORY BLANK DPARM(4) = 2.50000E+01 / KEEP F >= HISTORY BLANK / WHERE F IS FROM THE INPUT IMAGE ITSELF HISTORY BLANK / BLANKED PIXELS SET TO MAGIC VALUE BLANKIN HISTORY BLANK RELEASE ='15OCT88 ' /********* START 06-OCT HISTORY 41 BLANK INNAME='X13Y11 ' INCLASS='BLANK ' HISTORY BLANK INSEQ= 1 INDISK= 1 HISTORY BLANK OUTNAME='X13Y11 ' OUTCLASS='BLANK ' HISTORY BLANK OUTSEQ= 2 OUTDISK= 1 HISTORY BLANK BLC = 1., 1., 1., 1., 1., HISTORY BLANK OPCODE = 'TVCU' / OP = TV C HISTORY BLANK / BLANK PIXELS OUTSIDE BLOTCH REGIONS HISTORY BLANK / BLANKED PIXELS SET TO MAGIC VALUE BLANKIN HISTORY RESCA INNAME='X13Y11 ' INCLASS='BLANK ' HISTORY RESCA INSEQ= 2 INDISK= 1 HISTORY RESCA FACTOR= 0.10000000E+01 OFFSET= -0.250000 HISTORY REMAG RELEASE ='15OCT88 ' /********* START 06-OCT HISTORY 18 REMAG INNAME='X13Y11 ' INCLASS='BLANK ' HISTORY REMAG INSEQ= 2 INDISK= 1 HISTORY REMAG OUTNAME='X13Y11 ' OUTCLASS='REMAG ' HISTORY REMAG OUTSEQ= 1 OUTDISK= 1 HISTORY REMAG PIXVAL = 0.00000E+00 BLC = ( 1, 1) TRC HISTORY REMAG NUMBER OF REPLACED MAGIC BLANKS = 2.7321000 HISTORY 39 PADIM INNAME='X13Y11 ' INCLASS='REMAG ' HISTORY PADIM INSEQ= 1 INDISK= 1 HISTORY PADIM OUTNAME='X13Y11 ' OUTCLASS='PADIM ' HISTORY PADIM OUTSEQ= 1 OUTDISK= 1 HISTORY PADIM IMSIZE = 512, 512 HISTORY PADIM IMAGE PADDED WITH 0.0000E+00's HISTORY PUTHEAD BUNIT =' ' / OLD HISTORY PUTHEAD BUNIT ='JY/PIXEL' / NEW HISTORY PUTHEAD CROTA2 = 1.12898E+00 / OLD HISTORY PUTHEAD CROTA2 = 0.00000E+00 / NEW HISTORY PUTHEAD OBJECT ='x13y11.5' / OLD HISTORY PUTHEAD OBJECT ='MMA-TEST' / NEW HISTORY PUTHEAD CRVAL1 = 1.038014025E+01 / OLD HISTORY PUTHEAD CRVAL2 = 4.104682085E+01 / OLD HISTORY PUTHEAD CRVAL2 = 0.000000000E+00 / NEW HISTORY PUTHEAD CRPIX1 = 3.97000E+02 / OLD HISTORY PUTHEAD CRPIX1 = 2.56000E+02 / NEW HISTORY PUTHEAD CRPIX2 = 1.65000E+02 / OLD HISTORY PUTHEAD CRPIX2 = 2.56000E+02 / NEW HISTORY PUTHEAD CDELT1 = -2.15482E-04 / OLD HISTORY PUTHEAD CDELT1 = -2.77778E-04 / NEW HISTORY PUTHEAD CDELT2 = 2.15646E-04 / OLD HISTORY PUTHEAD CDELT2 = 2.77778E-04 / NEW HISTORY ADDBEAM BMAJ= 7.80560E-04 BMIN= 7.80560E-04 BPA= HISTORY ADDBEAM BMAJ= 1.00000E-03 BMIN= 1.00000E-03 BPA= HISTORY PUTHEAD CDELT2 = 2.77778E-04 / OLD HISTORY PUTHEAD CDELT1 = -2.77778E-04 / OLD HISTORY PUTHEAD CDELT1 = -2.77778E-05 / NEW HISTORY PUTHEAD CDELT1 = -2.77778E-05 / OLD HISTORY PUTHEAD CDELT1 = -6.94444E-05 / NEW HISTORY PUTHEAD CDELT2 = 2.77778E-05 / OLD HISTORY PUTHEAD CDELT2 = 6.94444E-05 / NEW HISTORY PUTHEAD TELESCOP =' ' / OLD HISTORY PUTHEAD TELESCOP ='MMA ' / NEW HISTORY RESCA INNAME='X13Y11 ' INCLASS='PADIM ' HISTORY RESCA INSEQ= 1 INDISK= 1 HISTORY RESCA FACTOR= 0.39999998E-02 OFFSET= 0.000000 HISTORY SUBIM RELEASE ='15OCT88 ' /********* START 10-OCT HISTORY 01 SUBIM INNAME='X13Y11 ' INCLASS='PADIM ' HISTORY SUBIM INTYPE ='MA' USERID= 1341 HISTORY SUBIM OUTNAME='M31 ' OUTCLASS='MOD ' HISTORY SUBIM OUTSEQ= 1 OUTDISK= 3 HISTORY SUBIM BLC = 1, 1, 1, 1, 1, 1, 1 HISTORY SUBIM TRC = 512, 512, 1, 1, 1, 1, 1 HISTORY SUBIM XINC = 1 YINC = 1 HISTORY SUBIM RELEASE ='15OCT88 ' /********* START 10-OCT HISTORY 47 SUBIM INNAME='M31 ' INCLASS='MOD ' HISTORY SUBIM INSEQ= 1 INDISK= 3 HISTORY SUBIM INTYPE ='MA' USERID= 1341 HISTORY SUBIM OUTNAME='M31 ' OUTCLASS='SUBIM ' HISTORY SUBIM OUTSEQ= 1 OUTDISK= 1 HISTORY SUBIM BLC = 1, 1, 1, 1, 1, 1, 1 HISTORY SUBIM XINC = 1 YINC = 1 HISTORY RENAM INNAME='M31 ' INCLASS='SUBIM ' HISTORY RENAM INSEQ= 1 INDISK= 1 HISTORY RENAM OUTNAME='M31 ' OUTCLASS='TEST ' HISTORY RENAM OUTSEQ= 1 OUTDISK= 1 HISTORY PUTHEAD OBSERVER =' ' / OLD HISTORY PUTHEAD OBSERVER ='BRAUN ' / NEW HISTORY PUTHEAD CDELT1 = -6.94444E-05 / OLD HISTORY PUTHEAD CDELT1 = -2.77778E-04 / NEW HISTORY PUTHEAD CDELT2 = 6.94444E-05 / OLD HISTORY PUTHEAD CDELT2 = 2.77778E-04 / NEW HISTORY SUBIM RELEASE ='15JAN89 ' /********* START 28-OCT HISTORY 06 SUBIM INNAME='M31 ' INCLASS='TEST ' HISTORY SUBIM INTYPE ='MA' USERID= 1341 HISTORY SUBIM OUTNAME='M31 ' OUTCLASS='SUB ' HISTORY SUBIM OUTSEQ= 1 OUTDISK= 1 HISTORY SUBIM BLC = 129, 129, 1, 1, 1, 1, 1 HISTORY SUBIM TRC = 384, 384, 1, 1, 1, 1, 1 HISTORY SUBIM XINC = 1 YINC = 1 HISTORY PUTHEAD CRVAL2 = 0.000000000E+00 / OLD HISTORY PUTHEAD CRVAL2 = 3.500000000E+01 / NEW HISTORY AIPS IMNAME='M31 ' IMCLASS='SUB ' IMSE HISTORY AIPS USERNO= 1341 / HISTORY AIPS CLEAN BMAJ= 1.0000E-03 BMIN= 1.0000E-03 B HISTORY AIPS CLEAN NITER= 1 PRODUCT=1 / NORMAL HISTORY /END FITS tape header "HISTORY" information HISTORY ---- IMLOD OUTNAME =' HISTORY IMLOD OUTSEQ = 0 INTAPE = 1 OUTDISK= 1 HISTORY IMLOD INFILE = 'T:M31MOD.M HISTORY ' IMLOD RELEASE = '15JAN90' HISTORY AIPS IMNAME='M31MOD ' IMCLASS='IMOD ' IMSEQ= 1 HISTORY AIPS USERNO= 400 / HISTORY AIPS CLEAN BMAJ= 1.0000E-03 BMIN= 1.0000E-03 BPA= 0. HISTORY AIPS CLEAN NITER= 1 PRODUCT=1 / NORMAL END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;h==9="t=E`{=\+=C =5$=7x=< =X;=Gs=7x=Jk=',=R=',=$= Mz<Ռ <<,<<,t=@Ȧ=>t=^#=v3=SXK=j=aP=7x=+= 1=j<t=e===Q=M=ۊ=s=7x<t== r<3V>V>C==W==z=@Ȧ >'R>*2&>%6>/q>V==е=="<C>>==&=W=:S===[=9=X;C>i>5<>H>F>4> QN>N==l==<3>,> e>]>̎>>==%>Z> >C=ܸG==Gs<;{h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(=Z=ߢ=^=hg=G==*=s=w>>"F>C>Y>Z>ZT>He>4>)*>"F>F{=2=?=EJ<;8:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>,>> >N>7>}>=>>]>u> = =g=.(<-C;8:;8:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:v=R=]==[=%==&=͖{= >>"F>B>\N>b3>Rw>>>>>G?>B> QN=N=E`{<ǔ<<9|4:v;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;< =C>>>> >==> >Z>#:D>==a=EJ<%k=[=>V>6>Q}>^{H>Spu><>>>P>RFy>4==h;>s>*2&>+\">=hg==',<<}#<-C<9|4;8:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<=?=9=J=..=G=6=[=T=>y>+ >=>Lx>H>2>+ >9K><4>#B=&=s<>+\">8>'I0=i=b==0|<{<Ռ <}#<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;>P>*$>5>8>$`:>}>pw>}>=|=o7k=͖{= =W==~== =[= >]>,><>0 > =o=9=o7=.(=jZ=>Z=i>,>7>}>^>"F>]=C=&=Ԓc===ZT3= Mz >'.>:u>2T>]==$=MY=j=9̾<{m>>>,==?=>>=i=͖{==a==SXK=2>)(>)(>=?=2=^=a=c=<<9|4;Z;;;;;;8:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;C>>==:S=w=>k=..=ێK=R=a=s=N[=7x= Mz>y> >==>k=b= =Gs= Mz>C>="==^==е=N==a=ZT3== r<<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{h;{h: ;;:v;;;;;;;;;;;;;;;;;]y;(: ;;;;;;<<&t<0,T;(;;;;]y<3= 1===$=2=m=m==..=W=W=&=>>Z==i=q=J=9=x=Gs<Ӽ<&t: ;;;;;;(;(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:k=W=w=N=R====(=o=o=&=i> > > =%=$=MY=N[<{<^{F< ;(;Z;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:<=$=SXK=e=q=q=o7=o7=s===^#=j >F{>'R>"H>}==ռ_=E)=^#.>*$>T>N==1=< t=^#=^#=L\c=< =)=2=Ib<e=2=ZT3==#]=l=>,>s>"F>&2>k>=Ԓc=a= r<<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{h<<9|4<3>>u>=ܸG=I=+tt=3==J=|=/=9̾<}#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<> >=ێK= =}/=< = Ц>@>Xc>Tq>->m=>k= =b==Y~=9̾<}#;;;;;;;;;;;;;;;:;h >m=X*=(=MY=C <<<;(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;== >$8>u!>">!/>i>.> $>> >̎>=x=GsAm><>/q=b=j;;;;;;;;;;;;;;;(<&tt=',<e<%< ;]y;{h<C=dO=I=^#= Mz<;(: ;;;;;;;;;;;;;;;;< D>n*>b3>GФ>$8>>Z>8>U/o>Um>5<="=Jk<9|4;;;;;;;;;;;;;;{h<0,T>,===>>.A>J>J>-=2=N[y>(s,>%6> ;=9=t=L\c=L\c=>t=9̾=l=#]=wU==SXK=0|=<-C;(;;;;;;;;;;;;;;;;Z<<Ӽ=<ǔ<===^#t=)>=Ԓc=MY=e=E`{=UC=q=e=UC=@Ȧ= r<>> =i=N=MY==/=E=a=3=h;=.(=Q=j=E`{=l=r==Y~=}/=a=j=.(=Q<<^{F:v;:;(;(;h;Z<&t<%<{Z> >7>]> >=== =^===Q=ߢ=aP=C =E`{==5=N=X*=е=a= =j=+<e>/q>F{=..=1=}/=Jk= 1<;h;]y: ;;;;;;;;;;>>F{> > >==ܸG=ێK=[=2==E)=MY==Y~=v==s=>=q=(=#]=j=)<ӼZ>; >>>Z=hg=/=\+=',<Ӽ<<;;;;;;;;;;;;{h<==Gs=l==C <;h;;h<<<Z>>m>C>m>Z==C=m=T=&= ===x=dO=T>> $>>=q=̝=wU=X;=R<Ӽ<%<<< <;(;Z>>>>> =====G>>F{>k>"F>)(>+\">&4>=?=hg=I=^#=Z<|t=9̾=9̾=< =UC=v3=5=C>2T>g!>z>kA>=^= =?=Z<|;(;;;;:;;;;;;>N>> > e>7> >> >u>#:D>5>H>I>K>N7>J$>B>.A>x==(==< <Ӽ&4>a<>>{>Ts> =a= 1 >}>]>u> L>$`:>&2>6>J>`@>}C>>>E>'K>z>f%>Lx> L==R==SXK=EJ >M >\>~m>Wg>^==E`{<et=2=2=ZT3=q=s=a=Y~===]=MY==[=> Ц>}>"F>=>RFy>`:B>t>!/>>^%>_>h>>ڿ>>->k >8>==ۊ=^#=7x=$== r=',="=E`{=c=^#=7x=<+<==B=B=< =9̾=)=2=C =ZT3=?==>/k >i>y4>U/o>"H=ռ_=x=EJt=v3=?=== = ==e=QS=< =)=Z=t=o7=zۧ=e=aP=zۧ==/=wU=E=E=E)=E)=wU=wU=1=b=s=> >>\>=>j>A>߀> >&>C>>֧>Ӿ>C >'I>_>S>q>N7>==r=}/=ZT3=L\c=$==2=>t=e=x=e=E`{="=EJ=B=EJ=2=C =e=3==a===r=9=>k>u>J$>dI->Q}>&4=G=z=0|<<^{F;Z;;;;;;;;;;8:;;;;;;;;;۩<<t=Gs=L\c=e==ۊ=I=I=/=zۧ=X;=N[=< =B=j= Mz<e<<,>'R>B>sf>z>>>/h>QE>>#>u> z>\>1>/h>V>(>a<>$`:=T==9==?=SXK=2=N[=UC=l=}/=^#=Gs=< =E`{=L\c=9̾=2=^#== ===^=4===|>>1>Oa>E>"F=C=g=N[<{ >=i>>m> >> e>&4>M>>\>>Ώ>2>N>Z>›>˝>΄>>>/h>{>>>y4>>> =..=>k==-=ۊ=UC=o7==?=?=c=UC=^#=o7=s=QS=5$=ZT3=/==o=w=͖{=̝=Ƣ==b=*>i>9>8>o=~=E)=e=Ibt=^#=j=QS=Gs=2=7x=aP=a=-=-=|=T>> >y>'I0>0 >+\">5>@C>F>Am>=>a<>2>X >>fB>ڽ>t|>@V>_>y>Ƭ>\>ń>>>{>>4>>n*>.A> >,= =N=1==ߢ=9=5=wU=ߢ=j=v3==ۊ=v3=>t=Jk==9=$=$=(=====J>>#B>'.>=ܸG=IA=^#=j:;>G>I>T>ʁ>Dg>r<>?>*$>===E=s==(=l=R=s==]=?==a==UC=@Ȧ=^#= =MY=r=wU==/=-==Ƣ=G>x>pw> =ܸG=MY=X;<e e>.>Tq>x>>:>K>E> >s>O>j>b3>컔?? 7?`~?B\>a>>g??c?}?>u>>>َ>u>>5>J>>U/o>/k > =G=l=x=2==C=l= =Q=wU=I=/=e=Gs=C =N[=o7=aP=j===M==Ƣ=2=>=?=..=Q=@Ȧ<Ռ <&t;;;;;;;: ;;;;;;;< <-C<<<%<-C<^{Ft=EJ<+<|<=Q=N[=q=aP=9̾=e=e=)=Ib= Mz=0|=e=5=dO>>"H>VYk>->fD>h>G>֮>Ѝ>M>>q>/e>? i??Е? ? &?c?,?!?,d?/r?%?Y? >>)J> >Ya? ?b> >֮>#>}>Tq>*$>>C=>>>/q> ==̝===-==\+=C =+=Jk=ZT3=\+== =z=9==$=s=*=X*=>k=M=+<-C<;;;;;;;;;;;;;;;;t=<Ռ <3=Z=ZT3=r=[>]>C>M>>|>na>:>>R? 7??{>??v??# ?f?F?x?$?5@?D>?J+?C2?3I?!?(H? +?A? l?v?(H? >`&>>>&>o>Q{>0 >i>>hX>)*>5<>->>=6=J== =ߢ=e=@Ȧ=SXK=s==3== =s====-=4=е==ۊ=)k=*=o==a=N[=+= r==B=)=>t=N[=QS="<+=<<3<<,==X;=a=Ԓc>V>f%>Dg>nj/>>>_?T?c? W?+?)?![?f?"_?(y6?'P>K>>h\>I>*$>V>%6>6>I>M >4>`>==ێK=======z=v====9=M=z=ۊ=#]= =QS=j"F>Z>>~>(>>? x?,?&>?-"?$E?0?X_?瀩>>>t>Q}>*$>hX> L>1*>He>Xe>M >0 >>\> ==o==9=a=1=-=Q=#]=MY=ۊ==M=wU==o7=q=ZT3=<<&t;:v;;;;;;;;;;;;;: >> >>\>1>C>B>;>->==$=IA=s===9=IA=v=I=9==b=(=b==< =<;{h:v;۩;Z;;;;;;;;;;;;;:<ǔ<=0|=C =e=Jk<e e>s>'R>x=~==Y~=}/=E`{=7x=X;=c=Jk=$`>u>m>y>Z>ĥ=>c>y>Hs>D>8>o>E>>">fD>>>P>0>nj/>A>P>>t~>(>t~>#>ѷ>I??!?%??H> z>>>KN>'R>C=m=C> Ц>P>4>DV>He><4>Z>="=|=-=E)==s==Y~=Q==R====3=+=> >]>>\>&4>Ym==..=4=a=zۧ=aP=?==j=.(<ǔ<y>\'P>9>\>6,>{>!->_>ڸ>֮>g>>>kA>_D>g2#>u>jT>s$>>>>R>>g!>Rw>U/o>q>>>R>V>a>g>]r>>>oT>B>$8>x>>>}>&4>5>GФ>Um>N7>->>C===-===E=MY=g==4=9==a= 1<t=@Ȧ=C =$= 1=N[== ="> $>hX>u>`>$`:>"F> >=%=̝=1==I=E)=ۊ=UC >; >v>>d>>>›>֮>C>I>>>;>P>2>0 ><>Oa>[R>O>j>\>m>\'P>I>/k >4>I>f%>jT>9>>3x>>>lk >Lx>6b>0 >/k >0 >:u>Lx>U/o>Wg>_D>j>c1>B>"H>}>,=&== ===s==a=I=M=Y~= =l=0|t=+=$=E`{=]==dO>>o>>\>i> QN>"H>^> $>==Ԓc==E)=5=Y~=s=)<+<+<{= Mz=7x=L\c=\+=/==ռ_=~>>/q>E>o>>m>B>>b3>Q>y>H>>>m>)(>pw>'R>.>@C>2>B>QG>89>p}>Ts>->u> QN>&4>5>?>G?>J>K>H>>>2T>0 >B>ZhV>y>s$>}>>&>89>0>z^>Wg>3}>>\>x==ռ_====g= =s=s=c=^#=@Ȧ=7x=$= r<e<;(: ;;;;;;;;;;;;:<>x>pw>Z>'R>'R>/q> >=C=Ԓc==z=x=e=Gs=$=)=>t=SXK=o7=zۧ=o7=]==x=o="=>s>>>g!>>k>&>Ԟx??#?,?v>>>Am> L>'R>1*>@C>7>/k >x>>\>Ň>&2> > >>>]>}>^>#:D>$`:>"H>&2>3}>ZT>>>'>>c>>>)>A>h\>F>$8>>m=T=[==$===< =< =.(=0|=Ib= Mz=2=<V>̎>hX>#:D>"F>T>}>==x=a=e=E`{=SXK=^#=h;=q==ߢ=ߢ==zۧ=ۊ=I=1==w=C>s>Am>t>߀>>&? W?J+?V?9w.? >G>h\>?>6><>D>?>+ >N7>>r>@C>Ym> >m==ܸG=q>> Ц>>s>y>P>9K>q>M6>>?x>>#>>]>>q>Q{>7>i> =i==q=W==/=7x=Z= Mz>%6>->->*2&>'R>̎===3=^#=X;=}/= =/=ۊ=/====e=h;==ۊ=9=[>>+ >h> |>??7?ji?t?O?>›>I>\N>N7>I>D>B>8!>4>Q}>Q}>3}>}> Ц>==ܸG=*>>>>k>k> L>>>G>Yd>???>P>5>B>I(>u!>Vi>C,>1*> L>>]>̎>=l=E=X;= r<Ӽ<ǔ<<<%pw>*2&>5>; ><>5<>!{J===a=?===M=I=r=ߢ==ߢ=\+=>t=L\c==M=Ƣ=G>P>`@>>C ?X_?D~?x?ӟ?Vr?b1>\>&>d+>M >B>B>B>C>8!>1*>0 >#:D>> Ц>===>N>u>'R>$8>&2>2T>Ň>(>A???n ? %>>>&>>y4>c/>RFy>D>8!>,>)(>)*>^=m==v3=B<3 >)(>=^>N7>VYk>I>'.=i=>k=(=E)=E)==g=#]= =zۧ=x=\+=N[=N[=x=a=R=*>pw>Um>v>?J?F?pΆ?v¬?N֮>->Xe>9K>->1*>=^>E><4>)(>`>N>>=C=q=>>Z>1*>9>8>4>@>c1>>>? v? O? >A>َ>h>S>>{>sf>c1>Oa>@>8!>5<>,>7=x=x=V>&2>C,>^{H>`:B>I>*2&>>=m=&=dO==9==x=aP=QS=c=s=a=M=|=%>>N7>>De??>?Y&?W?3?%>>>F>$`:>T>(s,>2>@C>; >$8>F{>m== =6=2=> >)(>F>Ts>M >Am>@>\N>A> ><>~?ҝ?p>b>U>>Q>">>9>1>r<>U/o>He>; >->7==o7= r<< :: ;;;;;;;;;;;;;: ;۩:: ;{h;۩<<ǔ<=Z=k=s=9=/==aP=E`{=E`{=UC=}/=Q=J>> L>C,>YX>Um>J><4>5<>4>#:D>u>==r=}/=X;=QS=q=ۊ=a===>>H>>t|??/X?;?/?>ׅk>#>h>6b>hX>>\>4>B>B>Am>->>==..=Ԓc=hg=>>->J>[R>RFy>Am>8>=>f%>>w>Ϯ >E>X>X>_>ȶ+>Hu>>=>>w2>>o>Ts>?>#B>==C <+<3;h;;;;;;;;;;;;;;;;8:<9|4<< >4>Lx>VYk>^{H>]J>i>]J>G?>(s,===ߢ=l==a=4=|=x=W=~> >Am>>?L?l?Fj? o>Q>#>;>ZhV>2>%6>)*>K>u>m>\N>He>"F>==ܸG=[=dO=q>x>'.>; >G?>C,>/k >&4> L>2T>f%>S>{>nj/>m>ۘ]>>">ͦ>!->ń>Ƭ>q>6,>A>]J>9>=..=ۊ=<'.>J>i>|>E>q>r<>J$>pw=[=I=#]==&=?>m=>>> >8!>V>>??^>ߩK>X >>t>Ts>=^>6>G?>kA>>v>jT>ad>>3}>>=T=..==m> >/q>#B>'I0>$8>k> >> >2T>n>>!>w>0>t|>֧>>>>~>>y>>m>8> ;=x=}/=B*2&>Vi>V>2>Z>X>i>->=J=x=>P>3}>8!>.A> L> QN> QN>2T>c/>>>m>>pn>>{>d+>Tq>I>O>d+>0>>>1>`:B>4>> e=?==G=>,> ;>N>>x>=="=%> >9>n>|>L>y>>#>d>>C >>َ>C>[>y4>>> Ц=R=zۧ=)=j<<ǔ<<<9|4;;;;;;;;;;<>9K>r>>>>>M>'R>,>>hX>J$>kA>}C>|>c1>KN>?>;>J$>k >>B>>+Y>7>p}>`@>VYk>Q{>]J>wu>k>[>>Z>I>"H>,>Z=i>Z>=>m>>C>> ;>=&=Ƣ== >]>:u>t>S>>>;>+W>>M>ߩK>> >na>>3>I>===7x=+=>t=',<+<<;;;;;;;;;<t=.(=Z<<}#<<%<}#`>Um>X>>o>>t>E>&4> L>1>[R>>L>>\>!/>oT>Wg>Q}>_F>z>&>#>>>z>f%>\N>Spu>Vi>m>>>|>Spu>*2&>=X*=Ԓc==?> $> ;>m>>>>>=*=x==J=>o>\N>߀>j>Ѝ>ݟ>V>?g? ײ? i?g>t|>u>`@>o=J==SXK=Gs=h;=h;=Rk==#]=3= = = =?>.>a<>E>Z>>b5>p}>M><4><>Spu>b5>X >ͦ>ɕ>>߀>M>y>>9>#>M6>>\>>|>f%>Q{>E>Lx>Rw>0 >!{J>Z>m=dO=|=|=>k=>>hX>N>>,>>,>==Ԓc==$=..>x>Oa>C >>><>(??F?&p?*l?>I>_>vK>&4=>k=r=e=l=ߢ==Gs<{m>= =̝==5=-=I=5=ռ_> >*2&>H>j>>>E>q>[R>J$>M >|>V>ʽ>">'I>>K>K>w2>>i>ۘ]>M> >!>>z^>P>2T>*2&>'I0>=W=T=[=R==|=[=i>>P>pw> >x>7> $>==..=J=͖{=ܸG>7>P>2>X > >c>M??#>K?=_?D7?2?X_>K)>}C>0 =dO=v=s=v3=a=Y~=s=+= Ц>> ==6=Ԓc=Ԓc=l=е=>k==>V>$`:>F>m>>`>p}>ZT>Tq>q>>>T>>^%>=>T>U?)N?0?8?/e>@T>ʽ>>>O>$`:>> =%=J=:S=ռ_=$=Ƣ=s=ێK=>> >̎>F{>V> QN>P>y>==hg=Ԓc=*>>K>1>fD>>b3>De?s?'?F?M?8?V>\>>'I0=..==x==v=a==j=@Ȧ=EJ< >V>'R>s>N> > > e>==q=w=4=[>>;>f'>u>o>_F>[R>u>>F>4>m>L>>Ӿ?C?*l?D>?D7?+? +>c>>>He>`>=C=*=o=W==Ԓc=ܸG=G==T==>,>>*$>4>1>+\">Ym>==ܸG=%>>;>vK>>S>>>}??$E??lV?C?+? >f>n*>/q=J=/=h;=v3==ۊ===a=SXK=)=j= r= Mz<Ӽ<3> >}>%6>.A>.A>->%6>(s,>2T>/k >"F> Ц=W=r==J> ;>2T>Q{>ZT>Wg>Xe>u!>&>d>]>[q>k>o>?֬?I)?e?^?81? t>ͦ>z>h\>9>}>=T=[=ռ_=:S=T=..=[=~==ռ_=hg=ێK=q> >)(>@C>?>9>+ >}=?==q>N>+ >RFy>q>>#>Ƭ?`??+?)q?>#>}>E>=b==^#=L\c=h;==I=-=1=ߢ=c=@Ȧ=.(=',=Ib=Z= r<Ӽ<<}#<<=R=7x=2=Q<<,<<,=j=t=?=-=w=%=>>>]>^>(s,>5>7>=^>8!>6b>E>Lx>B>!{J=%=M=\+=ߢ=R=?>#:D>;>I>VYk>n*>89>>W>K>>>q?*7.?ZK$?r?cL?3͆>>>{C>RFy>*2&>=i="=$=R= =Ԓc=dO=o=o=:S=Ƣ=4==w=>`>; >B>>>3}>&4>x>C=>C>^>3}>B>Spu>~m>ڿ>2>M6>a<>}=J=Y~=h;=\+=E`{=@Ȧ=a=9=$==I=?=j=@Ȧ=< ="==R<+< > >pw>$8>0 >C>G?>GФ>@C>5>D>RFy>J>-==g=UC=Gs==b=G>Ym>:u>Xc>q>QG>߀>M6> >y>\??0v?[`?mR?Yk?'8>2>+Y>oT>D>"F>>==̝====x=͖{==J=|=b==̝=>>(s,>5>7>1>-> L>7=?=*>>>'R>'.>I>>>i>>΄>8>r>#B=[=a=x=\+=ZT3=^#=ZT3=3=$=Ԓc=͖{= =]=q=C =+=)==Ib<<<,<= Mz=B=2=>t=.(= Mz<+<|<Ӽ=.(="V>x>o>%6>; >P>kA>v>kA>Ts>9>9K>He>F>.A>C==zۧ=>t=aP=3==>->YX>z^>;>>>nj/>na>? >?0,V?RD?]?H?/>֧>m >ad>>9K> L>̎> e==..====е=Ԓc=ܸG=ێK=W=hg=~=> >pw>^>V>%6>&4>(s,>'.>`>=ێK=[=>> >)*>Spu>E>B>>c>a<>$8==b=q=X;=h;=h;=c=a=s==s=..=Ԓc=|=v=o7=< = Mz==j=Q>u>#B>2T>DV>h>A>>M6>i>V>RFy><4><>8>'.>=N=MY=o7=UC=x=MY=X*>#:D>Wg>}C>>>.>m>7???*?C2?Gز?3͆? o>K)>>Spu>+\">V>i>s> >=l=4=b=l=>>> >>\>0 >=><>5>#B>}>>Z>"H>->&2>=~=s=ێK=> >^>7>Xe>|>>VYk>hX= =|=9=zۧ=N[=j=}/=x=]==[==hg=Ƣ=g==< u>+\"><4>Spu>q>S>>na>>җ>>}C>O>@C>1*>k>=s= =]=e=l=]=x>>F>q>>s$>>җ>'???!?.#?-Db?֬>g>_>>@C>F{> >'.>0 >$8>7=T=$=͖{=*>pw>#:D>5<>N7>r>>t~> >u>Oa>+ >V>#B>5<>F>E>(s,> =*==> >pw>#:D>6>Lx>GФ>+ >== =s===^#=q=a=]=z= =ռ_==>k=4=g=z=Jk=<|<ǔ<<)*>D>VYk>lk >>l>. ? 5?e?>t|>>oT>KN>2T>==е=1=]=j=j=?= >>/k >Vi>r<>'K>>>>?ˀ?/e???@T?L>>+Y>dI->.>=*>`>>>3}>F{=%=̝=6> >->G?>i> >>> >Ώ>>1>b3>K>GФ>[R>vK>s>O>'.>===> > >>\>/k >,>s>=o==IA==l=q=Y~=I=IA=9=J=dO=s==ۊ==aP= Mz<<<,>Y>Z>lk >>>(?)N?~? 2? >컔>&>I>ZhV>2>=..= ==}/=aP=c=zۧ=a=ێK>i>=^>\N>>e>>?2? ?A?2>>>> >M >P>=6>m>/k >/k > =*=J=ێK>y>C,>dI->ְ>/h>P? h? >>~>V>ְ>@X>}>O>>1>j><4>=C==dO=G=>>k>#:D>/q>=..=$=E==^#=UC=Y~== ===J==E=q=X;=Gs=EJ= Mz=)=$= Mz="=SXK==I=b==1==X;=)==Q= Mz<<t=>F{>RFy>v>>>'>H?7?? 5>ڽ>>>VYk>-> e=>k=5=a=\+=N[=QS=zۧ=v= > $>0 >H>r>k>>N? 7? ?>b>>)>Hu>Z>G?>̎>=C=?>hX>"F> =G=dO=X*>F{>Lx>y>>)??M?>>">&> >(>2>s$>&>q>d+>4>N==W= =ռ_=ێK=..>,>V> QN> ="=R=IA=zۧ=N[=2=x=5==g=9=b=9==X;=)=B=$=< =l==o7=s=]=s===o= ==I==Gs=B=Z= r<,>`:B>>k>pn>na>q>(>>>">c1>6b>x==b==j=Jk=>t=Gs=x=E=Ԓc>7>4>F>g2#>>R?B\?4!? u'?x>R>`&>>_>2>N7>=C>>V>}>`>x>,=>>u>H>}>>na?ҝ? x?kV>ׅk>&>)>>Z>>>~m>g!>D> QN=?= =N=x=N=w=͖{=%>pw>#B>===a=v3=QS=7x=UC=ۊ=g=-===Y~==E`{=)==5$=v3=a===9===:S=T=6=N=s==v3=QS=$=EJ=<->`@>>UU>>>>>|>K>!{J>=$=a=x=SXK=< =0|=2=Gs=x=1=~>Z>F>VYk>h\>Β>Ƭ?? ?E? x?F>u>M>`>>_D> L==> >y>o>F{>̎>}>`>#:D>Am>o>>C>ߩK>>>^%>3>n*>VYk>N7>Y>Z>c/>Xe>E>)*> $= ===$===J=~>7> QN>7==s==3=v3=N[=Gs=X;=a=v=ۊ=\+=N[=o7=aP=< =< =UC=j=I==J=ێK=dO=T====T=N=E=aP=5$=B=<+<"F>]J>QG>1>>j>G?>"H>m=o=IA=c=)=B=',= 1= Mz= 1=5$=e=5=>.>Tq>h>r>9>q>s?J?~?y? >H>>>>|>=^>]> >pw> L> QN>$`:> QN>V>*$>3}>:u>Vi>`>m>^%>Ҡ>UU>>_F>B>*2&>"F>$8>2T>4>+\">F{=i=dO=x=|=Ƣ===͖{=q> >pw>C=>k=I==s=Gs=Jk=h;=a=3=l="=R=L\c=^#=L\c=\+=]=E=(=="==>>C===*==z=SXK==QYm>E>U/o>GФ>+ >Ym=G=E)==2<Ռ <<<Ռ C>?>a<>r<>y4>9>`>w?/e?v?@T>o>`> >f'>1*> L>*$>9>9K>9K>7>&2>&2>5>5><>U/o>q>V>q>\>f%>Am>&4> >>>̎>s>pw> =&=x=R=l=̝= =-=l=> >,==^=/=s=l=E`{=< =l= = =aP= rk=>C>>> Ц> >==6===2= Mz<Ռ <}#;]y;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;{h<%= r=l=R>>>x==ێK=(=o7="m>F>g2#>n>q>b5>ʁ>^?b? x? ? /? 7??B\>>s> >ZhV>?>I>YX>ad>>Q{>H>5<>'I0>0 >4>->9K>J>[R>es)>f'>P>0 >̎>=T=%>>>>C=2=4===Ƣ==g=x= =C==J==3=l=c=N[=9̾=c===SXK=EJ= r=2=h;=a= =MY=е=&=> >N>>>>=ܸG=е==7x; >ZhV>\N>[R>v>W>0> > >???a?7?W>o>>E>_D>dI->o>{>j>Ts>B>5<>6>:u>.A>0 >B>Um>`:B>]J>G?>'I0>=T=2=6= =C==*=ܸG=(= =е=R===x==&=̝== =z=q=l=ZT3=< =N[=s=aP=7x= 1=',=E`{=c=}/=a===">>>k>#:D>$`:>s=i===< <3<3<<;]y;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<hX>5><>@C>U/o>7>>y>!->U>? +?n ? ??> z>u>|>oT>v>>t>^{H>I>>>=>?>5<>3}>E>\N>g2#>ZhV>>>!{J> ==:S=Ԓc=>k=dO=X*=dO=:S=o= = ===x=s=2=W=4=E=s==r==v3=c=9̾=)=5$=+=Z=Ib="=7x=X;=o7=zۧ==(=G> >$`:>0 >3}>0 >o=q=IA=Jk>>y>#B>9K>g2#>89>>>w>p>]? ?e??>'>@V> >t>lk >vK>m>^{H>N7>@C>:u>9>5>4>E>Xc>c1>Xe>>>#:D>==2=>k=$=|=s=:S=o=:S==ܸG=е=4=:S=~=dO= = =/=Y~==zۧ=l=UC=',=>V>1>B>B>+ > =l=a= r<%< :;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]y<&tZ>7>&4>He>g2#>o>@X>m >>ͦ>둘?? &??x>4>m>>a<>`:B>\N>O>G?>=>4>)(>->1*>@>VYk>Y>Z>P>?>)*>o>==hg=R=9=^=w=l=Ƣ=&=ێK===..=m=dO=R=E)=ۊ=]==\+=@Ȧ=2= r<Ռ <|k=>o>*2&>7>=>; >Ym==9=5$<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<<x>#B>9K>P>Rw>Y>Z>r>>B>>>P?L?ˀ>>ĥ=>">j>Ň>K>@>9K>0 >&2>F{>}> L>4>Q{>]QL>Oa>B>*2&>Z> =~=ռ_==-=1=^=Ƣ== =̝=4==hg= =>k= =wU==x=c=0|=Ibu>(s,>2>5>/k >^==g=q<+;h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;: ;{h;h:;;;;;;;;;;;<^{F=7x=5=G>===?>>+ >=^>K>He>J$>U/o>k >>>#>QE>^>s>>>N>{C>YX>J>=>/k >!{J> ==>>V>=>Um>O>Am>.>i> $=G=dO=x==Q=9=== =b=I= ==е==a==SXK=',=<e<3<Ռ >'I0>1>5<>+ >`==4=e= r<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;( $=m==> ;>'.>@>Ň>H>GФ>J>Ň>\'P>oT>>o>>>c>q>q>˝>>>ad>>Lx>1*>k>=s=N=..>>$8>=^>Am>2T>&2>pw> =?=X*=>k==E)=E=IA=E=IA=IA= =3=MY=#]==e=Jk=+=Qt=o7= ==6> >)*>.A>(s,>k=?=R=x= 1> >=dO=>m>^>5<>I>F>C>D><>>>B>M>h\>ְ>Ҡ>ѷ>>S>pn>m>\>]J>=^>k=?=͖{===%>7>&2>+\"> QN>]> e>>== =ռ_=R==IA=M=I=9=Y~=o7=j=h;=QS="=>'R>"H>}>Z=$=zۧ=Ib >̎>=T=T>>>#B>; >@C>7>8!>.A>)*>#:D>P>+ >J$>\>>›>>Dg>E>`@>B>!{J>=*=l=o=> >^>Z>pw>=>>> e>V==ռ_= ==9=(=Ƣ==r=l=@Ȧ=',k>Z>]>y> e=i=w=v= 1<<<<&t:v;:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; >pw>x==>> >/q>,>7>.>(s,>#B>>\>> > >`>>>sf>>W>>>wu>Xe>9>%6>>=i=>>}>T>k>>==?>,>x>7>===*=ռ_=X*==~==v=Gs=Ib<+<%<^{Fk=?> > =~=N=9=e<+<&t;{h;]y;]y;;:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;(=j=wU=X*> Ц>i>hX> =>> ;>}>P>0 >-> L>k>s> >V=?>V>^>?>h>}>z>a<>Ň>B>(s,>/q>y>>7>}>k>T>$`:> L>k> =>C> $>̎>> e>> > e=i>> >C=W==\+=<<,C>=J==^#="<<,;(;]y;{h;8:;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:<==Ԓc>V>k>"H>^> >m> >̎>Ym>&2>+ > L>>7>x>N>>>7>P>Am>M>H>6>$`:>`>x>> >7>>k>'I0>(s,>'.>&4>2>*2&>̎>k>$`:>T>^>s>}>N>> >> Ц==>k=5=ek=Ԓc=ռ_= =o7=Z<<,u> QN>k> >,>V>7>u>T>P>Z>F{> > >]>pw>>>]>P>)*>!{J>Ym> ==%==?> >>s> L>&2>#B>#B>DV>c1>B>Am>M>F>3}>)*>T>>> =q=~=s==ߢ=>t<Ӽt=c==Y~=-===|=b=5=v=\+N>s>x>==i> Ц>]>]> > >F{>u>̎>pw>P>pw> > e> ;>> > >=~="=>>x>u>`>Ym>>\>^>o>9>~m>z>oT>x>t>ZhV>; >!{J>===J==Q=x=L\c=j<<-C<< ==6=ռ_=6=>>==>>k>^>V>P>o> >=i> e>y>s>7>=i>>N>F{>T>!{J>>\>hX>P>i>(s,>f'>G>>>I(>v>K>#B> ;==|=#]=?=j=7x=Ib<Ռ <<ǔ< >Ym>#:D>%6>i>N>>> $>$`:>2T>3}>)(>'R>s>"H>*$>1*>9>5<>6><4>2>*2&>B>a<>V>Β>c>|>O>'.>=ܸG=g=\+=$=$=Ib<{<ǔ< >hX>'.>$`:>o> >,>u>4>KN>Xe>Um>Lx>F>Lx>ZT>a<>n>q>i>j>ZT>@C>8!>?>ZT>z^>M>n>He>'.>=dO=E=E`{<<<Ӽ<{<e=B=7x=}/=z=E=E)=z= ==]==w=6=6=J=5==aP=aP=x=h;=C =EJ<ǔ<>^>$`:>"F>$`:>pw>x> L>@C>ZT>lk >z>>>{C>R>>>>)>->V>`:B>GФ>=^>Am>VYk>es)>\'P>;>^==w=a=Gsk=o=͖{=9=r=#]==Ƣ=~=m=6==Y~=UC=.(=>t=QS=QS=9̾= Mz<3;(<<m>i>&4>'R>$8>*$>"F>0 >C>ZT>n*>>>>:>ڿ>>.>>#>>s$>x>Y>Z>K>D>G?>Vi>P>0 > =2==/=aP=SXK=>t=L\c==MY=4=%> >==X*==E)=R=dO=q===w=9==Jk=EJ=$=.(= 1=<ǔ<k== = =>7>V>T>#:D>9K>9>; >C,>I>Xc>j>O>>>F>.> >=>E>>>{>_F>Ň>J$>E>J>DV>&2>=hg== =#]=g= ==J=C> >(s,><>1*>Ym==hg=Ƣ=%>> >C=*===c=E`{=R=Z=R= Mz>>s> QN>6>C><>9K>4>9K>GФ>]J>y4>>> >>d>>->O>kA>Um>J>C>>><>5>'R>==dO=6=ێK=*>>>> L><4>Q}>_F>F>*$>7>>C> >>==s=I=v3=C =0|=EJ=Q= Mz= Mz<<,>>'.>;>8!>.>#B>"H>*2&>8>N7>h>|>89>s$>E>Z>vK>m>\'P>N7>F>?>5<>.>'I0>/q> ===>C> >]>o>#B>1*>G?>`:B>ad>>F>&2>hX>pw>i>7=?== =-=ۊ=o7=< =EJ=j >$`:>->%6>i> >>pw>'.><>RFy>b3>v>n>a<>`:B>]QL>U/o>M>F>8>1*>)(>$8>`>}>>>C>=i>>,>y>(s,>5>I>K>3}>/q>>u>]>==-=#]= =x=j=>t=EJ<{<<,<<<%<0,T;]y;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;۩<<^{Fk>C>>\>T>>m==>V>}>(s,>;>N7>Um>KN>P>Spu>Ň>J>I>4>->/k >/k >0 >'.>hX> $==2==R= => >s>P>%6>^> =i== ==wU=l=^#=X;=o7=c=5$= r<3Z>F{>>= ===i>>P>0 >:u>5>8!>B>@><>B>9>+ >6b><>?>8>"F> ;=ێK=b=I=z=I=N="= ===i=q=Ԓc==s===^#=+=+=)=5$=Gs="=t=e=/=>> >=m===i=> >!{J>&4>)*>^> QN>%6>$8>->2T>->4>?>?>5>hX=C=$=I=3==MY===|=^====IA==E`{=',=R===R=Q=<Ӽ<ǔ<<-C< ;: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;]y;;;;8:< <^{F> > e>>,>> >}>#B>"H>'R>}>> > >u>P>#B>)(>.>,>!{J>=X*= =Q=v=wU=IA=g=E)=s====l=j=Gs=',= Mz<{<+<|<=< >s>̎>N> >>$`:>0 >5<>&2> L>>N>>x>>}>i>pw>7>>="==1=1===1===^#=+=R $>x> $> >y>,>?>J$>D>=^>2>$8>)*>#B>F{> Ц>> e>Z=m===dO=N==== ==N[=)<C>>}>(s,>?>Q{>Xc>U/o>Rw>F>B>B>1>^>Ym>k> $>=?=m==2=x=(=^=-=l=$,>s>$8>8!>H>M >KN>Lx>J>Spu>M>=^>3}>.>(s,>/q> >=%=W=R==Q=ߢ=N[=j >Ym>$8>&2>*2&>0 >Am>Oa>K>He>=^>1*>$8> Ц==ܸG==wU=?=\+=C =<e<Z> >Ym>->4>:u>4> L>/q>=ێK=R=wU=zۧ=@Ȧ=j<{<e>V>N>pw> e====9==c=',<3<<:J 155?>" V 6D:  ^ 19 6#;5 ^(0> dL& pƽ9"ÿtAo½ 1ƨf1 "G~0 8 ŭM (ÿ ;M% ]     Md     l F.  fdm ,(((   . or4 ; 7õ%     ; 6<*l ' 6        "6y)6Œ       I&/ / X l 76 %     E)      8 9*   !  %)d  ( 9   Ƿn    s ^ _  > ;E (l]RT^|A'    1>Y" JYIl~S u  8dX ! +mn/I')#+517}  E N +MR:7 %uATA &(-.31Lu!++ \ .~ +s{\"./+./A4D`&3ڹ Y u9=>% #vZM,M-3XY^dbghhgikhh:& E -HRNOfN8#+f/fdv}ecda_abdffjzqt{)## g   S@ Yh/$Z"! 5XI" \u!± \:  D#n b_Dƺ0T'?7!  $5ba`)  X tq"yP+rҗ+r啁b5iyr_#,ƿe  G 'veA5Ns#!$''H]ַž8#"yk̯ b»im0  @ Ynrtҫ'"'(mVMЬܡ$!!tձ ?´UTE#)2+  4$_xiisѯ('%5Z'P9'aG*|n$ z-MDD` O, J -GJL((Ug{rȹ1&#KH-Z@!u#Up# zTMEAaE %  T =(8@GVS %AUl5(%BU'#!4V11S<(G&%HG("}G1_XRqU %~  Ip9@F]lS!,*G_n|?j B(/(,E5U0\$#Ս%tLI*( * `  " ,JDO`xD&B+,D]izs~-T*%?*|$&&zN"Yüĥ# ! 2 SYhyv\L2+CXht|L=j{/\.%TH(;:$" o!    ZO>,n_  3 R7&&*&#XM!#0/7."#%)$a 37F     Ci&c(  F XTROENXINPSRMOSPNZ)+1j 3       +Z!-  / 5y%&#!3B)#'$%(% " %)+v "/     C    V>  HhN   *-    "A  c   q56A>;n2H+A      %` ~/ DF`+.s  I% I    17 | lnw2F@>Xk3=?BB#  J      "  . l(Z+10GI7< L       $  #+, =G  I    ' 6 :L       , /   !c6L 6  U       7    " {+  j        A  * TmB O+         vI   !٘{ꦫf 1+   +         jD  5 xaL* Q         E>   JPtpuqEA6l޽6&{         R<   ;-4A46aX8H;O+=       EC    *O    8 (          GQ     7}   5       :[   !   G t      .j        <8        "z          "þ           ;    7     =#ä G      !  @=    (̪        )    6<52-**  [ "~ʽ j         6     *[m H  .+)*.498    j   #G ( Z     #3.-*/4=BE4+'     #I '   )I:# $   (3/'.6:B::/$,    0>  OW )!f$ !    *,/),426<) /   uW &&ʌ'   >& 0  #(!#)*),      . .Z* =<Ň9 &,X  &'+-/    S:@C|B s ;o% 2     #((&     4 "EKmF R 6+I   !'#!%'=   ! I\b@  >.       '#"$'  ( | FXb9 1B E6P      "(  + ']HWe1G +0 a    *   /D &  D6HZiJ2  ;LQ.;      !'7$  qD   + } I]lMx /!!           " L 0  JdsN# ?g!         ) ; 7n    HpUe 3$.        Q  +/ 5/  +  +b Jmg ? &¿ÿ {    @ " (- > K ^2 GlߏdK C6A÷ļüL     #  > L, (`Ild 7(-            Hiߏc;  JPĺ-  k         w Hla+(¾¶           d9v  5n+Mpݍd( >e¾÷ 7%e          8 J  eCJLqazO 0"*ƿ)       6Q% )uOna|dhz 8z % Y      " p Ooߏ`hMPcuA A1 ,         Rsd`JTl*NǷ Q       U>f 0{SvޑdgTaz: =G        5  ]T>Stݑew]OPXdkti #Ź }|zz{~ [          E ,uUsfeACIXbls% <W ô;zwzwuvtuzwqx         gRĺ UwގhwFO\qg /ǽ'tvvwrvuxwsuvxv~d     ` Δ Vuݍe{OZl~ =Ĺŷ"-qmmpiqrvvqunpqz     L 0S "Yyߎe}R[qT >2br8 nkhmltnokllwxsw    , v  o' N[AX}ݐfO\p~ .nolnoqprkidcnpxxy#  $        g 4V|ݗfvRam|5 UO *krlqprmoihfdho}~ͼ            eǩ ĽV|ݒmmMZk~} &%-km!kpcnlkspqq~}׼?            Ȃ Uohqlz# Kp(jhgjkk[`hhnmnqzz}zwĵ        $W #'VݒpyX}v ."¹$nVR`d[UUauvo|x~vlty~`              Y[3 JhHTܑr¼ ;wu w|zxyz}yyvw~~z~yxwzzx(m^hs\VX̝nTJJV^ebe^e     Z    8oTܒrĬy8 ?'Qvo}vaU\mty}#~oZWV±į|qYHCFJJLNC       P ݲ !̼νUߒs¼IJ` '(kYgyqmr}~r#_{{mci|{x~~mSCDFHJ"         h~ Tޒm) 6Ii^i%|idbf`NNtoG@peK+_lnelbctx{llojiklqpq|x}hMEEFH             szsspmjedehs3 "b][d\hSi|my}mso _F\Q=av:6jf5=fa}slO8KtpKCUbPJ#RUPPQIJTTZTSOHJLJHIGJLHKKW`LKHEGG1     U! B#RurYQT~yfe`{ ,C=('1dGp0.q|"}qlQ>Sng^^YWDEEC@A>@>@?@B>@A@B=>@A@BADCCJ       q l rRQʸɶSvpkl> #L#1.q Bd9¾]ECDHTcxrfh^W?AKZ[U]hm^bic_NL FD?@?>>@>=>@ A??@?A@@?@@A@BAD?        p 4BnaZ\TXRfoavsl 0\#96~t(CxCe5  %'/>Y}q`hb^daS2-/5ERZ]dUPPLQML@B@@?>=?=> @A>C@?AB?@?ABCDJ,         n "&))%! $  '++!%'Rޢh[7E[1Y|ztv~tR -/d $<&=xv3"BW>I!"!!%,@i*{edfdhf`ccV84215;L\cYLEIQNLB?@B?A@@?AB?DACEED@ADBCENM          #' D 94) &$OmX3@U2\tbSRtnhjw~kfbzk )d$G6Hvs:-IQDqJ' !#$"%$$'1VbL^dghfcbgU:99767?Xb\KCKUPK PJROVLNISHTJTSUYU^TaXbZaU]ZbnV          '- 0) 3xl(%!##Clٿ\~TYjPBJpiZ\YiaXTnfD 11%|O@PqpA8ISL_J%!#"#$%'&'&!)M} kC9?^jefdbadV8:7KWZN@FLHF%qpywvi~qqv}|qtrxus?      =@AAQZ8Eg\@BDE ct7;*&$N|GrafP9DqhJGETPCCgb !$~S?NlnH=EDGnjzrwg|nkvnuzzjcsif|o~xmvr       {kvrwX IaR==>exv[IGEC<4%|L;Jc^KCJyNN;#"#$'')++,+&%%7o\8-1//5_gepiaccd[?2568@;4 # $ZAC8>7+FUcSuFACPWd[F>?DB:[TqS *%zG3C]XJABoo[]7+/$ %$##%&,O5**&"" #I$yP7AF>1'0dhjxue`bcG%#().D;2=7&5%!<<,%uzD           x{k yUY8gY+58LT֎bsmbXODGHYzRew .2{J0;YSB>@akgf2@JNA6(-^iha`cbba6"1+'5+,1-&bg|n{zzpy|zyerdro{oy          }t %x|gLF)3*P>49]}|Bs}qmqqgVZSSY;^~2 '{K&/a_@9:i|UO1=@,,' "&'&)&''('*'"%$"&$!$HhRHEJ TUA;40Wcd\`ecfX%!+"%%!X^|xmw}ty}x|muenn}f       NҠ fDqXW<8-Li1CbxfK=HN4d263B_[PjxZ3$Wzpa #cQ+>|uZQkf961'.%"6ZG'($)-*&% ""#*,$04+)4aUJ`^"MLVXHAABZcig_ac_E' `jr~y{=          H[?12"61H~k/+,018laA3@=C\ylOEqv}+ %.b<:_zvN@@AE?J>?^rWUFDPK:3/<=6ITM^qdVPp[UudZYUXW\gobpoc`T4 gwxz         N $Ŷa>4.50So++(*6D;ܙsYC7JYtvxiypv{jq "hjdmktpb^XddXSXTRZboRQaymYUZb]J?MXTY_^cppfgjTsoi_X{^emmaduk_XG(!'ehlhjxbj`dfjgbs      4 ɣ[D@tb2`֠o*)&(7diA~~lMUZc`ugfXVXZp& 0K{nrmf\[VRa\TXb]SV]pZ\\opri\[_fg^Zfhdjmhlkmsnpkijnjl^UWY_ac`^bh^RE<59=>@Ӂ~|P %) rty~}wxz~}{yoqw}|@           +  (i%^ϗ$Bߨi!iBՉ -tC~|zyw{}~      ~ w^y%C~ߢgaK͋@ )5!l        *Wz ,'HĪV@tͬ^gbJʍ &'     EN V#pӂs[͍y\NÄ1  4F{zp}~~x{t        , m$ `?$5q`єu]Rh !"~}xz~~} L         < >cnfЏl_ВpO_亇~ *VL~}~yzz{y~~{|}{z}{yruutzxqovxxtxvrwtvrpssoklkpqkmstwqnt+           a # )$}f^̓i xJ`x{}K #$zz|vw~x{voxtvtqluxx{vtuqvuwvppqkpqtohiehjgkjkjlhnsqnsztqmqnhhdjkfgglhkln       T] $kL͠h^ʒh~{y|}w|}{nrBfliiqsootuwr +`zxtspuvzwvuknwtqknpihjkhklmorsmklei*lnhdeea_^`cYYW_b`fdlrqktsstnqspklnrqxvplotqk     4 S+"ֆg\ѓk{}yzzyxy{}y{txwf,qۉpfזk{~7{}xyu;zwrtuuqvt# +=ovooedbeiifcf_]aa]fjc^^]_^b[g.fdacfjffmlkknjjmjbbhehlmjjkpqrqlmllpgfknn^_dfifxe       ~z|x_  ];}kdԔi~~|}zw~y0rpqtvmu{Y {wottswsknvzvy}tmspmpkqthheiumekmhklp%nonlifdghhknlmfhlmpwnwlinkkjifjiehktts}y}~ }p       {uvx|}~uv}~{A $iӗi`Օbvvrz{vwwuwzwvszyy8uqvpqyz &W}pwxsrxuuw|rspwoikkdlirugjljpmfjlpijbchigefmmijibkighnqjkmsjshijeflea^dhe}{|x}H   =}||) ]R+|y{i`֕a~}{|uuwy}~vwz{n:㎁ywz|H "}uruz|}uxrsotoqkegogntwstoqrh+onlhelehklgouuwoqnjdkpihjuy{pnqukvrsmrplrusq}{}~{y}wxzux~8        g t JĪo\ؔc}}z|tu~j6݉~zwzr #ezsr|}}uzzy~~zp{yror}}~~~wrw}|}wwy{qtxzupsrqsmr#}|wz|=     |~{~ ;'րy~|}p]ؐa~|z|}rw{uu|~vurplidolhU0ladfrpz. &3}wz~|}z|wyqvu~xtto+t}}~~vyovywz}vt~|yy|||y{{}||}~{~H        |z~X   ?rnxzx~tzzb]֓b{~|z|yy}xzvuyyw~vxvwszwmq[:vqnojs_ ~v}}px}zw{|tqsz~}sjqs~}{wvvzs(rwu}~ww|vrpusklrtow}w||wts{~uwqlqw~!|N        61 + 'lӏoU֓c}~g<҆ %Jxtx}}~~vuxz}xpzsnulqoopxtqrtjksqomdeT_kh_ u~|w~l       pp \3~zFϓf~j;τa yx{|,wtrirvvywxx}twt~wqq{zrmidigaVXaahkdhdjcha%x5     mQѠwFЉkh<nj "Y{}~w}~w{{xz{zuu|~uxxw}}||tzsxgicf``feglmrpku{ z~i%    -"j >&׃PrHтmx|~^CM }vw{|rv(~w{|~~}u{ryzxz%~c%      H: & ?{~_iz}YKܺ y}~}|xzyz}~~}({~/       bz}~xvwok . irhikg[aYYnltyz}~~SD߳= "0w~||xv{}~xezwzuy|xzjowtty$x~||{}{y(       {|{np~zvnsqvs Z{qvmtnu~PVݬt x~{uzu}yy|~}yzywutrxz}|smlumjcfkkjy|u|~w}znv~}/|y{x       +q x#Տw|JZw% #K{}{u|y}~{~wwxwxqifmig`\lcmqgiz{y~ztvssmkswxlux}}zy ,   Q2 I^z|~~xvz~wvp|{x~|yHY}_ C{z~wtxup}q}ypqwyo%sknrunrwyrstsnpltulslhicfeehutk|uhty*~ /2     ,:`J~}}yw~zztrvuliqr|CYច&'sێ}}~xylow{,~}zvxnmx}nts}qwy{sskqrnnlvkdgemxiuvwtkz{w{~|| ';$    ~y$+xi΃y:iŴIkzq}us~'|t~{mekpv|p{sqhrpsqoi{{jsrmhw}{lnwyynxq ::    V#p;ბQ|G\USl|~ozzxwt}}wksnkox}nrfo^tpv|{l`cvmqvqqxormssorsq`hknr+|~z|}xQ 7<+   V~X 1nm~{~~x{{{zv|wxzmj &ontxxyqsrv}xy|ze ikxorknjts|v{zw{x|u}}xmi zP 1?7    : FFŽtyqzvxqtqz~z~}{m  xx|xmqwtpy{wzs&josqpynsxxo{vhpzyz-~~T %?<*    B! %2dzzzzwpxn|x|x`t~v|wq~jv~2 $?|vvtwposvgjskuqz}x}z{i{ywhq{|x~y{}}~.n}||}@ ::6     ) 6 twYs~|~x~y~w~f{l|}hw{{||u_ {owt~|aulYeRhaZdri\kr|s(u|t|s|zxkymrnymbq~mnpuprp1x~36@85     ,J}vwn|tujsu| uy|rz}yn{wt{wr~xjojh| &N}nlzu}ozjltohsemoyrsvwmmnyzrkpookswrjydehbsj~upgpy/~qz||t}) ,?96)    mm|sU q*}|tne{{no~}zyt}|k|vwnpO z}:ym}}{~qjiq||qj`V[g\^\e}fg`eanffe[\`^ONXV\gnw]LC?>>Y~/zqxq{~}'!:=49(   ryv~{x}w# ;O}vqkquuvmgxhhudRP^|yhpqt{vzrvqxwuwxxr~{{z &Tsnvo{yvtym|jq|pyrrzls(}xsip}snbu{~|wxmjqpc`szt\_[]OO>.2=5u{w}hghlq{y0=794!    W_\mhfgd~hbjqX_kl  X~UYn\atZv\eYHRZebfKR^ohnyrzx|~{zxs|mmmxx}slq|R #~oo~tjr|}wpl}zvq}|)}}w|w{sjoprvqvzmymb`{nizQ\`\2rm}ywqg_ZeLZblgjekqrtyp~yq(8939-      @tzdypgugejpeijs A ^TCWZQVW`hchljzx`l{~ysz~z|{nig|wq /~sswwury}uvwh`xlZkwxqtnsvhyu\x|sf`l`zuagz k\lzqlfqsf4wx|o[f^tjmmsn~}"0>6:7! ( Krx~ttzO mkkSBMddilm~hkpsux}|}||= 2z|{upfotmlnm{p~orelrwn]\qkr}xm}{uw}orslwesyopovxc"xlp||~~*9?0<+!$&   `xyy{xkv|- r p_cOUvoj|}sc~z{~_v~~ymvuw vy}rpkjkfo+rvlYz{y{{qa\i{}n~zusvxwxghhmit|7ewxyxwtv~)5>9,:2$"#   ZtwupsKBSajq F.pK]zo~o|i|regkiVbo\mi{v\xnkz|t|i~nv- Gyo{+vsy~}|wzmpwt~sx;|v~quw~w~~m'09<63;3$  NbZTUhN6BJI[lM\]b - Oyrvihom_qqk_ENQbXQ\m{|s|~xrp {{|swpy|zspg\r}mrz}jw|gj<}wtr{zvyu{{}|y&26=?37<9,&    `noth_]b}or  4 j}txmvholdeQ^[hswVblpvp[euv{~ $Wqdx~zfhbq-wyonuznvsjpw}igushxpkhfnzysx|q}w{=nz~s{rqt{vq||sc~|ryyl~uppt^%378<=:1:<92,"!   !#t}umn}wu}|}s|D  bswzedfzoz~p}obl|v{|px~qw{|zjhyb "wvoysjkb{|n}kkg0fp\q_ptfxzs{xlnpxehl~q~prx|fow~iqqmpkffpj$x{tytuwktn^iu||sp}vc$7:998/4:?@;=9 ),53B{ozuvwyoj\~ Y2[omvfzZjW{qnm~{mqnrqwxztq{zlzzjqyxXtxzK  /+y{y~yenY,azzkovvonkpwzshvqunuoWhrzuk{~y}wv=x~gw|r|qsxkmrqyn}L 16<;:98;<98;<;J. .==:;=71(wowm{E9Z  kk]jhi{wyiqtw|wt~rh~~x|ozbv}qqzdqzg6 "xxsn{dge5nsuqo{vkm{swy}onwvijfdvubdVs``thqucyA~|{mA*4;=>5(*19;9$&  (7<<=:5*'|{r}}ru13?; Mq}utwysonpftssznyzx}yz{uunixtveᬁ{7suqdxuy}xxqmhdmuuvyw`}em{n}sklvcXwnfx[giyyhwUy|y}|w|~xtvw~u= (6;>?8+(+.3+K+  %2=;;8<8@8-'&,,+su*  &/:;:?@;P|sx`03Da~.h|xb~|yszv|{yyw{~sqpzttuzxurq|x{==7Oqt:&mm|pphip|vomyoslmx|l`;[Eᠧuusszuqz{kSoff\oorwwgnrjl|uzyuu~smleZwjjtgm|XikjzYemnupwmkw###,+ *:B?60.'# y:#+ *2(&9:9;1lvul,*kquta]l^eww{~~krrdltl~p|t|s{zu{nm}}ey~wpvK)=t|p|qrbczyarwmW^ov~~|{qnks}}q~nph|r{kat^~dvvtc\|dpjf^vbasmz{kv_omv!""+.&&:?@0-*%$!}D%*+)),#/9<;=w{xp^ -~xwyp~vu~ltyv{dmtzvxr}ronhoaj~j{ospfm|nvyq1.-)& &U*0/-" "*%#.:>okmcwkzsosG5pQ~zpwpnjbyxyytyutxuw{|hrq|Urhvslwmtlq~cnhOr}rq~d~c)-'('!hrvy//2. *;}~~ge~kjq}p%%7r}wfloyw|gwsvn~gpZu}|w|d~}hor|~{2:Rzimq.mYY`mnqqlctimvWqal[r|~f`Zr}}mlapbprFkxjxyhpvcpljs{lpyxi"(2<=1!5' f(,&&/) {zitjqp~wo/:ppxs^nllwt{s|e{~w~{a|z]}yz}dwirdxpo[v{gymuh.D~rrgsml.osq_[b`aw{\cT_klatPtiaegn]uzxl{s}gyuJ{|qws}cn{zy~zjzp"#!/8;9*0)!qwzz{,B??681,#pp{z{ThdY$&=jXt}uvhZk|riqpr}srwz~u~mzi`xv}|ottf|yquxo{zogjlwimy|.;`qhoh~0rugibkXhpouv~raccdchhylp^j}slWt}opxh~_ueyuy~vvdgf %6890#+-%#3u$GDC9>=;94-%FraypuhxwnQaeyhS3Fe^aZQpvkrVapZ~Zn{ipqip|\Xhx}xlryal_mfdyp}tgajopTyrriI2HhlFnw{{wTs}dzwdtPamTrcmn]i~^lJ`xxwbhqnsVuggE{grbje~r|f}rtzzn{qu~e! 17:8+03/*Wx,CJKF& 2jrkrprmms{\+7s]vqmrgol|qtt{zodhg}X{xkbq}|}zbdgzorvuke}}y{zq0Cy~wuxxytpzb[tirsfdk{_rrkuh{wotarajy~ow{qq[h|gmt}p~mknSdhE"(%0:<2)4/'c~zJ 6GICA;;BGHKEILM: 4kbmwv}edW$+9eiovyztktojn}myesaqwkmv}ht|sztxjsqfVu{xohw{]iyPewkdz9:S靀cbuzppl~acqmddxyi}zmwrwax}rwp|xpzflrlri{wljnvqcsvu{u2%%!+:?:+73+}~vezSBG>@CGE;3& Jtwpnz~pjuK/Al^xWt|wyzerqtztqlgngq[ggwm{kqf~nvgbi~nr~q~w|gkj}qglgj`2FnoZnl|tzplg`Xgx~iddJp`Zp|~`Ktu|lgrxuxk_khip`1&,(!%4;:150nplvmzV 0A?>@6$  gmmwpzhxkx@9Y}~prdmyyuyyvrwstxqsesnX]zrxaqT}^d_{zkvtztujniprlf}6=ZY~v.vy|xdb~{nlvvspliwvB[S]ryorlgy|~xj`r{wWvu~xrsbzims_oac`s{u'&/+%,;>8&50RxxZgxaU 2::?64003.#  ojqov}tfj4 9yptRhuzoyyuvx{w|uqn{tn_}|y`VrritbqokfgTkzkyqv|tkw|{}yudglrR6Me~xb||inuwqpyY}~]Ozt{qsxoz_VRoaDYTdbrn\n_}jncihg}|ululHnnmd" &1/$'5;6-1.7xf`gmckd "23CFEBEBFHD nnxicz{{hshp\*(7oqy|qm|qzwk]~xjlYbZVCYrv]TszjtUmhzh{lnyctwr}yZfoq^v3@`k~YYecsxltYzqlqlnjYWVwmdRstokzEGwijUOcf~jFt|vWwp{Onyjpgljr|avqc!#01+*30-/.=mrMc]fpR (+?FCECboXhpJdvP09oqs}|~{}~ytkz}lwrVruspfgsjit|xxaX{qd|vXQk~m~jheylvo|~rptyK6N2cZdBPbjaWf}`~RsWnOD\wdg|Zkd`d\pXcomdoonish}xIr{cYp}pjqury{dx~y"!00. #+(.0.5xpqvqyg #*5HGA?@E Eujy[kyr{y~B4Knudl^kvooeou`gyvy{{yswqn}zahzutth_cr{{hMvzylrxsUunkoa]2Ag2xfk{\]tN^`w^v[\n`ipypvl|fzhNz}qOakr>y~ft}goossz%"31-$")%-42.Wiff~z^ $/>LFA?DCG VqOj|o{tpd~o6#8b`h|~^}pqch[Q}Sqozvkbff}XZrdXyjvle~~isrZrYydu|st[vl_yqv{Qc{_Ri\{<9M멅QGJ|Tr|tYxidvlgiXy|q~po]{ehg~uq>y~ft}goossz%"31-$")%-42.Wiff~z^ $/>LFA?DCG VqOj|o{tpd~o6#8b`h|~^}pqch[Q}Sqozvkbff}XZrdXyjvle~~isrZrYydu|st[vl_yqv{Qc{_Ri\{<9M멅QGJ|Tr|tYxidvlgiXy|q~po]{ehg~uq 6V^(F *@`~3׽=> Gf+ HH sopt-2.0.0/matlab/test_images/lena_256.tiff000077500000000000000000002004071277570055300204500ustar00rootroot00000000000000II*va^Xfghihnkhmlknkmnhjmuqypy}y|z~~~}~y|wyupsfhtzjehitwwywxy{}y{x{zyz||~{|v~~|}~wrtvxva^Xfghihnkhmlknkmnhjmuqypy}y|z~~~}~y|wyupsfhtzjehitwwywxy{}y{x{zyz||~{|v~~|}~wrtvxva^Xfghihnkhmlknkmnhjmuqypy}y|z~~~}~y|wyupsfhtzjehitwwywxy{}y{x{zyz||~{|v~~|}~wrtvxzkaY[\a`hofjjjchlehkfsknxsux||x|}~}~~~~}{|{wtongfrz}Ͳifmqtwvxyyz}xv||~z}{}|w}}z~}y{}}~wv~z\@|naZX]^cihikhlgkklfsjgnnnwwyw~}z~}|{}|~~zzzrroofksyĞoflpst{vwu}wwv|wxx}~{{{|{x}~|}{}{_@2/qaZZ_hbdigghcfndggfjlpmqxw|yy{{{}~}~~~~}wpvvsqnngmxзjdimsu{uvzyyvxwxwyy|zvzz{~z|{|r[=2/3}ldTYaXaekgiikkkfieifirmprwuz{{z}|~}}{y}xztpqokjfnxȧtggkqvs{xx{yzu~uvw{ywyy~y||{|z|_<3.00}qc^X`_dfhgkgnhjehmffinorruv{z}zy|~~~}{~}xz|yvusoikgmvҿgkjmpvquxzu|xzvs||uz}zz~zz~qY624161mcZZ]\fg_jomocfjnehdikorqsyy}w|}~~~}|{~{tztwr{nnjgryγ|idqlztrvzx{usyvyw}{y|~pR/0(,1-1}m^^^]_gbeednggmggbhemkrrrvvx}zx}~}~~~}~{}{tuqtpqefnxƜigmkporywy}xz{z|y}~nS2(4.220.gbWY`dfijmhlfgiejdgdlprozuwv~|{|~~}~}~|||}~yz{ztsljmdmuϹcpkvquusyy{zxu~tzy~~pR4+75-9/..yb]Z__bcagidfmahkhfinuous|uxu}z~}~~~~||{~|}}}yy{xzrplujfil~̤lfjosyxtvsy}{wwzusG1)--5/4014qcYY\a^ffnjigejggjehkkmlpxwy|yu}}~~~|{}~~z}}{}|yyyvuookjkou}fhlqv{v}tzzxyzvwy~~qJK/+02,,,176zm\WNT]adgilkhiefelfilnlqqwzx~z|{}~}}}~~~~~|{~|}~yy~~}|{y|vmqkhjlqwβyhlnrt|z~y{zvwz}w{oR204&%/*-/7;/|o`XUV__edgjjhjiicgcillosrt}{uz}~}x||}}}|x|}{|}|z}{~{~~}}|}{{}yzztsnjlrxřekmntuyw{zwx{yw}|{pJ+)1/++-..1:/9r_]WZ]daflhqdighfhfffjkmqtvy{zy}|}}}{{z{w~{~}~}|~x{~~}z{vuwuqqmlkt|Ӻbrqwqut}utx{xxxqJ+,.02)/)/5325:mdZV\b^eegolmlndfhbghjnuquu{xyyx|~~{|~}~}{xz{}x}|w|~~||{|~}~x}z~|{}}~}ywyythpnmkksҼpkqszvwu|{x}w|xW34)8.0+01833/39|m_R\a\c`igkilchhgeifhonluqs{{}{v|}~~~~}||z}~{v{|}}|{yx~{~z|~~z~|{}}}~|||uyqrtompu}jgkiqtuxy{z{}qK.(*+-8249.4153;3kaZUXececchgggehcekkkmotnwuvyxv|yx}~}~}||{{|~{~|~~y}||z~}~~}x}zw}{z|~}|~}|{z~||{~~vvvrsqmjnvzͳ|cikrrqxw|}~jK**)//689831104852|p]PXW[^ccmfdgeegfggdiilosrv{xwux}z{|{~}{y}{~~~~~|}~~}{|xz}w{~{zxxv{w|}}~~~~}~|~|}}~|~}~wyw~unihkq|˝fbkoosqwu|ylL-0,)+.137>86525,/4zh`SQ\\ejgigdgfffdehkjjtsvrxy{y}xz~wy{~}~|yz|x||~|~~~~}}vyy|vyzz{yux{x{w}}~}|~}~y}~{~|{xysuvnrsmor|dhrkorsx{pK1&2).--2711311/4-//|i]YQZXdgcfkhfgjakdihgjnnsrxyuxz{|y{z{||}{~{~~}}}{}|}xwwzwxtwutxx|zx~}~}}|}}{zvysssxnmntx|ˢlhmikolrzqQ/+)*.,066<6411402/-)|j`TW[\dhcjekeejifeiefmkoruyxzy}z{~{{}}|{|~~~~}~~~~}{yx~y|utsxww~vx{}{}|{}}~~}~}{{|tzpsuqnlopsbfknrpxykO2+*0)1366:;57525-,.1+|i\WU^Y_ejhmhhiejefhfhtpvts}vyyz{zzy}~{|y{}~~~|{{rwvww{x|~}}z~~~~}|}|~}xtsuoxoqkovwϬlgimut}|iR/+,1,+.04<7848>*26./4,m\YR\^\_dgkkjehlhffhkpqoqpvzzz|||{||z~}}}}~~}{Ķ}yuutyy|~~~z}}}{wywqptrpmnpw|ƕiinr|znN,/&*-)13:4<79944.*.1)-0lYQY\^dcbfiiiffhkfghnprrnuzy{zy~z||}z|{}}}|~y~urpzv|{z}~|~|{}}zuvxwqsopjmqw}Ҷku}gH0%)*-,./52688;67-/*+-/1/~maVSY`[gefhifflfehfchlnqtwxw}u{z}zz~{}||~}~»vswuwv}~||{{|}||uvxu{woqpmmknwΧutwsL1*(-,,/*,37296250/,0/-0),zm^RXVb\hgfkh_ejddlfillqzutzx{|x}z~~z~z}z||~ĵrusuv}|}~|~z{|w{zyvwpuoosnjjmz}ȑynP1'1.-50508781.833)43/10/20l\PNWX]c_hekddkhgjhjfnn{sxx{w|vy~~z{}||~}~}ķ˿yosyu|~{z~y~}zy|{{xuutrotlpjqm{׷xS,*)*$4*/63445563.+852.*6*.0}yx}~iXNNUXa`\bbeidgic_lljinqwtzv{{xy|~t|w|}}~}wz{xzt|òþrmu|{}}{xx||{~|zxvusopomljglnss̈́/.*&3+3)681981><53.0;4.1)/.-tnqjYPRVc]`djcebbgbecmkljnprx}txw|wwuyy|z~~{~}}||||z}yxɾ¥pnyqzwuyx{z{zyxzsqrrvqojidcknup")((-.3)45203530.02M45/78-92ueespXSMR\W^\`cc[a`dehcfhrtntsvq|vxvsyy{{{~{{{~}y~~v}yuxyyƸruqq{xxv|yzxywwwvspqilneeciqx8'(+/*035853655.-.2900/+-/+89ziZ[p}j^QKKQV`c`c[_eccdfgjhkmhnvswqrwwt}y|{wz{{{{{|z}q|z{|zvzw}yǹàpnlpqtvwxsxvvuruspsnmimgdjptz"*#',3,4461/=53.-,368/+./2772u_QXm|rVNGQUZ[]^cb`_cblebnhdfimnuvs{sqxzyzzyyy~zz~[jx}yp}s}yuz~~ľĺ}jmmqsrswtuwutrsplmkkkcdemqә1,&,*).-9;2=8<6-//352),/1/7<-"mPKVo~mVPEVSZ^]_dgbbdhbfgddelmoqtrsrsvty{x}xz|}|}|zy}`out|t{{yts{yŶ½ĿĢmfjignssnutrqtpoqjmklijkrϜ1&*.)-/,5126768,/-164.-*+35?<$vVLJXr~lQQDNTUa]bkilbebbddijljgqvtnrtuuv{zwx}{||}smrmtw|ssx|ux{uúʬoeahhlnjqpntorprjknfbgnp~1'/-/-,/2040675,1:89973/11=?<'#~fQLOapyiRPGPV_X_fc`nge^`gd^aehpmprrusurqzuqyyw}{~w{xnrqxytmlxwz{y}ywȺǼ̵sX^cdglisnrjljjmrjhedjpu2)-4),.3131071:2(/=863,,:/?JD2 4qYMNOct~nVPHSWV][]acfdjefgcbkkioptstwpqrxwxxy{x}y~|yz}oqvrmjmqvyptz~ľþrmcY_ahqlponjljjggggjm~z}q;.1,&)'*3')1[t`QTUVQ`t{kXMCMRY__\`cchc^cfebfhlhoqpvoyv|w{w~ywzvwz~zoonipmssrsr|{}xwz~x¿øSQ]digfhdgchffjlspgachym..,-)*5.-9.2023.)/470-/.13>KR=+1Z|gOSQUXW^n{hWMKPX[^a]fqbh^`cdghkigonootquvuywwy{}wy|}{osjhnpwxvyo}}uzzyv}}|~yŪ´ĸuKY^ccidebhcea`ipwZRRYlys7*0')*/3/033672+1,58;.75.6;HQQXak|yfT0*'+2>Pewu2%(()++=2;D8247+/8:6-1/;627;AHZ}Y[SY`YZ]^\VX]o}~o_NHOV\__f_c^afadehahenmqovwvuvuvzyz{ktfontonquismstsv~qz~Ž˻ܗADGOV]kxfP4+*$+0FZhH3#%++7558957:0326:G6,9165728>[zU\_[^Z`aY_YWamzldMMQYX_\_`^jgbgfbgbkggkmlquwuyxvutzqigdjl|vpoqryyuszrzw}Ŀɼ½r5?GSYm|veO3,+%&)5L^{c.,).*-529=53640,142-*/12@433;UzTTWZ]]\_^ZVZfpwkWQOPVWba_^fafhb_d]efejlpoorwwr{uq}}dihhjlqqqnppjqktj}vz}~s{{ùƾdzEBDOXkz~jU8*)3,*,@U_wv7-,),))4625?473,.3:3+0-40214:Eo^Z]\_\XTY[YZdszo`LLSW\_Yage`ecffcdgjiikmvsxqntwqrvcchqhsprpqmykvrqwzltvyxŸüŸһqZGFUitzkT<+.++'%0BYo{L)'+*+;/238;;6?/048<2244=66(.Ni\Y[\_ZY`YWRX_p~kULLPVV[__bfbfeffcehgljpnsquttvqjpƩhhcufklkulmspxwy{w{y|t}{gqyɿưn8HQby}iT:0,2)(((4D\kwh1,)0*22/?838865+6:8/3.7<10&(2\XdW]]_^`\WRX^j~wn[QGUWWY``a[dbdjcfcihngmrlttxqrooΐdgjkinphsjtqpzuzxr}}|z{kgŲ̿>>Kav}lR>3,*0,1%%-CUЪǫr6+'/*4370:7188=49186-754721'-P{Za[[\YVYWVSS\l~m^SPRR]Y`^[b_ldie^eixomkhknororkj—ebndjmmmppvild}uuwzv}nymrh4J^mcU93)0-.&&$&IذF*,3)A*3;6739:C82;530-6671,+7MsXX[X^^VVUZSXYiyzm`HGOOXUXZbd]b`^_fh^gdijpnwnnoilyٷu]geajnlvxojvkxn{u~{nx~qp~ªƼ4G[qlR:2-0.((3'FĸP#(+-1*9>=:9/86/5794/47;337;038435-).WWYY[Z]WZ\^WP[o|ykOLEILRZ[_c`cace`gbelgekmonolofkĪi_ikiqogtqzm}pwzs{ywj{~kkpĿŽž۠?Xm{ydS4.*(%$1ո*/,.,0497:432..28031:4>2+=KuZU[UZYZ^`_ZZ]i~|eVJDGPPZ_[^bhbia`ch_eilgiisopje{wcaeiilgo~nnvk|knu|ku|zolxĹƾĺiKh|{iH+'!#$D͡B+-*-.129F-12-5=0-.2341-5EhZ^^`\[\_`[YWYpxxiUSHJEWSa^cdc`dcfbhdfffkgnqsuifÙu`aeigkmt{qish}~r|zoz|ykoZ»þ·Ƹ޻L\zv`F+""&Ss,,0./24;;40/.+,$7099:888XZ]`\c]]`cc_V]ly|lSIMIQX\_bdab`hifdeiefgkrsmsqnjҸr^bmeifsorYppm~~y||rvxrqviǺŽĺſ։Xxm`;&+qҴ-*+*0182<1.,0,&145<77/3Fp]_bb_bda`]kcbn|whTMMQQY^\`_cb`fecfilgnilopqpjiiɭn\gcmooloWszyuywzoo~{zsnjù³Źqv{jQ4(?ϧ**+-7?904+-4.,0-1363.*5e_`^accgb`_bb`mw{iTNJNUWYbhh_d_ecjgadmjgmkmsokhnԸo_ihcidaVsqxryu~xz{yrvfj´þǼǽž´ǐx_G=sī%(,.7:>4.--+/*28107*"9J^ecabfcbcba`_l~zlWNLMQ[a\bfajcbjqhdegmlplqoriewƞ}g[acgjciq}rwrtz|ipyw~z\pýǽǶ֡qY[ʰ|0-21368052/0*,0>6>(#$Akcadeddgbaa_abjy{jXNOR[V`addfecifidcdhiillowsjhΓwoe]^hannrqqr`xue{v~v{q|fpƿĘΗpϾZ/'-1/.>8752/532714' ,]ebccbbccdac_eo}{oYINMWV^]heaefcgcga[elhmlptlf]׼vwg^e^lhydpobvvr{yy~sxytgsýʵýҾƻ5/143/.583.0/*51693%%&*)0.4F'..6/,5Ga`^i[[]ccaa[ejrmZRLQZ\[dccfbeag`_bbdb`df_[Rz̮ªzsik`wjvzɮûе,(*83150-5149,0GGm_agc``h`cedcittdNGMYY^a_f`_c^dccbfcccje^[RԾ˱xij\zv}jzvsɸȾϔy~}$)+.743:.4E6=8..82.I52.6@jf_b^`cd_dbfkmsn[OISSXcfb_ab^]ccda^bgdj`\TOʾgex|hwn~}q\lohZ[priobŸ¼ɛfPV]ݻ&!#,-,7.--4<375=Uae`e^dccbefjju~nZREIVYZca_aaa`ag^bacdeab_XPƾxw|{z{jzv{y]_vvnfNpVqc`plw~V8Ʀ½þңvOVZaq['(%.5+1+-417027@hcbabba^eh^ddluo[KLOSVY^ahaafedfdgbcdbedXTO˷wqwo}ryv|tkw|xmo\MTzo|~iXynhCc@pq3/ĴŽ̫VTWZ`mگ('/*.//2+(7674-9V{cdgbbf]dlfghr}nWKJPSWb[_`ckhd_icfcafcgbXVR}˯oqk|tyrf~rwrdfbJ>?D@|{n`TW`ERQCC<,8)@&+{ģҴbQRW\`e2%&%3.5-+)).76//Nifgcfff`adjmjjwo[JFOURb[e^bach`g`cdbbbc]_[SoѾαʪ{vmju~wo`zww~}vxhbheX_kTX`M?CE9b7B@856,/+.&#R̭l][XWX^^cڃ,,)2/11-'6659,*1L~cccfbccj`dklnxsYKCPTW[f]gfaaf`cbfgfdcl`aWU]ιնŚwtqnppgnvu~yplsjpu{lJVjXt\Lg88Ax`:>DV,0$#)H%cmÿžɔnYVV^Z^XVfqմ-10*26-4.0)05.+&8^ccfildbabmihlzq]SIUT\\ea`ca`ahacaddi`d_c[QNռд}l{tpq|wgqvkz|}rn}f|klvcCMNPSr`lIFMUx=J^KI`7,&$ !.¿¿~aUWYVWaW]acc1())08402+531;.)*@wbdmehged`dejnyp[NFQSZ[^^ab^`_dajbj^d^b_`]QOҺ×xi||o\ot|t~|zm|i~vxR;:89:2hjinjhjibdfbgjyrZKHKYX\^Y^ee___ae_\ebdgfeccYSVÜ_ufxz|x~~w|xdKxuU:@WSA>8:0O/#(6ft;=,48{O\w\")w!yǼZ2X]Afyd}'(*-,00927472,.213435Jwgigihghdgedleqt]HKOS][^^`a]\^ei`b_da]jjlgga`Yw̶ba}x}yf{tzp}v{ohr[MRJG@USM?92\J'&+=Hs.;96JUwS,2}Q Fzwľº¿X0._rL`p{tȿa-&**./53583470.+*522.2akniqlhhejchfbsw\JDITWYX_[`b_a]a`h_`aagigkef_WYǽ_i|to{}|x||xxc84CMT@MWWBB+)Tk)(,/X5E)/7<\F>d;'d"*{wÿqRPVEgu_tmcέ4*' *--148<4C5701031:21Elgmnproig`cefftuWMKMST\]\^ed`dbaaiadb`ffinfeb^Tlؿg|xkvyy}yiivkoXSLt'#mAe}tg¿fKXlM`_X|uh{Ώ5+61,-.334:6@94,9*/5695DRwnmlfhiifcd\_cp{wYIIMRW[\Zebcacadd`^bfedhjiihf^[TϽĸiutt|ttp~uu_cN?Fb^>,'),CrN&*00K;8+<205)@p*5eBoĿÿý]PD|[g`fxzxͽq00%+0+577:4337;20-.,1::;Hc~xlkniiiifadb_`nyq[LGLR[W[[cd]_aadaedgcdhjlkpkng]W\ĿǛh}p{xv}~xs}q^pW>]IQSZ`Q612*/Rl6$+\+5:7?N[TX8]UF`xz~T¼ſoY]Ikb\z;41-/+).43;4/84:1++//2666>Iu{kkkmhekjed`^^h|sYLBKMSXZ^^^_b_bac`cbajllknrjmleZV˿͙|suqequwip|omB;PLJ]MieB746*7QIG.9k*25.08?B59U:M>kVzcWP@SS@R),'/)3301997779<0*+1254+2@Y}~lklfgkedc`b\]jww[NEIOLXZ`]cca__]^bebcghnhmtpkkc_VŤ|~wep{}~rj{~y\lOAG:;HB[ZJ8/--CB@`XC+/.-./110($<6>.=dSDMA>3G;4kfJ'-423/53-,*AYxV^\úy^V<,=VNAuJ3**'/.8>85;A99@463)./208>Z~{nnlgejgbd``Y\h|w^JEKOU]Y`a`bfccb`e^^ceiglpnqrieaZ|Ænt|r||zhlzwfObO6;8;:872E/-*23-/Kmw~klhmlldfge`_Ye}u[OIIXT`^dd`ggcbbabjdfiilotvrqqhbXگtbv|tyzzndsvv]5=/8_6+3)/3IY>GT;/IB(Gu9*.04/."$)`}uNwzľhSC006SH]`-5.1.0/43<>;HA?60/3).31-8Yx}gjfiejnea``]Xcxw`MDOQVZ_^deh_iecabhbdjjgmoqorqlc^o،egpsnqzspv|r~x]-)?>+.-,/700/?gdlkgh`gcfe\[[i{xcHISRU][aagfdeie_bbdhhjllstwomnjgcljjhjwryn|~kwrryni-+>`,)&/4+018VE?K@EZ-<2X>J>)$#!Vmx˹sYM.*/BU>M-3*/-+316:@=@E:/,13/=*-6Nvhiiklihhce``\kwwaQCNQV[^[chc`bfdddfffhhip|ouppqpe^ۻqnsqnvkc~x{nWZNAAB5.Ub-')4.81/1@LADAFP+;-^)$'#Ah§bQ1#.0EFuM/1.1E88846;A9A530,228(+6`|dfmfnjegecdb^evweUFMMT[Xb_jefkekcicdecimrmvvslkmb~ަujuxtgd|LZQHY98R3,fK-*.F:<*./54>94ZdB7/P)*$#!4k}ımX7.*+7RBe3?23607889;DD>8.,0267),:qjihjcgigde`]\cwwfSLFNW`bccggjlgihbeeaclxrxstqvtppp߫nruuyd~~}zohUD./+&5jB*/AG,=-5B7.A84?rxP*6)%#6{}ĺsR<0"'3K1s71<06578::+*@/74/772.<.o")y{ʰ˽tUG-$"&AEc9349<27<9=CBB>241/460.8`kjhleaei^e_^`eszaURTYZ]acafgiefjhjbcjepwrrqvuxtswtnnxom{|h^a9;1S/'#(EXGN+/B1/762H:&,k6.-507<.-Kzhigkedge__^^VctwdPNKZW^bgfddfegkdhegdgjuurzyv|{vqww{iqiF,>+qh'(.*5l;+0MF-5:,3T4(.R*MA( E{ fz}þɩfY>/()3UH[>(45<5:87<8@913,,:610/SgeibcfcdccZ^YixudKKKW]abhbcejjjiehfhhlitwuru{uwz~yuqzn{~aH-K3'?F*130'5a.;X9+79,O? ,}^otͲo`M3)+'GBiBD2;39:AA;=;7063373+/EsdhcfjcdadibZ[bvs`QQQSX^`f`hbkiijjffhjljlvxrllmnldgVVyi{zbN/-['&OE,b)9&'6Mi?7)9.,R--<91.ca!>qt\Q4%*,7IV9/+93=8D@B:1*32893)3S{gfgfbff^c`eWZevs`THQVS`^ddgedbifbifkjknmrxyyxwux|}Lag|woU/]M%#VZ?4(,?<:D@<7.8/553,4hdfcdgcea\a]]ZewudTGPRX_^fb_dbhjddhgeglqqqwqvxyyywwuxzu[-:Z@&$N`5!7(8SnPC1,-=2+o'&d=&]*02$d^hƥ_G1''-5DyOA6=JB3;@D>51403@8.5Jtihnccbaaea]]Wfru]SFSVRX``ddlgdfhegijhhpoowtyvuu}8>CYv}qq42^w")/Zj$"75M?2C((*-0:/G$,e<$mE;!EtdMRuyȽyG70*+.-Y^_C8?;K>=CS?91714>014W~bgegeecgea``[euzaXJNXTZ[`ejgilgfgdgekglnoywwxywoV%!%%|pej95YA_"+:j+,.4:4:+*5717.F+8I>3B%+]xSXaf[hdft}ÿƳd?6+'(*/`>x33GC58BFE9421259/1;e~cffdhejcdd^_Xbrt_PNPXUaacfdeeihlgfhegijssuu{zy}d6/&0UYDO7?a,-)Yxr!+#48+)()0O21/:L:@>=881,80<412Flkefhh`cgefb^W`t{cMLTXXY]_fndece_eegdejoprovz{F1$-P\m@IW6BOT06F^;"('MB,S3T)>(+ )PYi%]/#'PrsƳñvz`RMA9Og¿ýrXTKV^VV6.,+/@.@45OCEBA7+521-9811O}gcedimfbfcc\Was{]NOSVU[addhjgcgb]hbhjhljiqw{1=?#QQMhH:@f_115rQ*+)&G?/,9]<0$)(*1S%I'2qħǞnu[ZUONN`bXaWffyq_=7)'*A1W79G9==C73./5:9995\}cheejcfcecaZS^rzbQHUX[f^gigcgcdccfacchlmnkpylPg}v;R13HmeADYc#&qD/*S3&*1e['((/(*18b)&!{m£ǻɂbqru}tXZ`}Ysqdcdhz¾lfq}boso_PRzmR+')"!3q~ɧ¾YK?C040//0,/2Fh8),*Cuʟ8:/72?V|[1+438;/54(/M,ZGA=J<90/0/1725/Az_ba^^`[ZZYOZLQi{dRILTX][``bfbcbd^^XXTƽzePV-"/*a'7w%@icdy8-,?)0.Gf01.2+0;-=Z2'!!r`iPUE2)3=C/<'(WV̰F,L?myyյQ2,1,7EP++56:/02%,O+YXA?C=<1,1580/,0]bc_\ba[^ZUQQHQp{_MLQW_ac^ce]bbffa^\VR^g-Q,&Hm>07f@()RWRq4..,$5,425'(.,2)*:*/K;gɤz[VD94.8\Z9]/*p8G]n[ztsoE2C6&-++//)1',b,{OfMY4E0-4345304Ht~i`c`bch\\XQNDOg{dUISRZbafldfk]klrkGA0+qӶ9()1$/=aE70C>8D:>Uau.10/6.((TM,0,+50/'+.%@QƘcr~}uoa23\rq>69MȰa}towu{ֆivAg_QGmE07./(.-'4e-jW[LV852?01>5,-1Ydibb_dd^ZZSNESk|xjVPPZ_fdalohfcjel8?09U8L%/#&3eQTY3@UFRb[`iJn7)5.?+,+=8(@')/5$-#*5./-178+0Cukgcgaj`[[UTMHOe{iUPV`bfkjqopm%$7NM4+%H__tSGU$$)]-aQON^Rps8`+.*)/700++,-(%$"9_ʦŠ_u|x}lkoy{{ɭu[A/TL;59)H69K.SMYJD322/(:9.:Xygfhiah\XZUOREJd~hTQS]cfgqpono*4j}A@F319vy:/Gz'%*8[7Oh.Mirc\K#-+&).04*9/,'#"&|\ǖSj~mln{}~w||Ϊoqa];BX|gZKR]_bopnlrmnuphoL;G]`0<+1VGNkln<4lS&*2-=Z76`=Kr*+-+2,001?00+*7od@Maquw·wrooa=@833@U/12(26*+6ka^^X]UWOUQED?IZyiWMS[a`hjolpnuz`soqw?8217mMhtu_All/$'29bW=HOT\s;332436+-//3.1'olLCWdp|y~ƴ|y|qdE;4/4;FB?zGnuXphsJ')%21:[ublXNEj_QM'(3*/*/-+(Bmj{4GVmpx{|zʷ~|tlN862;18>#5w4<%B+,81-+[ÿZ\gVSTSSJIF?9Db{kTNU[Zcfgs<4HV8<>BFQgLwObyV/))'(*/>PGu|j;12c_034:/0-0)&ofvШ+6KZqtz}}}͸}zviF843I:=93,/@.;,-9+/4iYTYXQJQMMHI?;C\yfVOTUZguu~~uT82\N>?=I4HdF]wo:554*1.,02GX6?j/$1DtF8.2.-//)*:rv-(8Ubo|zз~xzjF@1/<4A9+122*,)20*,BuPVNTLJOQKIF<>>Zy~lZISV_dknosuyiji_UZ\:D/=Lo=Ks|N:;),>33132-I.'@<"1YpmX% $$"%rrsƻ2*:84CQhpz{~}ۿ|ymO?,0/19_0&$w(($A:0.FxJLRMLONHJI;<6:XwlODTZddjggzT/JpPV<6MtE3::5I42+)*(/I2.=--`vO2/&+'`dyѧ"%/H8GSemt~~}|ȡvkG61738A\*$$l4$(;<-*ZþTNHLKQHJE@;21A]wnPMK_]^iwo*75kvQ{13+tIV6Zp567>C,%&*)(+SLG:8N\a5ti%&|k1'$&U19Veos~zx|УzdC0(769?W0&,bL)/85.0f¿SLMNNOMLAE:32:VxcNIHVoeqX*6`Ry;897pNjMdA8C<5:,%&!6JlVL0SK)QXYoqF!#%)X<ro>:Fvx,2s&!%yyx͉%%!))\6EMblt|{xx{}ܨ}lX2(,0;DMD3$#HX-+.*Q~QVWKMEKLCC7212Sw~hPKFM\oxvzp}f44viLTSJ9YX]xT[cp_DS**'0/.,"66IP_08702P*!+J8/(*?p-$'. bN(&')1&2iV:U`ns}~}l|wvҧ~xY1*,)92@H=O,0&(gyP.%%]W[PTQNMNDB;83<\wmhSOW[_fdmu]I?W_nwRD"8nQR.WnWs\782-M9\'$38J3/TD&%%,%<' ")/%).o]PVbjsw{|~tV7Hfs~{~ɿ~r:(&0-;3CM7N04$(X`((/mSRUSJNPIECC98DgqYKNW\]gjpqk<[:^TwN= ;R3o-Hncs{5<+'CYG.#&$-HMc=-*+2"/4!(%&*2/'.niO\dityx}{zW;Q]WYrv~ƪ|`-/,--44CK@Q305&>}`#@BzOUQNNPMJAKE?BRmlWKSS\agoosmJeA\ROZP&8qAHn2Kxdyv=^#-1Xv1)( (YT,3>3$.;i%'*)4,/(,0peNcfuqv{~t}{wnbyzs@/18**2]VNE+*quN]YRCEKeqY{!'7'oL7&$pm,#JDe^momz{c'#&;JF,-';,rjS\ipvv~~~z|wzi//.4/-39NN9Q2,1'+e;'pJORSJRTJE@HLTYzpRLMU]b`iwslD+2aZM<%ZyH0H]GjHpVwjz1$>*i79a6F3Zkh~dfm%*$)1<41/').w^K[jtuty~½x>//4,,47?SMKB:1*+%U=0}LMKITOPMEHDJUc{pZKLVb_dejyZ(3[@F?NN,1QT?vphkzTUY.4.OrH$/W/Mbdqo[pj|:.4628?:34118w_Q\mrxy{|{}t653/*2+A8]DPM7>)."pTJJRNKFPRNHEB>FWc{lUJLUabahvV2:cMSaZ;25JVEMghr~iJ]K@MGjp6>N+(8`Yvt56A>784?6,2-2o]V`jtxx~ŨB2436534H5_IFD?F5,#XQ\gLLEHJGNKE?=BTemXNLVY^_jlW2=XBu~b6,10KBL<_IW\sQ[yUC`Wb^>/B%4{SjZeÑ,&24.3-6A<./+&pofalqvz}}yʷƮu661-0-/8D8[HIB7D/'"CWpjNOFMFGNIC=9EYhlZFJRV]gjzO9@Jv03F0<5O8R=[G\wNQYxg6tlG?'=DXlZY-$-40,3-3K904(0tko^jpxw~|μñG01725.6@F>OH@GF;3"#;bkuIFHGFBCEBFCGOb}pTFNUTWxowv=CEn{q(3;;E9I;]AEFAy;Lto|7S8(?2Dfetñ]VZr:'-468.5,=J=-4,*cg{Qinwx~ŧ|/71,/7/3E8S[GE>F21''FqfvMJF@EGDCA>BNR^wsTENUYnffw6Ee_zX,;2X>LF=ALFKB^e95skz~/++'tk^_S`Wf@*(-R32/889CQ;/&(kfqSbjoz~ѾM)..:31-C?;HLFI8C;,*'7quqJA;??@EJC@ECO]{sQGJR_mdek;X4ThD75IA?SEKOEJCEG0$'*{x~}}F=;>C?DCD@ADS`~mRJKUv^^eiB:(r}F93>A8M@AvS`XPP@mS;BXm+Scmſ_[]*(%*@q5-*;46>HD.,+UPi[Vdqz}{~~{X/+1531464@E?LHFPAF7&%.~t~}?@<;>>DB@:;HO\znTGPl[Ygre4/2SjM5>@B;49A~TndUGEDzQ;lda|Zuɡ^nYwB" .-/T.,05/;<=N)+.`N]RScosy~~siw}}zvvyerzcav4/+-9/-082Q9BACQ=3DC(,+px{99:<>@JA<;EMSa~nRFliVXq_>9b76C;CHQ>1=M{n]i[M?Mzay:a`:}ѴMobd$02:&,J=)5*.81BO,'-U?XWEYkvx~~[TMHUahkjog__[QZcpv}t]Tcopsa(/%.=.3.<;K7O>ETF,?G1)+b:755;?E@@?>QUe{pQUtWTZX/QP9+(UCSYM]esy}}~z}tk^^`lqsnqljkoks~}y4-+-2;++/2GA6WH?SD+7P2&*Q667;::BB<9D\_k|id{PN[rz{]7HA7,88.?E;f9:Lcdaeki_TRf=HhԥYo_U*1371,*9;.0388@;JB,,NCQVOVbqux{z{~|{xyL,.-18-123=P39`ERSN/;a22)M|9;?9;=C?=8CU_dy~xMJQ\qrcE?TKC*4*EJ=a/=K<_nl\Md;*2NJVNLM`kquvvy|}~~yz~ģx.++025,*(3263@fCNS8/EZ4)+O597;:8:>@5EW\dx|KGLTlkhbUJ8F-'3*dE;Q?BO-QYly]b::Z`tilr23+5152-(+<51,68B?FC-*BH[W;NZiouwvwyvy|~{w~<*'+,C/,+(.I-*9pBQUH8EPZijm8@FG340-j:c3`bp5KZ@WYs_gcx|־_~ʗ4-1.1579/,39=702I;;DI1.JXNT9H[cmovsvyx~{z~i/0/--=/1/5+E/.Cm=GUBD=T:16K~~4.386;<978JQ_\shJJLPhdtg74d2$5+Dn/YK\lYNmN:Tw{nqf/:-51=5@:4:304474D9FF5.AVDD=AO\fhlnstx|~z~~~N'/-23:5?/;0B7/Fe;HXND:[975Bz}A3-36?8<54H_XUqkRDAZncfyJ57x&1."_]60STbYl{dKBbkfv̖e948:5;0/=v}2025073/38Q`\XonP?Edednf25=ru///'d@6)?ag=twoLTLz`fn{zuχˌ0.0,503:7:,)937F::H2<>A856L=Y@;KPUbiinjtwv|yuz|~a9;+-(,-183C479A.J[HCfH@@NC=7<}vu-/254531.=ncafsmJ@E```^JJ4GzB41$0X8A9%l|TfuaquUwwjJwglΧ5335562:9;=5588943<><>B>E;6C6OG7GVX]cillqy{-?60+,/.8:5E41,=-I[MF`A=>MQ251}{x54/7/201+GdlehrnO@DZmdYYBGJe-7-'5b3@5Ci^SgfBW|uz7^}r|ܶP,)-905,09/;22B/37108<97;;8,6?CK:;JFT\aglqtx|Z,T4"+0.36C7>25+>1RaLBXLBFPM4;(~sv12-352/35PffgiynYHCTvyiZNB^X^54))@\*1>2GmcfyujyfNXVctigbR1.35;=6,4;96.0?26=00+;849H603?08.>2264;4;78:;;:@60C3;;5F95CE/1+5>QV]mxz|p,+E169:559;L41874.?hhJMDFPOM7X4,|wu43/1,,-74E:JB2.4)Kxt9NKfaY|{oQH]]?6<56;772;>CM2--E/2:59./302<6=C4<9F>U92+6$0xA@MEVy[er{zvzwB2.2<338178BN/13K423:8437*286?<6=AD99AII=5-+8>BFEAMZ^owyya+.92867;716@374/8@@afWLMHURZ8\<.~{vwkB30+/0-1+*/5)?B^_[teCAle0*1QH;B<3F<.6-.))[R`AAtqlM[5..184973IEN2*.X1030:524/351:?AB=?@55HQJF<8?;ADN^Z`gfryw\9456779?5:8>77-4/A>\mTTSLIP^AKC4pxz{wsyƾ_<+$)**/.1,(),*'3IW]^h~y\IyʟLG5('KZ26D7I<4.-+(-QUE6YyAhOwFqq=/)-3112QFM1*0J644-8;,36+427;<>@8<95FQQDJVnmnt~pA;57B<96959@75-/-H;]qRWQNMUWAJ@U[RaUG??D(++-37KOF-(3P2-./35-10-2349<7@84214ERWXknxzZ@972=43<=25'80I;XmSWQMSRbJQGDsysipmqyyyq{z{xrǿb:-1,:+3FB767E<4.+)8=HJHaڙ@QBQW(-(;aJ9?S7yq[F+,P~nqU_~x];V?0147:DV@63;_.1572:2..1635:953E5-5-FRUfpw{ġj=363-37./*165@XrLUNGMO]JPH@~sz{opqovoqsupvtv{~zttqE0'&)2A972>05MVUgwz{̬sE;569:35;5>ZZsKPTERN[KQSI~}uyqsspproomonowxy|y}~{{rsƿwK.'/29>KUSJ_RGK<25614EH9;Rl~vF8H7f3%("4[P,5=59CkG>@75G~R{zx\ROwX[C^uwW:,6<@S3'*:\5.:22,94/86.92<;99;493ER\io|~~{{}ʲz?1*5&2*17QKwFLPJQRSGOKJ{{qrilimkgimrnvrttsvsxomsĹqI%&.7=AIQWX[ytc]QIA847<862A\vgNG`UV+01'-9U@G+-6;kTI?M,$ntW<[z{?OiKrmjudu{_@V).3BX7-18[./5-3*363-3144=>8:47;2>IWmyzq~}~}~γy9/'($)2QKsDOMGPQM@KIS}~vtomjhbcfbZcfeeeihkibeaa3-/2>=ADTRQUUq_UQE=G@543BVpmOOu`.$')&-,Abq #19ubMBk%!8xVLbQ8eaccf|popp_RWQK345?[5.%:_1.2-5/67821.186>7E@48/5M\kpt{~y}|ѩ]1%&%4J\lCKJJLRIEJQ]~}xoqijbcbac^Y`^nrg]NYĶi--.AAGDKPVSRUSsl[RHNH:5/@[piTZ5.+(/*,(6P!$&5ypKOy1.'=}i[uC8zmg{GvzO.gb64AO7)%;M62;.6,799::25678EHC6<3:Keionvyy~ƈ3'&9FWfDIFIIJALEHf}{{spmebd^`ZZcvtq_LRʿrB-8DOOJMISYSSZYyn`UTOG2+@Toopl.',(,*-AcXi'!#AcInD2/+e]9WmyMAU>rpbnu{e~33eC9E?7..9I1386:119:E33,766>FS:837TXewwstxz||{ПB..:9cGLNHQ[JH?Ftzzupifl]Vhi~sjIQ©Y/*6EOPPTRVYW^USQ}qabSK0*:Tsm|Z'-,-&$$*eq]hm>CDP0-_v<=D7OH4=2X[dqsxux~|zԱL./.\AFE.@zV:E7:NcLasn*7a+\B?8.105KB0666+14=<:823<9L8/-))*4Q9%3N>@:3VA?egVXq1%:`b8/-2/9P:656:63.8?7232;@;GY`B-2MJotryqt׺M5NCED?OUL?.:yyzpt|vnbøX,-GU^YURS]hhf`[^VezqWA*9Sqۇ%)&1:;65=L?-9`C8??B6;4/2/-VP):RMHDoZP\s5Iy>85/43;I876<<5;4DFMN)8xzx}qnʽH59VYW\aZUdjni^]VW`gk{eC+6XpgM$$)-46,1MGB45841G\F92++?6,4Ru53G>FIKv`Ov~iucy\2W02.,:GB8475,/59ZU,%++7B@:688,6:>D5<5+7I?ToxiI/1TbhgT0,1C08A)R}̼jIFRa]Xd^cjptsc__\gef%.On}W*0RqoFc$%/*+7.T62.E32*3il2=@+)'aU-*j@Ra2^_S@Ycu\kqyu+&PO("#%7..;7`v~qQ&(Ifkv|ܴ1'-=.35&a}}ɳVIPT`W^c_foroaZa_bdhd#'4Or_)-MrKx"#50+14R5+221.-4ns)4;.+"9`J%aE8dYLff\@St]qjx8 +N53)):E(+-'03K5--4/-000ts+/T?("/-cZ?K.O[X^tvn?[Why>M"9M '';J\a`-N;iJsnjMRRY<(T4k9" "G=6X126(.76C30:?88Xlqhc\69Q`zz|b(.&) +~zy{ĭ~Y]\c[Ygdkppme[Xaamhe^j(+6`P'&Hoth/12/.:@.70.40/3(Ol&'KB#(<#:77H.N>XZfecG]Lbyj C-g/#(%MN9g3851+.<;.)7.=Dbrdcmd32TXt|ܲ&'"* /{|z~˻f^^[_[djjnrqf[VX^bmj_gb!!.@`Q" @nq14/(0A1/6+&,5023lc#%@M+2A1=9$2>4XBlYvX\R=elr1/+T*!$)WW;U/94822A=3+-;5R\]dvzc62d_sE&$#3~xyĨ^\\\`]ginpvn^\[^ackdbrn! -Z[%$@nsq(:0*B50-62)9)&)9W%0)C-<<659,/0.O4h`teNW3bky4/hUk))%SNAK47,24/:5842<7Oblx{ye0.^krܝ+%" >~x|˺o^\_[Yeekrprf_Y\aigid^hf"#,WW!(7k-&8)5:-()/)$1'('rb$$(67E6;'2.6-1G7`Lt:97LhBqnWD&+PG?<8<2?30743:;:J]svyuf04Vht& U~x~yįg`^\Y`ajopsqbZXYchmkgfdb#!*J{_%$7m}1.49?)+%),/2/(,SNw?$(,/:M':!&/77*>>54mEBU^JDq0..M5;3D<5F263.7?B1+)3FF'3*/07:'.I4<|tlSk`@&(%N9L0>8822:1?3513MJXz{|vu\1P]hz|ښ $x||wzƯpjge^]bgkurj`Z\^hikjh^dVZ"(N}o-$3dykC;G,++/.+..-8;Y/*^US5010SD/+0++6L'*a04KPrqQQW)'Z2C>3N+:@9;,>1225FPdx|z|~vM/TXjy }}{{̼pjjjbfbcttrii`\_ahdhb[_VT!"#(Au7$>cG-9-10++44.9_>2(;dM[88&4R@6*0%0>14.^A//6Bx}kVfoyrr5R91B471NTG57A4'.?71+&7;(Ui%I 8AbUnkbP!*|$.M("LZDymh]&VVNrkt{j`uzk+j)0)';>?.L.?z|̿zvxplpgZ_ci_]LXfeicc_]e][]\`!#""2^zJ/<[z;8+81,&-<(;SH:/4.D;5A6231/<7(,,E,OV;aQ1]jGY]ra=cPY64"(EB.$ID34475/*19NVjgwt~|P/PdpՓNzͽ}sorki\^ZefYFL\hhgfe[\^X`d__+((%/U}T4B[9W6<*.,/2HcH32*+9E=:5-=58/8h*26:5X=:Jr'%Y~lZCrkl:+*<8<.Ydx\|ǴzolhmcX]eb_ZNRbnjbeZVa^^YagY*&$'N|^:D\?`82(*+NZO@/0,)+B5H1/6ECH3+G1=.-`=/68fY#+cUoT;?^|s&613/27003/,10/:JYbmvy}{|{b6B_r{mqxƪunke^YZ]adVNOUglja^XYZ^b_b[Q(%!-*Frd2?X:]27*+2=<49.,5,1C7H71o5++4jbC*1-8bn90?H{j,2;.+@9407-+-*,@PUpnv{z|yR/TXtؗvblhpt~~оrplj\S[ffWXLS\hje`_R]X`_Yc[G'&'"%MaB=V|;]34*)-/,30,,>+=5C957LC.41A7+')GP41+H{wC_+;)$]35WDA&116'*?34+/,.//1FQcnovxylB3\i}پriN`Z\egmx}˴upmb_WZ`ccNRTYghecaXU[bf_`\M6%'#$*Es\=A]|Ha=,(.3348/+,02H1J4.9PH.**/7,)&P01A/=y{2L, /<[G)\~[R#3<552.32.)'(3>CFUiowsy~{yV6=[nӀXPGNLRUabfjpswzŭukfVONYfbSGKOafa_b^]_afc^UR@A$&#")+7WnڥITG_IPNOQIRVSRXX\_cenzħw_URKLYc^SHQacm]_a][_eie\]KF76'%""/o~C@Wxrp`[`'#3.'.(-/@G3.=A12?@G76<*&/2402U'fIdq+7gms?Z-0/701-&01-+,)5+/9JN_qzxvtwuc/&EixMTQ`ZYWSWNHKJ?FHGHPJWewк~bPG>FPXZVJL\cnV[`_^[[eiXb\P?:3)#! !0f|F;SvKydQ['0:*,+&.=@:+-P81,B:645;WQYJJM\lof[_\[X\]fja]YE?942/.574iLPSMKN_hpqe[XYS\[ejbbXL;<30.9CEADgUAZx^hA1*2%((1?.127-,1>+6D8?:7@1B/(#'A:*:/.%\hqIby|U(&47)%(*,'%''(2:LL[jpsvuyV,+>^tظQ\djfdhf_[XQQK=75.&"%.Aʽ̷`F;?BMTTGDSZelf\VSPO_`khg\WE;7:3ITPOOSfbCTulcrE8&5,7GH0)+.?6/5?4?<5K77>2/*)3'+<.\531$Mwh_e]x,+3-42.-*/%+1).JNZfrqvtwuc4,,SqXX`bmimoe`bUVPG?6)/,#$EϴœbJ?2=HONPDLYgrr[ZUVTRXelqdVVIE@4<_]XS[ZskDWvp`_V&*2:><0-4.5244875G2=M;;=/1/*56%6H<;2+1DC[Tt6.-),*/+.) ')+>OLUhsqsuzg-).PezvTXhmfklhfaT]UJI=;/'%,CʭťtB@5AJKLDGKXfkg]URLQNX\jqog_RIH>:;TYZZcd{sEbqfb|[R-*4/+15,.,84?43-.1/?N47<;,/2,A7#=;A<:A9G>JbXA/5+*(--1#$%-.4EMRkjzsqtf+$,Le{}آKY_knkmkhbd_UPPHF5.59GɻĤxA856;FOEAMTaji]RHJOKT^ckpj_TTVL=9DV^WcdnwH\t\ox[J,-0+.+9..-67;,36/,2;D6/FR621%CU8.8X3/G[0TFwHxk+.5,1/++,)"),5BLF^hnysuY,%2Lct||OVYejqlhgab\WWPLKB?;:IvP@49:EL?AGU`fga^TFKNTU`hrla\VRPE;GGIVcklx{K`tZ{w\4(815,0(-:+967-4-.3B@T+4PW2.2'5XY43Q-<9m6Ev7S]h;.,0/+2)'%1/1=MOafamtf8# 4Wekz{|jT]`ckkig`\d[\SPSIKNJWȺrLF76DEHIBGQXjoeaVUHKLQbisof^^ZOLAAI/@-96*26=2/,07Z=^2@FVS*+.*[GG:2b.E4PF\kX$MG4(.-4)'*#$'0FMUendT:#,J_fouzz֎UZ_fbjfkdee^`XSUWZZR^]MC<<7EJLEDVWdjh^TKGKPO^_pskh^\XT9AGMA7M^pqlowU`npVma,%0.0.?/;9+.+LD0-/6R?CZUGO(IS(&(1-&$-&),GPW]R:I&'2C]dipwv}|{ճIT`^hdbdgbiagdXWX\`[[z[NLA;BJTJJIXblnieYJGB?MV^krjme`]L@9KEG:+=P_cahX^q{T^[(.)63/;*I=/50M6.0.3UDYYZsucr?N.-*&23-1:=>@/7S?,73DI`B%0]iudM-"[S~ =4r9N4jdeng))-.+-)$+)&/1??QT]Wcmxu|xzy}~֞FRV]caekhlpiidotqpmrmpvmcZUTUU\VVPCFT^ck[SIGC>>ARjjmr{vjiYIF>@==522:6AMVSuycr@O29.-94*/8CJA8=?\%.09T_8,'JqK|i$$2[uN ;Y:z1Meb}8oa6.+.*(!&,59FLUX^fbmtxvvz{}~|~ԽNKWT]belmsnkosutqoswmngg`[[aag`VXNRQYggcT[OKJC?O]imwzqjhbSKB8=B:8;2C?@CMLn{anuGE>4e2.-.Db/.'Dp=w|6(%dem-*btH0HrwsUDG(&%.).<.5:DOUclpooovy||~}}VIS\]cghnlnprsuzxqtqmjkfeb^jjgbXRRTVadVVREKNQIBTbqqzyko`SF<979323.48:4B;Df£}huD1:7;17;--:6C798C2MU(0(WoD4.:jCTf8(QdwM"#DJ+*V^yA-=(4(&4-22:NT]dnmtwrtvz~}}z~xCVU]fkjnnnrvxtypupqqlkgbcmprk^[TQ[bb]VLD@HFQHMepxvsuia[SF?6;B682508=2<=JhǷfth@964>+1.077=;49A3:i&+1sc125?hK@>+%Qu-B!0Ple%;DioN52-+$1309KX`ffpruwutux~}~}|ӡMPUV[Vfmfiwzw{txvtstskjhnuuqjc^V]`cdWSDJCBHFQZju{zxli[NF:48:7697F0553;8:hǻfsV9/.A0?/@R:786?@C0T<2)P301Tp9WhT))2dL;>(QBn;3IXj`p+&$+3NY[afkqttywxux{~{}]OPUW^hdhqpwvw{utuqvxs{~~yrh^]_cWWMVSUWKJOZhu}unaYJ@A,/77C:KaX.242:97Wùdos`N7C'%-?/:1?Qv+KKL{f):{8'(KYdb,762:.5Oiw_E50''6F"6+K?8?FFEA5Ia\5L%;Hr20ND?]1~]-220EOCG(5J`)^Iy:KQR^[^dknppvvyx{z~~ԝmf^][\^bhix~~y}~}|vdVZUNMHEV[]\TST`fw{q`K<:3,*.6DL^adi ( @` HH sopt-2.0.0/python/000077500000000000000000000000001277570055300140325ustar00rootroot00000000000000sopt-2.0.0/python/CMakeLists.txt000066400000000000000000000001071277570055300165700ustar00rootroot00000000000000add_subdirectory(wavelets) if(tests) add_subdirectory(tests) endif() sopt-2.0.0/python/tests/000077500000000000000000000000001277570055300151745ustar00rootroot00000000000000sopt-2.0.0/python/tests/CMakeLists.txt000066400000000000000000000000261277570055300177320ustar00rootroot00000000000000add_pytest(test_*.py) sopt-2.0.0/python/tests/test_pywavelet.py000066400000000000000000000043611277570055300206310ustar00rootroot00000000000000"""test cython binding of wavelets""" def test_1D(): import sopt.wavelets as wv import numpy as np signal = np.random.rand(64) + 1e0 coefficient = wv.dwt(signal, "DB4", 1) inv_signal = wv.dwt(coefficient, "DB4", 1, inverse=True) np.testing.assert_allclose(signal, inv_signal, rtol=1e-8) def test_2D(): import sopt.wavelets as wv import numpy as np db_name = ["DB1", "DB2", "DB3", "DB4", "DB5", "DB6", "DB7"] for ncol in [1, 4, 32, 64]: signal = np.random.random((32, ncol)) for name in db_name: coefficient = wv.dwt(signal, name, 1) inv_signal = wv.dwt(coefficient, name, 1, inverse=True) np.testing.assert_allclose(signal, inv_signal) def test_complex(): import sopt.wavelets as wv import numpy as np s_real = np.random.random((64, 64)) + 1e0 s_img = np.random.random((64, 64)) + 1e0 signal = s_real + s_img*1j coefficient = wv.dwt(signal, "DB4", 1) inv_signal = wv.dwt(coefficient, "DB4", 1, inverse=True) np.testing.assert_allclose(signal, inv_signal) def test_1D_pywt(): """compare the result of 1D DB1 direct transform with pywt library""" import numpy as np import sopt.wavelets as wv import pywt input = np.random.random(128) + 1e0 coefficient_sopt = wv.dwt(input, "DB1", 1) cA_pywt, cD_pywt = pywt.dwt(input, "DB1") coefficient_pywt = np.concatenate( (cA_pywt, -1*cD_pywt)).reshape(coefficient_sopt.shape) np.testing.assert_allclose(coefficient_sopt, coefficient_pywt) def test_wrong_dims(): from pytest import raises import sopt.wavelets as wv import numpy as np signal = np.random.random((32, 32, 32)) with raises(ValueError): wv.dwt(signal, "DB1", 1) def test_wrong_type(): from pytest import raises import sopt.wavelets as wv import numpy as np signal = np.random.random((32, 32)) with raises(ValueError): wv.dwt(signal.astype("S1"), "DB1", 1) def test_noncontiguous(): import sopt.wavelets as wv import numpy as np signal = np.random.random((32, )) + 1e0 coeff_nc = wv.dwt(signal[::4], "DB1", 1) coeff_cont = wv.dwt(signal[::4].copy(), "DB1", 1) np.testing.assert_allclose(coeff_nc, coeff_cont) sopt-2.0.0/python/wavelets/000077500000000000000000000000001277570055300156645ustar00rootroot00000000000000sopt-2.0.0/python/wavelets/CMakeLists.txt000066400000000000000000000003221277570055300204210ustar00rootroot00000000000000include_directories(SYSTEM ${PYTHON_INCLUDE_DIR} ${NUMPY_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_python_module(sopt CPP TARGETNAME pywavelets LIBRARIES sopt FAKE_INIT wavelets.pyx) sopt-2.0.0/python/wavelets/python.wavelets.h000066400000000000000000000042171277570055300212130ustar00rootroot00000000000000#ifndef SOPT_TESTME #define SOPT_TESTME #include #include #include #include namespace sopt { namespace pyWavelets { template using Array = Eigen::Array; template using Map = Eigen::Map>; template using Vector = Eigen::Array; template using MapV = Eigen::Map>; //! \brief direct transform wrapper called by cython //! \param[in] py_input: double or complex pointer of input data generated by cython code. //! \param[in] name: Daubechie wavelets coefficient. //! \param[in] level: wavelet transform level. //! \param[in] nrow/ncol: number of rows and columns of input data. In the case of a vector //! input, ncol = 1. //! \param[out] py_out: result data in either double or complex pointer. template void direct(T *py_input, T *py_output, std::string const &name, t_uint level, t_uint nrow, t_uint ncol) { auto const wavelets = sopt::wavelets::factory(name, level); if(nrow == 1 or ncol == 1) { wavelets.direct(MapV(py_output, nrow * ncol), MapV(py_input, nrow * ncol)); } else wavelets.direct(Map(py_output, nrow, ncol), Map(py_input, nrow, ncol)); }; //! \brief indirect transform wrapper called by cython //! \param[in] py_input: double or complex pointer of input data generated by cython code. //! \param[in] name: Daubechie wavelets coefficient. //! \param[in] level: wavelet transform level. //! \param[in] nrow/ncol: number of rows and columns of input data. In the case of a vector //! input, ncol = 1. //! \param[out] py_out: result data in either double or complex pointer. template void indirect(T *py_input, T *py_output, std::string const &name, t_uint level, t_uint nrow, t_uint ncol) { auto const wavelets = sopt::wavelets::factory(name, level); if(nrow == 1 or ncol == 1) wavelets.indirect(MapV(py_input, nrow * ncol), MapV(py_output, nrow * ncol)); else wavelets.indirect(Map(py_input, nrow, ncol), Map(py_output, nrow, ncol)); }; } } #endif sopt-2.0.0/python/wavelets/wavelets.pyx000066400000000000000000000060411277570055300202610ustar00rootroot00000000000000import numpy as np from cython cimport view from libcpp.string cimport string cdef extern from "python.wavelets.h" namespace "sopt::pyWavelets": ctypedef unsigned t_uint void direct[T](T * signal, T* out, const string & name, t_uint level, t_uint nrow, t_uint ncol) except + void indirect[T](T * signal, T* out, const string & name, t_uint level, t_uint nrow, t_uint ncol) except + cdef _dwt(input, name, level, inverse=False): if input.ndim > 2: raise ValueError("Expect 1D or 2D arrays") nrow, ncol = input.shape if input.ndim == 2 else (input.size, 1) output = np.zeros(input.shape, dtype=input.dtype) cdef: long input_data = input.ctypes.data long output_data = output.ctypes.data string cname = name.encode("UTF-8") if inverse: if input.dtype == "float64": indirect[double]( input_data, output_data, cname, level, nrow, ncol ) elif input.dtype == "complex128": indirect[complex]( input_data, output_data, cname, level, nrow, ncol ) else: if input.dtype == "float64": direct[double]( input_data, output_data, cname, level, nrow, ncol ) elif input.dtype == "complex128": direct[complex]( input_data, output_data, cname, level, nrow, ncol ) return output def dwt(input, name, level, inverse=False): """ direct/inverse Daubechies wavelet transform Parameters: ------------ inputs: numpy array 1D/2D numerical input signal name: string Daubechies wavelets coefficients, e.g. "DB1" through "DB38" level: int Wavelets transform level inverse: bool True - indirect transform False - direct transform Returns ------------ numpy array Approximation matrix in the same size as input Notes ------------ * Input will be converted to "float64" or "complex128" automatically * To avoid extra copies, please use those types exclusively * Size of signal must be a multiple of 2^levels Examples ----------- signal = np.random.random((64,64)) coefficient = wv.dwt(signal, "DB4", 2) # direct transform recover = wv.dwt(coefficient, "DB4", 2, inverse = True) # inverse transform """ from numpy import iscomplex, isreal, require, all is_complex = all(iscomplex(input)) if (not is_complex) and not all(isreal(input)): raise ValueError("Incorrect array type") dtype = "complex128" if is_complex else "float64" normalized_input = require(input, requirements=['C'], dtype=dtype) return _dwt(normalized_input, name, level, inverse=inverse).astype(input.dtype)